2 // php-GACL access controls are included in OpenEMR. The below
3 // function will automatically create the path where gacl.class.php
4 // can be found. Note that this path can be manually set below
5 // for users who are using an external version of php-GACL.
6 // Also note that php-GACL access controls can be turned off
8 if (isset ($GLOBALS['fileroot'])) {
9 //normal use during OpenEMR
10 $phpgacl_location = $GLOBALS['fileroot'] . "/gacl";
13 //special case during OpenEMR and php-GACL install/upgrade scripts,
14 //which are run from main OpenEMR directory.
15 $phpgacl_location = "gacl";
17 if (isset ($GLOBALS['phpmyadmin_acl_check'])) {
18 //use for phpmyadmin acl check (ie. no globals.php is included)
19 $phpgacl_location = "../gacl";
22 // If using an external version of phpGACL, then uncomment the following
23 // line and manually place the path below. IN THIS CASE YOU MUST ALSO
24 // COMMENT OUT ALL THREE $phpgacl_location ASSIGNMENTS ABOVE, OR BACKUPS WILL
25 // NOT RESTORE PROPERLY!
27 //$phpgacl_location = "/var/www/gacl";
29 // If you want to turn off php-GACL, then uncomment the following line.
30 // IN THIS CASE YOU MUST ALSO COMMENT OUT ALL $phpgacl_location ASSIGNMENTS
31 // ABOVE, OR BACKUPS WILL NOT RESTORE PROPERLY!
33 //unset($phpgacl_location);
36 // The following Access Control Objects (ACO) are currently supported.
37 // These are the "things to be protected":
39 // Section "admin" (Administration):
40 // super Superuser - can delete patients, encounters, issues
41 // calendar Calendar Settings
42 // database Database Reporting
43 // forms Forms Administration
44 // practice Practice Settings
45 // superbill Superbill Codes Administration
46 // users Users/Groups/Logs Administration
47 // batchcom Batch Communication Tool
48 // language Language Interface Tool
49 // drugs Pharmacy Dispensary
50 // acl ACL Administration
52 // Section "acct" (Accounting):
53 // bill Billing (write optional)
54 // disc Allowed to discount prices (in Fee Sheet or Checkout form)
56 // rep Financial Reporting - my encounters
57 // rep_a Financial Reporting - anything
59 // Section "patients" (Patient Information):
60 // appt Appointments (write optional)
61 // demo Demographics (write,addonly optional)
62 // med Medical Records and History (write,addonly optional)
63 // trans Transactions, e.g. referrals (write optional)
64 // docs Documents (write,addonly optional)
65 // notes Patient Notes (write,addonly optional)
66 // sign Sign Lab Results (write,addonly optional)
68 // Section "encounters" (Encounter Information):
69 // auth Authorize - my encounters
70 // auth_a Authorize - any encounters
71 // coding Coding - my encounters (write,wsome optional)
72 // coding_a Coding - any encounters (write,wsome optional)
73 // notes Notes - my encounters (write,addonly optional)
74 // notes_a Notes - any encounters (write,addonly optional)
75 // date_a Fix encounter dates - any encounters
76 // relaxed Less-private information (write,addonly optional)
77 // (e.g. the Sports Fitness encounter form)
79 // Section "squads" applies to sports team use only:
80 // acos in this section define the user-specified list of squads
82 // Section "sensitivities" (Sensitivities):
86 // Section "lists" (Lists):
87 // default Default List (write,addonly optional)
88 // state State List (write,addonly optional)
89 // country Country List (write,addonly optional)
90 // language Language List (write,addonly optional)
91 // ethrace Ethnicity-Race List (write,addonly optional)
93 // Section "placeholder" (Placeholder):
94 // filler Placeholder (Maintains empty ACLs)
97 if (isset ($phpgacl_location)) {
98 include_once("$phpgacl_location/gacl.class.php");
99 $gacl_object = new gacl();
100 //DO NOT CHANGE BELOW VARIABLE
101 $section_aro_value = 'users';
104 // acl_check should return 0 if access is denied. Otherwise it may
105 // return anything that evaluates to true. In addition if any of the
106 // following types of access are applicable, then the corresponding value
107 // must be returned if and only if such access is granted (ony one may
110 // * write - the user may add or modify the ACO
111 // * wsome - the user has limited add/modify access to the ACO
112 // * addonly - the user may view and add but not modify entries
114 function acl_check($section, $value, $user = '') {
115 global $gacl_object, $phpgacl_location, $section_aro_value;
116 if (! $user) $user = $_SESSION['authUser'];
118 if ($phpgacl_location) {
119 return $gacl_object->acl_check($section, $value, $section_aro_value, $user);
122 // If no phpgacl, then apply the old static rules whereby "authorized"
123 // users (providers) can do anything, and other users can do most things.
124 // If you want custom access control but don't want to mess with phpGACL,
125 // then you could customize the code below instead.
127 if ($user == 'admin') return 'write';
128 if ($section == 'admin' && $value == 'super') return 0;
129 if ($_SESSION['userauthorized']) return 'write';
131 if ($section == 'patients') {
132 if ($value == 'med') return 1;
135 else if ($section == 'encounters') {
136 if (strpos($value, 'coding' ) === 0) return 'write';
137 if (strpos($value, 'notes' ) === 0) return 'write';
138 if ($value == 'relaxed') return 'write';
140 else if ($section != 'admin') {
147 // Get the ACO name/value pairs for a designated section. Each value
148 // is an array (section_value, value, order_value, name, hidden).
150 function acl_get_section_acos($section) {
151 global $phpgacl_location;
152 if ($phpgacl_location) {
153 include_once("$phpgacl_location/gacl_api.class.php");
154 $gacl = new gacl_api();
155 $arr1 = $gacl->get_objects($section, 1, 'ACO');
157 if (!empty($arr1[$section])) {
158 foreach ($arr1[$section] as $value) {
159 $odata = $gacl->get_object_data($gacl->get_object_id($section, $value, 'ACO'), 'ACO');
160 $arr[$value] = $odata[0];
168 // Return an array keyed on squad ACO names.
169 // This is only applicable for sports team use.
171 function acl_get_squads() {
172 return acl_get_section_acos('squads');
175 // Return an array keyed on encounter sensitivity level ACO names.
176 // Sensitivities are useful when some encounter notes are not
177 // medically sensitive (e.g. a physical fitness test), and/or if
178 // some will be "for doctor's eyes only" (e.g. STD treatment).
180 // When a non-blank sensitivity value exists in the new encounter
181 // form, it names an additional ACO required for access to all forms
182 // in the encounter. If you want some encounters to be non-sensitive,
183 // then you also need some default nonblank sensitivity for normal
184 // encounters, as well as greater encounter notes permissions for
185 // those allowed to view non-sensitive encounters.
187 function acl_get_sensitivities() {
188 return acl_get_section_acos('sensitivities');
192 // Returns true if aco exist
193 // Returns false if aco doesn't exist
194 // $section_name = name of section (string)
195 // $aco_name = name of aco (string)
197 function aco_exist($section_name, $aco_name) {
198 global $phpgacl_location;
199 if (isset ($phpgacl_location)) {
200 include_once("$phpgacl_location/gacl_api.class.php");
201 $gacl = new gacl_api();
202 $aco_id = $gacl->get_object_id($section_name, $aco_name, 'ACO');
211 // Returns a sorted array of all available Group Titles.
213 function acl_get_group_title_list() {
214 global $phpgacl_location;
215 if (isset ($phpgacl_location)) {
216 include_once("$phpgacl_location/gacl_api.class.php");
217 $gacl = new gacl_api();
218 $parent_id = $gacl->get_root_group_id();
219 $arr_group_ids = $gacl->get_group_children($parent_id, 'ARO', 'RECURSE');
220 $arr_group_titles = array();
221 foreach ($arr_group_ids as $value) {
222 $arr_group_data = $gacl->get_group_data($value, 'ARO');
223 $arr_group_titles[$value] = $arr_group_data[3];
225 sort($arr_group_titles);
226 return $arr_group_titles;
232 // Returns a sorted array of group Titles that a user belongs to.
233 // Returns 0 if does not belong to any group yet.
234 // $user_name = Username, which is login name.
236 function acl_get_group_titles($user_name) {
237 global $phpgacl_location, $section_aro_value;
238 if (isset ($phpgacl_location)) {
239 include_once("$phpgacl_location/gacl_api.class.php");
240 $gacl = new gacl_api();
241 $user_aro_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
243 $arr_group_id = $gacl->get_object_groups($user_aro_id, 'ARO', 'NO_RECURSE');
245 foreach ($arr_group_id as $key => $value) {
246 $arr_group_data = $gacl->get_group_data($value, 'ARO');
247 $arr_group_titles[$key] = $arr_group_data[3];
249 sort($arr_group_titles);
250 return $arr_group_titles;
258 // This will place the user aro object into selected group(s)
259 // It uses the set_user_aro() function
260 // $username = username (string)
261 // $group = title of group(s) (string or array)
263 function add_user_aros($username, $group) {
264 $current_user_groups = acl_get_group_titles($username);
265 if (!$current_user_groups) {
266 $current_user_groups = array();
268 if (is_array($group)){
269 foreach ($group as $value) {
270 if (!in_array($value, $current_user_groups)) {
271 array_push($current_user_groups, $value);
276 if (!in_array($group, $current_user_groups)) {
277 array_push($current_user_groups, $group);
280 $user_data = mysql_fetch_array(sqlStatement("select * from users where username='" .
282 set_user_aro($current_user_groups, $username, $user_data["fname"],
283 $user_data["mname"], $user_data["lname"]);
288 // This will remove the user aro object from the selected group(s)
289 // It uses the set_user_aro() function
290 // $username = username (string)
291 // $group = title of group(s) (string or array)
293 function remove_user_aros($username, $group) {
294 $current_user_groups = acl_get_group_titles($username);
295 $new_user_groups = array();
296 if (is_array($group)){
297 foreach ($current_user_groups as $value) {
298 if (!in_array($value, $group)) {
299 array_push($new_user_groups, $value);
304 foreach ($current_user_groups as $value) {
305 if ($value != $group) {
306 array_push($new_user_groups, $value);
310 $user_data = mysql_fetch_array(sqlStatement("select * from users where username='" .
312 set_user_aro($new_user_groups, $username, $user_data["fname"],
313 $user_data["mname"], $user_data["lname"]);
318 // This will either create or edit a user aro object, and then place it
319 // in the requested groups. It will not allow removal of the 'admin'
320 // user from the 'admin' group.
321 // $arr_group_titles = titles of the groups that user will be added to.
322 // $user_name = username, which is login name.
323 // $first_name = first name
324 // $middle_name = middle name
325 // $last_name = last name
327 function set_user_aro($arr_group_titles, $user_name, $first_name, $middle_name, $last_name) {
328 global $phpgacl_location, $section_aro_value;
330 if (isset ($phpgacl_location)) {
331 include_once("$phpgacl_location/gacl_api.class.php");
332 $gacl = new gacl_api();
334 //get array of all available group ID numbers
335 $parent_id = $gacl->get_root_group_id();
336 $arr_all_group_ids = $gacl->get_group_children($parent_id, 'ARO', 'RECURSE');
338 //Cycle through ID array to find and process each selected group
339 //Create a counter since processing of first hit is unique
341 foreach ($arr_all_group_ids as $value) {
342 $arr_group_data = $gacl->get_group_data($value, 'ARO');
343 if ((empty($arr_group_titles)) ||
344 (in_array($arr_group_data[3], $arr_group_titles))) {
345 //We have a hit, so need to add group and increment counter
346 // because processing of first hit is unique
347 //This will also deal with an empty $arr_group_titles array
348 // removing user from all groups unless 'admin'
349 $counter = $counter + 1;
350 //create user full name field
352 $full_name = $first_name . " " . $middle_name . " " . $last_name;
356 $full_name = $first_name . " " . $last_name;
359 $full_name = $first_name;
363 //If this is not the first group to be added, then will skip below
364 // and will be added. If this is the first group, then need to
365 // go thru several steps before adding the group.
367 //get ID of user ARO object, if it exist
368 $user_aro_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
370 //user ARO object already exist, so will edit it
371 $gacl->edit_object($user_aro_id, $section_aro_value, $full_name, $user_name, 10, 0, 'ARO');
373 //remove all current user ARO object group associations
374 $arr_remove_group_ids = $gacl->get_object_groups($user_aro_id, 'ARO', 'NO_RECURSE');
375 foreach ($arr_remove_group_ids as $value2) {
376 $gacl->del_group_object($value2, $section_aro_value, $user_name, 'ARO');
380 //user ARO object does not exist, so will create it
381 $gacl->add_object($section_aro_value, $full_name, $user_name, 10, 0, 'ARO');
385 //place the user ARO object in the selected group (if group(s) is selected)
386 if (!empty($arr_group_titles)) {
387 $gacl->add_group_object($value, $section_aro_value, $user_name, 'ARO');
391 //Below will not allow 'admin' user to be removed from 'admin' group
393 if ($user_name == 'admin') {
395 $admin_id = $gacl->get_object_id($section_aro_value, 'admin', 'ARO');
396 $arr_admin = $gacl->get_object_groups($admin_id, 'ARO', 'NO_RECURSE');
397 foreach ($arr_admin as $value3) {
398 $arr_admin_data = $gacl->get_group_data($value3, 'ARO');
399 if (strcmp($arr_admin_data[2], 'admin') == 0) {
403 if (!$boolean_admin) {
404 foreach ($arr_all_group_ids as $value4) {
405 $arr_temp = $gacl->get_group_data($value4, 'ARO');
406 if ($arr_temp[2] == 'admin') {
407 $gacl->add_group_object($value4, $section_aro_value, 'admin', 'ARO');
413 //if array of groups was empty, then we are done, and can break from loop
414 if (empty($arr_group_titles)) break;
421 // Returns true if acl exist
422 // Returns false if acl doesn't exist
423 // EITHER $title or $name is required(send FALSE in variable
424 // not being used). If both are sent, then only $title will be
426 // $return_value is required
427 // $title = title of acl (string)
428 // $name = name of acl (string)
429 // $return_value = return value of acl (string)
431 function acl_exist($title, $name, $return_value) {
432 global $phpgacl_location;
433 if (isset ($phpgacl_location)) {
434 include_once("$phpgacl_location/gacl_api.class.php");
435 $gacl = new gacl_api();
437 $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $title, FALSE, FALSE, FALSE, $return_value);
440 $group_id = $gacl->get_group_id($name, NULL, 'ARO');
442 $group_data = $gacl->get_group_data($group_id, 'ARO');
443 $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $group_data[3], FALSE, FALSE, FALSE, $return_value);
450 $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $title, FALSE, FALSE, FALSE, $return_value);
462 // This will add a new acl and group(if group doesn't yet exist)
463 // with one aco in it.
464 // $acl_title = title of acl (string)
465 // $acl_name = name of acl (string)
466 // $return_value = return value of acl (string)
467 // $note = description of acl (array)
469 function acl_add($acl_title, $acl_name, $return_value, $note) {
470 global $phpgacl_location;
471 if (isset ($phpgacl_location)) {
472 include_once("$phpgacl_location/gacl_api.class.php");
473 $gacl = new gacl_api();
474 $group_id = $gacl->get_group_id($acl_name, $acl_title, 'ARO');
476 //group already exist, so just create acl
477 $gacl->add_acl(array("placeholder"=>array("filler")),
478 NULL, array($group_id), NULL, NULL, 1, 1, $return_value, $note);
481 //create group, then create acl
482 $parent_id = $gacl->get_root_group_id();
483 $aro_id = $gacl->add_group($acl_name, $acl_title, $parent_id, 'ARO');
484 $gacl->add_acl(array("placeholder"=>array("filler")),
485 NULL, array($aro_id), NULL, NULL, 1, 1, $return_value, $note);
493 // This will remove acl. It will also remove group(if the group
494 // is no longer associated with any acl's).
495 // $acl_title = title of acl (string)
496 // $acl_name = name of acl (string)
497 // $return_value = return value of acl (string)
498 // $note = description of acl (array)
500 function acl_remove($acl_title, $return_value) {
501 global $phpgacl_location;
502 if (isset ($phpgacl_location)) {
503 include_once("$phpgacl_location/gacl_api.class.php");
504 $gacl = new gacl_api();
505 //First, delete the acl
506 $acl_id=$gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
507 $gacl->del_acl($acl_id[0]);
508 //Then, remove the group(if no more acl's are remaining)
509 $acl_search=$gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, FALSE);
510 if (empty($acl_search)){
511 $group_id=$gacl-> get_group_id(NULL, $acl_title, 'ARO');
512 $gacl->del_group($group_id, TRUE, 'ARO');
520 // This will place the aco(s) into the selected acl
521 // $acl_title = title of acl (string)
522 // $return_value = return value of acl (string)
523 // $aco_id = id of aco (array)
525 function acl_add_acos($acl_title, $return_value, $aco_id) {
526 global $phpgacl_location;
527 if (isset ($phpgacl_location)) {
528 include_once("$phpgacl_location/gacl_api.class.php");
529 $gacl = new gacl_api();
530 $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
531 foreach ($aco_id as $value) {
532 $aco_data = $gacl->get_object_data($value, 'ACO');
533 $aco_section = $aco_data[0][0];
534 $aco_name = $aco_data[0][1];
535 $gacl->append_acl($acl_id[0], NULL, NULL, NULL, NULL, array($aco_section=>array($aco_name)));
543 // This will remove the aco(s) from the selected acl
544 // Note if all aco's are removed, then will place the filler-placeholder
545 // into the acl to avoid complete removal of the acl.
546 // $acl_title = title of acl (string)
547 // $return_value = return value of acl (string)
548 // $aco_id = id of aco (array)
550 function acl_remove_acos($acl_title, $return_value, $aco_id) {
551 global $phpgacl_location;
552 if (isset ($phpgacl_location)) {
553 include_once("$phpgacl_location/gacl_api.class.php");
554 $gacl = new gacl_api();
555 $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
557 // Check to see if removing all acos. If removing all acos then will
558 // ensure the filler-placeholder aco in acl to avoid complete
559 // removal of the acl.
560 if (count($aco_id) == acl_count_acos($acl_title, $return_value)) {
561 //1-get the filler-placeholder aco id
562 $filler_aco_id = $gacl->get_object_id('placeholder','filler','ACO');
563 //2-add filler-placeholder aco
564 acl_add_acos($acl_title, $return_value, array($filler_aco_id));
565 //3-ensure filler-placeholder aco is not to be deleted
566 $safeListaco = remove_element($_POST["selection"],$filler_aco_id);
567 //4-prepare to safely delete the acos
568 $aco_id = $safeListaco;
571 foreach ($aco_id as $value) {
572 $aco_data = $gacl->get_object_data($value, 'ACO');
573 $aco_section = $aco_data[0][0];
574 $aco_name = $aco_data[0][1];
575 $gacl->shift_acl($acl_id[0], NULL, NULL, NULL, NULL, array($aco_section=>array($aco_name)));
583 // This will return the number of aco objects
584 // in a specified acl.
585 // $acl_title = title of acl (string)
586 // $return_value = return value of acl (string)
588 function acl_count_acos($acl_title, $return_value) {
589 global $phpgacl_location;
590 if (isset ($phpgacl_location)) {
591 include_once("$phpgacl_location/gacl_api.class.php");
592 $gacl = new gacl_api();
593 $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
594 $acl_data = $gacl->get_acl($acl_id[0]);
596 foreach ($acl_data['aco'] as $key => $value) {
597 $aco_count = $aco_count + count($acl_data['aco'][$key]);
605 // Function to remove an element from an array
607 function remove_element($arr, $val){
609 foreach ($arr as $value){
610 if ($value != $val) {
611 array_push($arr2,$value);