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";
18 // If using an external version of phpGACL, then uncomment the following
19 // line and manually place the path below. IN THIS CASE YOU MUST ALSO
20 // COMMENT OUT BOTH $phpgacl_location ASSIGNMENTS ABOVE, OR BACKUPS WILL
21 // NOT RESTORE PROPERLY!
23 //$phpgacl_location = "/var/www/gacl";
25 // If you want to turn off php-GACL, then uncomment the following line.
26 // IN THIS CASE YOU MUST ALSO COMMENT OUT ALL $phpgacl_location ASSIGNMENTS
27 // ABOVE, OR BACKUPS WILL NOT RESTORE PROPERLY!
29 //unset($phpgacl_location);
32 // The following Access Control Objects (ACO) are currently supported.
33 // These are the "things to be protected":
35 // Section "admin" (Administration):
36 // super Superuser - can delete patients, encounters, issues
37 // calendar Calendar Settings
38 // database Database Reporting
39 // forms Forms Administration
40 // practice Practice Settings
41 // superbill Superbill Codes Administration
42 // users Users/Groups/Logs Administration
43 // batchcom Batch Communication Tool
44 // language Language Interface Tool
45 // drugs Pharmacy Dispensary
46 // acl ACL Administration
48 // Section "acct" (Accounting):
49 // bill Billing (write optional)
50 // disc Allowed to discount prices (in Fee Sheet or Checkout form)
52 // rep Financial Reporting - my encounters
53 // rep_a Financial Reporting - anything
55 // Section "patients" (Patient Information):
56 // appt Appointments (write optional)
57 // demo Demographics (write,addonly optional)
58 // med Medical Records and History (write,addonly optional)
59 // trans Transactions, e.g. referrals (write optional)
60 // docs Documents (write,addonly optional)
61 // notes Patient Notes (write,addonly optional)
63 // Section "encounters" (Encounter Information):
64 // auth Authorize - my encounters
65 // auth_a Authorize - any encounters
66 // coding Coding - my encounters (write,wsome optional)
67 // coding_a Coding - any encounters (write,wsome optional)
68 // notes Notes - my encounters (write,addonly optional)
69 // notes_a Notes - any encounters (write,addonly optional)
70 // date_a Fix encounter dates - any encounters
71 // relaxed Less-private information (write,addonly optional)
72 // (e.g. the Sports Fitness encounter form)
74 // Section "squads" applies to sports team use only:
75 // acos in this section define the user-specified list of squads
77 // Section "sensitivities" (Sensitivities):
81 if (isset ($phpgacl_location)) {
82 include_once("$phpgacl_location/gacl.class.php");
83 $gacl_object = new gacl();
84 //DO NOT CHANGE BELOW VARIABLE
85 $section_aro_value = 'users';
88 // acl_check should return 0 if access is denied. Otherwise it may
89 // return anything that evaluates to true. In addition if any of the
90 // following types of access are applicable, then the corresponding value
91 // must be returned if and only if such access is granted (ony one may
94 // * write - the user may add or modify the ACO
95 // * wsome - the user has limited add/modify access to the ACO
96 // * addonly - the user may view and add but not modify entries
98 function acl_check($section, $value, $user = '') {
99 global $gacl_object, $phpgacl_location, $section_aro_value;
100 if (! $user) $user = $_SESSION['authUser'];
102 if ($phpgacl_location) {
103 return $gacl_object->acl_check($section, $value, $section_aro_value, $user);
106 // If no phpgacl, then apply the old static rules whereby "authorized"
107 // users (providers) can do anything, and other users can do most things.
108 // If you want custom access control but don't want to mess with phpGACL,
109 // then you could customize the code below instead.
111 if ($user == 'admin') return 'write';
112 if ($section == 'admin' && $value == 'super') return 0;
113 if ($_SESSION['userauthorized']) return 'write';
115 if ($section == 'patients') {
116 if ($value == 'med') return 1;
119 else if ($section == 'encounters') {
120 if (strpos($value, 'coding' ) === 0) return 'write';
121 if (strpos($value, 'notes' ) === 0) return 'write';
122 if ($value == 'relaxed') return 'write';
124 else if ($section != 'admin') {
131 // Get the ACO name/value pairs for a designated section. Each value
132 // is an array (section_value, value, order_value, name, hidden).
134 function acl_get_section_acos($section) {
135 global $phpgacl_location;
136 if ($phpgacl_location) {
137 include_once("$phpgacl_location/gacl_api.class.php");
138 $gacl = new gacl_api();
139 $arr1 = $gacl->get_objects($section, 1, 'ACO');
141 if (!empty($arr1[$section])) {
142 foreach ($arr1[$section] as $value) {
143 $odata = $gacl->get_object_data($gacl->get_object_id($section, $value, 'ACO'), 'ACO');
144 $arr[$value] = $odata[0];
152 // Return an array keyed on squad ACO names.
153 // This is only applicable for sports team use.
155 function acl_get_squads() {
156 return acl_get_section_acos('squads');
159 // Return an array keyed on encounter sensitivity level ACO names.
160 // Sensitivities are useful when some encounter notes are not
161 // medically sensitive (e.g. a physical fitness test), and/or if
162 // some will be "for doctor's eyes only" (e.g. STD treatment).
164 // When a non-blank sensitivity value exists in the new encounter
165 // form, it names an additional ACO required for access to all forms
166 // in the encounter. If you want some encounters to be non-sensitive,
167 // then you also need some default nonblank sensitivity for normal
168 // encounters, as well as greater encounter notes permissions for
169 // those allowed to view non-sensitive encounters.
171 function acl_get_sensitivities() {
172 return acl_get_section_acos('sensitivities');
176 // Returns a sorted array of all available Group Titles.
178 function acl_get_group_title_list() {
179 global $phpgacl_location;
180 if (isset ($phpgacl_location)) {
181 include_once("$phpgacl_location/gacl_api.class.php");
182 $gacl = new gacl_api();
183 $parent_id = $gacl->get_root_group_id();
184 $arr_group_ids = $gacl->get_group_children($parent_id, 'ARO', 'RECURSE');
185 $arr_group_titles = array();
186 foreach ($arr_group_ids as $value) {
187 $arr_group_data = $gacl->get_group_data($value, 'ARO');
188 $arr_group_titles[$value] = $arr_group_data[3];
190 sort($arr_group_titles);
191 return $arr_group_titles;
197 // Returns a sorted array of group Titles that a user belongs to.
198 // Returns 0 if does not belong to any group yet.
199 // $user_name = Username, which is login name.
201 function acl_get_group_titles($user_name) {
202 global $phpgacl_location, $section_aro_value;
203 if (isset ($phpgacl_location)) {
204 include_once("$phpgacl_location/gacl_api.class.php");
205 $gacl = new gacl_api();
206 $user_aro_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
208 $arr_group_id = $gacl->get_object_groups($user_aro_id, 'ARO', 'NO_RECURSE');
210 foreach ($arr_group_id as $key => $value) {
211 $arr_group_data = $gacl->get_group_data($value, 'ARO');
212 $arr_group_titles[$key] = $arr_group_data[3];
214 sort($arr_group_titles);
215 return $arr_group_titles;
223 // This will place the user aro object into selected group(s)
224 // It uses the set_user_aro() function
225 // $username = username (string)
226 // $group = title of group(s) (string or array)
228 function add_user_aros($username, $group) {
229 $current_user_groups = acl_get_group_titles($username);
230 if (!$current_user_groups) {
231 $current_user_groups = array();
233 if (is_array($group)){
234 foreach ($group as $value) {
235 if (!in_array($value, $current_user_groups)) {
236 array_push($current_user_groups, $value);
241 if (!in_array($group, $current_user_groups)) {
242 array_push($current_user_groups, $group);
245 $user_data = mysql_fetch_array(sqlStatement("select * from users where username='" .
247 set_user_aro($current_user_groups, $username, $user_data["fname"],
248 $user_data["mname"], $user_data["lname"]);
253 // This will remove the user aro object from the selected group(s)
254 // It uses the set_user_aro() function
255 // $username = username (string)
256 // $group = title of group(s) (string or array)
258 function remove_user_aros($username, $group) {
259 $current_user_groups = acl_get_group_titles($username);
260 $new_user_groups = array();
261 if (is_array($group)){
262 foreach ($current_user_groups as $value) {
263 if (!in_array($value, $group)) {
264 array_push($new_user_groups, $value);
269 foreach ($current_user_groups as $value) {
270 if ($value != $group) {
271 array_push($new_user_groups, $value);
275 $user_data = mysql_fetch_array(sqlStatement("select * from users where username='" .
277 set_user_aro($new_user_groups, $username, $user_data["fname"],
278 $user_data["mname"], $user_data["lname"]);
283 // This will either create or edit a user aro object, and then place it
284 // in the requested groups. It will not allow removal of the 'admin'
285 // user from the 'admin' group.
286 // $arr_group_titles = titles of the groups that user will be added to.
287 // $user_name = username, which is login name.
288 // $first_name = first name
289 // $middle_name = middle name
290 // $last_name = last name
292 function set_user_aro($arr_group_titles, $user_name, $first_name, $middle_name, $last_name) {
293 global $phpgacl_location, $section_aro_value;
295 if (isset ($phpgacl_location)) {
296 include_once("$phpgacl_location/gacl_api.class.php");
297 $gacl = new gacl_api();
299 //get array of all available group ID numbers
300 $parent_id = $gacl->get_root_group_id();
301 $arr_all_group_ids = $gacl->get_group_children($parent_id, 'ARO', 'RECURSE');
303 //Cycle through ID array to find and process each selected group
304 //Create a counter since processing of first hit is unique
306 foreach ($arr_all_group_ids as $value) {
307 $arr_group_data = $gacl->get_group_data($value, 'ARO');
308 if ((empty($arr_group_titles)) ||
309 (in_array($arr_group_data[3], $arr_group_titles))) {
310 //We have a hit, so need to add group and increment counter
311 // because processing of first hit is unique
312 //This will also deal with an empty $arr_group_titles array
313 // removing user from all groups unless 'admin'
314 $counter = $counter + 1;
315 //create user full name field
317 $full_name = $first_name . " " . $middle_name . " " . $last_name;
321 $full_name = $first_name . " " . $last_name;
324 $full_name = $first_name;
328 //If this is not the first group to be added, then will skip below
329 // and will be added. If this is the first group, then need to
330 // go thru several steps before adding the group.
332 //get ID of user ARO object, if it exist
333 $user_aro_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
335 //user ARO object already exist, so will edit it
336 $gacl->edit_object($user_aro_id, $section_aro_value, $full_name, $user_name, 10, 0, 'ARO');
338 //remove all current user ARO object group associations
339 $arr_remove_group_ids = $gacl->get_object_groups($user_aro_id, 'ARO', 'NO_RECURSE');
340 foreach ($arr_remove_group_ids as $value2) {
341 $gacl->del_group_object($value2, $section_aro_value, $user_name, 'ARO');
345 //user ARO object does not exist, so will create it
346 $gacl->add_object($section_aro_value, $full_name, $user_name, 10, 0, 'ARO');
350 //place the user ARO object in the selected group (if group(s) is selected)
351 if (!empty($arr_group_titles)) {
352 $gacl->add_group_object($value, $section_aro_value, $user_name, 'ARO');
356 //Below will not allow 'admin' user to be removed from 'admin' group
358 if ($user_name == 'admin') {
360 $admin_id = $gacl->get_object_id($section_aro_value, 'admin', 'ARO');
361 $arr_admin = $gacl->get_object_groups($admin_id, 'ARO', 'NO_RECURSE');
362 foreach ($arr_admin as $value3) {
363 $arr_admin_data = $gacl->get_group_data($value3, 'ARO');
364 if (strcmp($arr_admin_data[2], 'admin') == 0) {
368 if (!$boolean_admin) {
369 foreach ($arr_all_group_ids as $value4) {
370 $arr_temp = $gacl->get_group_data($value4, 'ARO');
371 if ($arr_temp[2] == 'admin') {
372 $gacl->add_group_object($value4, $section_aro_value, 'admin', 'ARO');
378 //if array of groups was empty, then we are done, and can break from loop
379 if (empty($arr_group_titles)) break;
386 // Returns true if acl exist
387 // Returns false if acl doesn't exist
388 // EITHER $title or $name is required(send FALSE in variable
389 // not being used). If both are sent, then only $title will be
391 // $return_value is required
392 // $title = title of acl (string)
393 // $name = name of acl (string)
394 // $return_value = return value of acl (string)
396 function acl_exist($title, $name, $return_value) {
397 global $phpgacl_location;
398 if (isset ($phpgacl_location)) {
399 include_once("$phpgacl_location/gacl_api.class.php");
400 $gacl = new gacl_api();
402 $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $title, FALSE, FALSE, FALSE, $return_value);
405 $group_id = $gacl->get_group_id($name, NULL, 'ARO');
407 $group_data = $gacl->get_group_data($group_id, 'ARO');
408 $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $group_data[3], FALSE, FALSE, FALSE, $return_value);
415 $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $title, FALSE, FALSE, FALSE, $return_value);
427 // This will add a new acl and group(if group doesn't yet exist)
428 // with one aco in it.
429 // $acl_title = title of acl (string)
430 // $acl_name = name of acl (string)
431 // $return_value = return value of acl (string)
432 // $note = description of acl (array)
434 function acl_add($acl_title, $acl_name, $return_value, $note) {
435 global $phpgacl_location;
436 if (isset ($phpgacl_location)) {
437 include_once("$phpgacl_location/gacl_api.class.php");
438 $gacl = new gacl_api();
439 $group_id = $gacl->get_group_id($acl_name, $acl_title, 'ARO');
441 //group already exist, so just create acl
442 $gacl->add_acl(array("patients"=>array("appt")),
443 NULL, array($group_id), NULL, NULL, 1, 1, $return_value, $note);
446 //create group, then create acl
447 $parent_id = $gacl->get_root_group_id();
448 $aro_id = $gacl->add_group($acl_name, $acl_title, $parent_id, 'ARO');
449 $gacl->add_acl(array("patients"=>array("appt")),
450 NULL, array($aro_id), NULL, NULL, 1, 1, $return_value, $note);
458 // This will remove acl. It will also remove group(if the group
459 // is no longer associated with any acl's).
460 // $acl_title = title of acl (string)
461 // $acl_name = name of acl (string)
462 // $return_value = return value of acl (string)
463 // $note = description of acl (array)
465 function acl_remove($acl_title, $return_value) {
466 global $phpgacl_location;
467 if (isset ($phpgacl_location)) {
468 include_once("$phpgacl_location/gacl_api.class.php");
469 $gacl = new gacl_api();
470 //First, delete the acl
471 $acl_id=$gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
472 $gacl->del_acl($acl_id[0]);
473 //Then, remove the group(if no more acl's are remaining)
474 $acl_search=$gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, FALSE);
475 if (empty($acl_search)){
476 $group_id=$gacl-> get_group_id(NULL, $acl_title, 'ARO');
477 $gacl->del_group($group_id, TRUE, 'ARO');
485 // This will place the aco(s) into the selected acl
486 // $acl_title = title of acl (string)
487 // $return_value = return value of acl (string)
488 // $aco_id = id of aco (array)
490 function acl_add_acos($acl_title, $return_value, $aco_id) {
491 global $phpgacl_location;
492 if (isset ($phpgacl_location)) {
493 include_once("$phpgacl_location/gacl_api.class.php");
494 $gacl = new gacl_api();
495 $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
496 foreach ($aco_id as $value) {
497 $aco_data = $gacl->get_object_data($value, 'ACO');
498 $aco_section = $aco_data[0][0];
499 $aco_name = $aco_data[0][1];
500 $gacl->append_acl($acl_id[0], NULL, NULL, NULL, NULL, array($aco_section=>array($aco_name)));
508 // This will remove the aco(s) from the selected acl
509 // $acl_title = title of acl (string)
510 // $return_value = return value of acl (string)
511 // $aco_id = id of aco (array)
513 function acl_remove_acos($acl_title, $return_value, $aco_id) {
514 global $phpgacl_location;
515 if (isset ($phpgacl_location)) {
516 include_once("$phpgacl_location/gacl_api.class.php");
517 $gacl = new gacl_api();
518 $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
519 foreach ($aco_id as $value) {
520 $aco_data = $gacl->get_object_data($value, 'ACO');
521 $aco_section = $aco_data[0][0];
522 $aco_name = $aco_data[0][1];
523 $gacl->shift_acl($acl_id[0], NULL, NULL, NULL, NULL, array($aco_section=>array($aco_name)));
531 // This will return the number of aco objects
532 // in a specified acl.
533 // $acl_title = title of acl (string)
534 // $return_value = return value of acl (string)
536 function acl_count_acos($acl_title, $return_value) {
537 global $phpgacl_location;
538 if (isset ($phpgacl_location)) {
539 include_once("$phpgacl_location/gacl_api.class.php");
540 $gacl = new gacl_api();
541 $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
542 $acl_data = $gacl->get_acl($acl_id[0]);
544 foreach ($acl_data['aco'] as $key => $value) {
545 $aco_count = $aco_count + count($acl_data['aco'][$key]);