Practices gui - bootstrap light, no pure php in smarty, html escaping in smarty ...
[openemr.git] / library / acl.inc
blob79be8dbf56c888d75b7d3e509ef89fe689eb4ff6
1 <?php
2 /**
3  * library/acl.inc
4  *
5  * Functions wrapping php-GACL's functionality, to create a generic OpenEMR access control system.
6  *
7  * LICENSE: This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see
17  * http://www.gnu.org/licenses/licenses.html#GPL .
18  *
19  * @package OpenEMR
20  * @license http://www.gnu.org/licenses/licenses.html#GPL GNU GPL V3+
21  * @author  Brady Miller <brady.g.miller@gmail.com>
22  * @author  Rod Roark <rod@sunsetsystems.com>
23  * @link    http://www.open-emr.org
24  */
26 // php-GACL access controls are included in OpenEMR. The below
27 // function will automatically create the path where gacl.class.php
28 // can be found. Note that this path can be manually set below
29 // for users who are using an external version of php-GACL.
30 // Also note that php-GACL access controls can be turned off
31 // below.
33   $phpgacl_location = dirname(__FILE__).'/../gacl';
35 // If using an external version of phpGACL, then uncomment the following
36 // line and manually place the path below.  IN THIS CASE YOU MUST ALSO
37 // COMMENT OUT ABOVE $phpgacl_location ASSIGNMENT ABOVE, OR BACKUPS WILL
38 // NOT RESTORE PROPERLY!
40 //$phpgacl_location = "/var/www/gacl";
42 // If you want to turn off php-GACL, then uncomment the following line.
43 // IN THIS CASE YOU MUST ALSO COMMENT OUT ABOVE $phpgacl_location ASSIGNMENT(S)
44 // ABOVE, OR BACKUPS WILL NOT RESTORE PROPERLY!
46 //unset($phpgacl_location);
49   // The following Access Control Objects (ACO) are currently supported.
50   // These are the "things to be protected":
51   //
52   // Section "admin" (Administration):
53   //   super       Superuser - can delete patients, encounters, issues
54   //   calendar    Calendar Settings
55   //   database    Database Reporting
56   //   forms       Forms Administration
57   //   practice    Practice Settings
58   //   superbill   Superbill Codes Administration
59   //   users       Users/Groups/Logs Administration
60   //   batchcom    Batch Communication Tool
61   //   language    Language Interface Tool
62   //   drugs       Pharmacy Dispensary
63   //   acl         ACL Administration
64   //   multipledb  Multipledb
65   //
66   // Section "acct" (Accounting):
67   //   bill        Billing (write optional)
68   //   disc        Allowed to discount prices (in Fee Sheet or Checkout form)
69   //   eob         EOB Data Entry
70   //   rep         Financial Reporting - my encounters
71   //   rep_a       Financial Reporting - anything
72   //
73   // Section "patients" (Patient Information):
74   //   appt        Appointments (write,wsome optional)
75   //   demo        Demographics (write,addonly optional)
76   //   med         Medical Records and History (write,addonly optional)
77   //   trans       Transactions, e.g. referrals (write optional)
78   //   docs        Documents (write,addonly optional)
79   //   notes       Patient Notes (write,addonly optional)
80   //   sign        Sign Lab Results (write,addonly optional)
81   //   reminder    Patient Reminders (write,addonly optional)
82   //   alert       Clinical Reminders/Alerts (write,addonly optional)
83   //   disclosure  Disclosures (write,addonly optional)
84   //   rx          Prescriptions (write,addonly optional)
85   //   amendment   Amendments (write,addonly optional)
86   //   lab         Lab Results (write,addonly optional)
87   //
88   // Section "encounters" (Encounter Information):
89   //   auth        Authorize - my encounters
90   //   auth_a      Authorize - any encounters
91   //   coding      Coding - my encounters (write,wsome optional)
92   //   coding_a    Coding - any encounters (write,wsome optional)
93   //   notes       Notes - my encounters (write,addonly optional)
94   //   notes_a     Notes - any encounters (write,addonly optional)
95   //   date_a      Fix encounter dates - any encounters
96   //   relaxed     Less-private information (write,addonly optional)
97   //               (e.g. the Sports Fitness encounter form)
98   //
99   // Section "squads" applies to sports team use only:
100   //   acos in this section define the user-specified list of squads
101   //
102   // Section "sensitivities" (Sensitivities):
103   //   normal     Normal
104   //   high       High
105   //
106   // Section "lists" (Lists):
107   //   default    Default List (write,addonly optional)
108   //   state      State List (write,addonly optional)
109   //   country    Country List (write,addonly optional)
110   //   language   Language List (write,addonly optional)
111   //   ethrace    Ethnicity-Race List (write,addonly optional)
112   //
113   // Section "placeholder" (Placeholder):
114   //   filler     Placeholder (Maintains empty ACLs)
115   //
116   // Section "nationnotes" (Nation Notes):
117   //   nn_configure     Nation Notes
118   //
119   // Section "patientportal" (Patient Portal):
120   //   portal     Patient Portal
121   //
122   // Section "menus" (Menus):
123   //   modle      Module
124   //
125   // Section "groups" (Groups):
126   //   gadd       View/Add/Update groups
127   //   gcalendar  View/Create/Update groups appointment in calendar
128   //   glog       Group encounter log
129   //   gdlog      Group detailed log of appointment in patient record
130   //   gm         Send message from the permanent group therapist to the personal therapist
132   if (isset ($phpgacl_location)) {
133     $GLOBALS['phpgacl_location_global'] = $phpgacl_location;
134     require_once("$phpgacl_location/gacl.class.php");
135     $gacl_object = new gacl();
136     //DO NOT CHANGE BELOW VARIABLE
137     $section_aro_value = 'users';
138     $GLOBALS['section_aro_value_global'] = $section_aro_value;
139   }
142  * Check if a user has a given type or types of access to an access control object.
144  * Globals that can use are:
145  *  $GLOBALS['phpgacl_location_global']
146  *  $GLOBALS['section_aro_value_global']
148  * This function will check for access to the given ACO.
149  * view    - The user may view but not add or modify entries
150  * write   - The user may add or modify the ACO
151  * wsome   - The user has limited add/modify access to the ACO
152  * addonly - The user may view and add but not modify entries
154  * @param string       $section      Category of ACO
155  * @param string       $value        Subcategory of ACO
156  * @param string       $user         Optional user being checked for access.
157  * @param string|array $return_value Type or types of access being requested.
158  * @return bool|array  FALSE if access is denied, TRUE if allowed. An
159  *                     array() of bools is returned if $return_value is an
160  *                     array, representing results for each type of access
161  *                     requested.
162  */
163   function acl_check($section, $value, $user = '', $return_value = '') {
164     if (! $user) $user = $_SESSION['authUser'];
166     // Superuser always gets access to everything.
167     if (($section != 'admin' || $value != 'super') && acl_check('admin', 'super', $user)) {
168       return TRUE;
169     }
171     if ($GLOBALS['phpgacl_location_global']) {
172       // This will return all pertinent ACL's (including return_values and whether allow/deny)
173       // Walk through them to assess for access
174       $gacl_object = new gacl();
175       $acl_results = $gacl_object->acl_query($section, $value, $GLOBALS['section_aro_value_global'], $user,NULL,NULL,NULL,NULL,NULL,TRUE);
176       if (empty($acl_results)) {
177         return FALSE; //deny access
178       }
179       $access=FALSE; //flag
180       $deny=FALSE; //flag
181       foreach ($acl_results as $acl_result) {
182         if (empty($acl_result['acl_id'])) return FALSE; //deny access, since this happens if no pertinent ACL's are returned
183         if (is_array($return_value)) {
184           foreach ($return_value as $single_return_value) {
185             if (empty($single_return_value)) {
186               // deal with case if not looking for specific return value
187               if ($acl_result['allow']) {
188                 $access=TRUE;
189               }
190               else {
191                 $deny=TRUE;
192               }
193             }
194             else { //!empty($single_return_value)
195               // deal with case if looking for specific return value
196               if ($acl_result['return_value'] == $single_return_value) {
197                 if ($acl_result['allow']) {
198                   $access=TRUE;
199                 }
200                 else{
201                   $deny=TRUE;
202                 }
203               }
204             }
205           }
206         }
207         else { // $return_value is not an array (either empty or with one value)
208           if (empty($return_value)) {
209             // deal with case if not looking for specific return value
210             if ($acl_result['allow']) {
211               $access=TRUE;
212             }
213             else {
214               $deny=TRUE;
215             }
216           }
217           else { //!empty($return_value)
218             // deal with case if looking for specific return value
219             if ($acl_result['return_value'] == $return_value) {
220               if ($acl_result['allow']) {
221                 $access=TRUE;
222               }
223               else{
224                 $deny=TRUE;
225               }
226             }
227           }
228         }
229       }
231       // Now decide whether user has access
232       // (Note a denial takes precedence)
233       if (!$deny && $access) return TRUE;
234       return FALSE;
235     }
237     // If no phpgacl, then apply the old static rules whereby "authorized"
238     // users (providers) can do anything, and other users can do most things.
239     // If you want custom access control but don't want to mess with phpGACL,
240     // then you could customize the code below instead.
242     if ($user == 'admin') return 'write';
243     if ($section == 'admin' && $value == 'super') return 0;
244     if ($_SESSION['userauthorized']) return 'write';
246     if ($section == 'patients') {
247       if ($value == 'med') return 1;
248       return 'write';
249     }
250     else if ($section == 'encounters') {
251       if (strpos($value, 'coding' ) === 0) return 'write';
252       if (strpos($value, 'notes'  ) === 0) return 'write';
253       if ($value == 'relaxed') return 'write';
254     }
255     else if ($section != 'admin') {
256       return 'write';
257     }
259     return 0;
260   }
262   // Get the ACO name/value pairs for a designated section.  Each value
263   // is an array (section_value, value, order_value, name, hidden).
264   //
265   function acl_get_section_acos($section) {
266     global $phpgacl_location;
267     if ($phpgacl_location) {
268       include_once("$phpgacl_location/gacl_api.class.php");
269       $gacl = new gacl_api();
270       $arr1 = $gacl->get_objects($section, 1, 'ACO');
271       $arr = array();
272       if (!empty($arr1[$section])) {
273         foreach ($arr1[$section] as $value) {
274           $odata = $gacl->get_object_data($gacl->get_object_id($section, $value, 'ACO'), 'ACO');
275           $arr[$value] = $odata[0];
276         }
277       }
278       return $arr;
279     }
280     return 0;
281   }
283   // Sort squads by their order value.  Used only by acl_get_squads().
284   function _acl_squad_compare($a, $b) {
285     if ($a[2] == $b[2]) {
286       // If order value is the same, sort by squad name.
287       if ($a[3] == $b[3]) return 0;
288       return ($a[3] < $b[3]) ? -1 : 1;
289     }
290     return ($a[2] < $b[2]) ? -1 : 1;
291   }
293   // Return an array keyed on squad ACO names.
294   // This is only applicable for sports team use.
295   //
296   function acl_get_squads() {
297     $squads = acl_get_section_acos('squads');
298     uasort($squads, "_acl_squad_compare");
299     return $squads;
300   }
302   // Return an array keyed on encounter sensitivity level ACO names.
303   // Sensitivities are useful when some encounter notes are not
304   // medically sensitive (e.g. a physical fitness test), and/or if
305   // some will be "for doctor's eyes only" (e.g. STD treatment).
306   //
307   // When a non-blank sensitivity value exists in the new encounter
308   // form, it names an additional ACO required for access to all forms
309   // in the encounter.  If you want some encounters to be non-sensitive,
310   // then you also need some default nonblank sensitivity for normal
311   // encounters, as well as greater encounter notes permissions for
312   // those allowed to view non-sensitive encounters.
313   //
314   function acl_get_sensitivities() {
315     return acl_get_section_acos('sensitivities');
316   }
318   //
319   // Returns true if aco exist
320   // Returns false if aco doesn't exist
321   //    $section_name = name of section (string)
322   //    $aco_name = name of aco (string)
323   //
324   function aco_exist($section_name, $aco_name) {
325    global $phpgacl_location;
326    if (isset ($phpgacl_location)) {
327     include_once("$phpgacl_location/gacl_api.class.php");
328     $gacl = new gacl_api();
329     $aco_id = $gacl->get_object_id($section_name,  $aco_name, 'ACO');
330     if ($aco_id) {
331      return true;
332     }
333    }
334    return false;
335   }
337   //
338   // Returns a sorted array of all available Group Titles.
339   //
340   function acl_get_group_title_list() {
341     global $phpgacl_location;
342     if (isset ($phpgacl_location)) {
343       include_once("$phpgacl_location/gacl_api.class.php");
344       $gacl = new gacl_api();
345       $parent_id = $gacl->get_root_group_id();
346       $arr_group_ids = $gacl->get_group_children($parent_id, 'ARO', 'RECURSE');
347       $arr_group_titles = array();
348       foreach ($arr_group_ids as $value) {
349         $arr_group_data = $gacl->get_group_data($value, 'ARO');
350         $arr_group_titles[$value] = $arr_group_data[3];
351       }
352       sort($arr_group_titles);
353       return $arr_group_titles;
354     }
355     return 0;
356   }
358   //
359   // Returns a sorted array of group Titles that a user belongs to.
360   // Returns 0 if does not belong to any group yet.
361   //   $user_name = Username, which is login name.
362   //
363   function acl_get_group_titles($user_name) {
364     global $phpgacl_location, $section_aro_value;
365     if (isset ($phpgacl_location)) {
366       include_once("$phpgacl_location/gacl_api.class.php");
367       $gacl = new gacl_api();
368       $user_aro_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
369       if ($user_aro_id) {
370         $arr_group_id = $gacl->get_object_groups($user_aro_id, 'ARO', 'NO_RECURSE');
371         if ($arr_group_id) {
372           foreach ($arr_group_id as $key => $value) {
373             $arr_group_data = $gacl->get_group_data($value, 'ARO');
374             $arr_group_titles[$key] =  $arr_group_data[3];
375           }
376         sort($arr_group_titles);
377         return $arr_group_titles;
378         }
379       }
380     }
381     return 0;
382   }
384   //
385   // This will place the user aro object into selected group(s)
386   // It uses the set_user_aro() function
387   //   $username = username (string)
388   //   $group = title of group(s) (string or array)
389   //
390   function add_user_aros($username, $group) {
391    $current_user_groups = acl_get_group_titles($username);
392    if (!$current_user_groups) {
393     $current_user_groups = array();
394    }
395    if (is_array($group)){
396     foreach ($group as $value) {
397        if (!in_array($value, $current_user_groups)) {
398         array_push($current_user_groups, $value);
399        }
400     }
401    }
402    else {
403     if (!in_array($group, $current_user_groups)) {
404      array_push($current_user_groups, $group);
405     }
406    }
407    $user_data = sqlFetchArray(sqlStatement("select * from users where username='" .
408     $username . "'"));
409    set_user_aro($current_user_groups, $username, $user_data["fname"],
410     $user_data["mname"], $user_data["lname"]);
411    return;
412   }
414   //
415   // This will remove the user aro object from the selected group(s)
416   // It uses the set_user_aro() function
417   //   $username = username (string)
418   //   $group = title of group(s) (string or array)
419   //
420   function remove_user_aros($username, $group) {
421    $current_user_groups = acl_get_group_titles($username);
422    $new_user_groups = array();
423    if (is_array($group)){
424     foreach ($current_user_groups as $value) {
425      if (!in_array($value, $group)) {
426       array_push($new_user_groups, $value);
427      }
428     }
429    }
430    else {
431     foreach ($current_user_groups as $value) {
432      if ($value != $group) {
433       array_push($new_user_groups, $value);
434      }
435     }
436    }
437    $user_data = sqlFetchArray(sqlStatement("select * from users where username='" .
438     $username . "'"));
439    set_user_aro($new_user_groups, $username, $user_data["fname"],
440     $user_data["mname"], $user_data["lname"]);
441    return;
442   }
444   //
445   // This will either create or edit a user aro object, and then place it
446   // in the requested groups. It will not allow removal of the 'admin'
447   // user or gacl_protected users from the 'admin' group.
448   //   $arr_group_titles = titles of the groups that user will be added to.
449   //   $user_name = username, which is login name.
450   //   $first_name = first name
451   //   $middle_name = middle name
452   //   $last_name = last name
453   //
454   function set_user_aro($arr_group_titles, $user_name, $first_name, $middle_name, $last_name) {
455     global $phpgacl_location, $section_aro_value;
457     if (isset ($phpgacl_location)) {
458       include_once("$phpgacl_location/gacl_api.class.php");
459       $gacl = new gacl_api();
461       //see if this user is gacl protected (ie. do not allow
462       //removal from the Administrators group)
463       require_once(dirname(__FILE__).'/user.inc');
464       require_once(dirname(__FILE__).'/calendar.inc');
465       $userNametoID = getIDfromUser($user_name);
466       if (checkUserSetting("gacl_protect","1",$userNametoID) || $user_name == "admin") {
467         $gacl_protect = true;
468       }
469       else {
470         $gacl_protect = false;
471       }
473       //get array of all available group ID numbers
474       $parent_id = $gacl->get_root_group_id();
475       $arr_all_group_ids = $gacl->get_group_children($parent_id, 'ARO', 'RECURSE');
477       //Cycle through ID array to find and process each selected group
478       //Create a counter since processing of first hit is unique
479       $counter = 0;
480       foreach ($arr_all_group_ids as $value) {
481         $arr_group_data = $gacl->get_group_data($value, 'ARO');
482         if ((empty($arr_group_titles)) ||
483          (in_array($arr_group_data[3], $arr_group_titles))) {
484           //We have a hit, so need to add group and increment counter
485           // because processing of first hit is unique
486           //This will also deal with an empty $arr_group_titles array
487           // removing user from all groups unless 'admin'
488           $counter = $counter + 1;
489           //create user full name field
490           if ($middle_name) {
491             $full_name = $first_name . " " . $middle_name . " " .  $last_name;
492           }
493           else {
494             if ($last_name) {
495               $full_name = $first_name . " " . $last_name;
496             }
497             else {
498               $full_name = $first_name;
499             }
500           }
502           //If this is not the first group to be added, then will skip below
503           // and will be added. If this is the first group, then need to
504           // go thru several steps before adding the group.
505           if ($counter == 1) {
506             //get ID of user ARO object, if it exist
507             $user_aro_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
508             if ($user_aro_id) {
509               //user ARO object already exist, so will edit it
510               $gacl->edit_object($user_aro_id, $section_aro_value, $full_name, $user_name, 10, 0, 'ARO');
512               //remove all current user ARO object group associations
513               $arr_remove_group_ids = $gacl->get_object_groups($user_aro_id, 'ARO', 'NO_RECURSE');
514               foreach ($arr_remove_group_ids as $value2) {
515                 $gacl->del_group_object($value2, $section_aro_value, $user_name, 'ARO');
516               }
517             }
518             else {
519               //user ARO object does not exist, so will create it
520               $gacl->add_object($section_aro_value, $full_name, $user_name, 10, 0, 'ARO');
521             }
522           }
524           //place the user ARO object in the selected group (if group(s) is selected)
525           if (!empty($arr_group_titles)) {
526             $gacl->add_group_object($value, $section_aro_value, $user_name, 'ARO');
527           }
529           //
530           //Below will not allow 'admin' or gacl_protected user to be removed from 'admin' group
531           //
532           if ($gacl_protect) {
533             $boolean_admin=0;
534             $admin_id = $gacl->get_object_id($section_aro_value, $user_name, 'ARO');
535             $arr_admin = $gacl->get_object_groups($admin_id, 'ARO', 'NO_RECURSE');
536             foreach ($arr_admin as $value3) {
537               $arr_admin_data = $gacl->get_group_data($value3, 'ARO');
538               if (strcmp($arr_admin_data[2], 'admin') == 0) {
539                 $boolean_admin=1;
540               }
541             }
542             if (!$boolean_admin) {
543               foreach ($arr_all_group_ids as $value4) {
544                 $arr_temp = $gacl->get_group_data($value4, 'ARO');
545                 if ($arr_temp[2] == 'admin') {
546                   $gacl->add_group_object($value4, $section_aro_value, $user_name, 'ARO');
547                 }
548               }
549             }
550           }
551         }
552         //if array of groups was empty, then we are done, and can break from loop
553         if (empty($arr_group_titles)) break;
554       }
555       return true;
556     }
557    return false;
558   }
560   //
561   // Returns true if acl exist
562   // Returns false if acl doesn't exist
563   //  EITHER $title or $name is required(send FALSE in variable
564   //  not being used). If both are sent, then only $title will be
565   //  used.
566   //  $return_value is required
567   //    $title = title of acl (string)
568   //    $name = name of acl (string)
569   //    $return_value = return value of acl (string)
570   //
571   function acl_exist($title, $name, $return_value) {
572    global $phpgacl_location;
573    if (isset ($phpgacl_location)) {
574     include_once("$phpgacl_location/gacl_api.class.php");
575     $gacl = new gacl_api();
576     if (!$name) {
577      $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $title, FALSE, FALSE, FALSE, $return_value);
578     }
579     else if (!$title) {
580      $group_id = $gacl->get_group_id($name, NULL, 'ARO');
581      if ($group_id) {
582       $group_data = $gacl->get_group_data($group_id, 'ARO');
583       $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $group_data[3], FALSE, FALSE, FALSE, $return_value);
584      }
585      else {
586      return false;
587      }
588     }
589     else {
590      $acl = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $title, FALSE, FALSE, FALSE, $return_value);
591     }
592     if (!empty($acl)) {
593      return true;
594     }
595     else {
596      return false;
597     }
598    }
599   }
601   //
602   // This will add a new acl and group(if group doesn't yet exist)
603   // with one aco in it.
604   //   $acl_title = title of acl (string)
605   //   $acl_name = name of acl (string)
606   //   $return_value = return value of acl (string)
607   //   $note = description of acl (array)
608   //
609   function acl_add($acl_title, $acl_name, $return_value, $note) {
610    global $phpgacl_location;
611    if (isset ($phpgacl_location)) {
612     include_once("$phpgacl_location/gacl_api.class.php");
613     $gacl = new gacl_api();
614     $group_id = $gacl->get_group_id($acl_name, $acl_title, 'ARO');
615     if ($group_id) {
616      //group already exist, so just create acl
617      $gacl->add_acl(array("placeholder"=>array("filler")),
618       NULL, array($group_id), NULL, NULL, 1, 1, $return_value, $note);
619     }
620     else {
621      //create group, then create acl
622      $parent_id = $gacl->get_root_group_id();
623      $aro_id = $gacl->add_group($acl_name, $acl_title, $parent_id, 'ARO');
624      $gacl->add_acl(array("placeholder"=>array("filler")),
625       NULL, array($aro_id), NULL, NULL, 1, 1, $return_value, $note);
626     }
627     return;
628    }
629    return 0;
630   }
632   //
633   // This will remove acl. It will also remove group(if the group
634   // is no longer associated with any acl's).
635   //   $acl_title = title of acl (string)
636   //   $acl_name = name of acl (string)
637   //   $return_value = return value of acl (string)
638   //   $note = description of acl (array)
639   //
640   function acl_remove($acl_title, $return_value) {
641    global $phpgacl_location;
642    if (isset ($phpgacl_location)) {
643     include_once("$phpgacl_location/gacl_api.class.php");
644     $gacl = new gacl_api();
645     //First, delete the acl
646     $acl_id=$gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
647     $gacl->del_acl($acl_id[0]);
648     //Then, remove the group(if no more acl's are remaining)
649     $acl_search=$gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, FALSE);
650     if (empty($acl_search)){
651      $group_id=$gacl-> get_group_id(NULL, $acl_title, 'ARO');
652      $gacl->del_group($group_id, TRUE, 'ARO');
653     }
654     return;
655    }
656    return 0;
657   }
659   //
660   // This will place the aco(s) into the selected acl
661   //   $acl_title = title of acl (string)
662   //   $return_value = return value of acl (string)
663   //   $aco_id = id of aco (array)
664   //
665   function acl_add_acos($acl_title, $return_value, $aco_id) {
666    global $phpgacl_location;
667    if (isset ($phpgacl_location)) {
668     include_once("$phpgacl_location/gacl_api.class.php");
669     $gacl = new gacl_api();
670     $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
671     foreach ($aco_id as $value) {
672      $aco_data = $gacl->get_object_data($value, 'ACO');
673      $aco_section = $aco_data[0][0];
674      $aco_name = $aco_data[0][1];
675      $gacl->append_acl($acl_id[0], NULL, NULL, NULL, NULL, array($aco_section=>array($aco_name)));
676     }
677     return;
678    }
679    return 0;
680   }
682   //
683   // This will remove the aco(s) from the selected acl
684   //  Note if all aco's are removed, then will place the filler-placeholder
685   //  into the acl to avoid complete removal of the acl.
686   //   $acl_title = title of acl (string)
687   //   $return_value = return value of acl (string)
688   //   $aco_id = id of aco (array)
689   //
690   function acl_remove_acos($acl_title, $return_value, $aco_id) {
691    global $phpgacl_location;
692    if (isset ($phpgacl_location)) {
693     include_once("$phpgacl_location/gacl_api.class.php");
694     $gacl = new gacl_api();
695     $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
697     // Check to see if removing all acos. If removing all acos then will
698     //  ensure the filler-placeholder aco in acl to avoid complete
699     //  removal of the acl.
700     if (count($aco_id) == acl_count_acos($acl_title, $return_value)) {
701      //1-get the filler-placeholder aco id
702      $filler_aco_id = $gacl->get_object_id('placeholder','filler','ACO');
703      //2-add filler-placeholder aco
704      acl_add_acos($acl_title, $return_value, array($filler_aco_id));
705      //3-ensure filler-placeholder aco is not to be deleted
706      $safeListaco = remove_element($_POST["selection"],$filler_aco_id);
707      //4-prepare to safely delete the acos
708      $aco_id = $safeListaco;
709     }
711     foreach ($aco_id as $value) {
712      $aco_data = $gacl->get_object_data($value, 'ACO');
713      $aco_section = $aco_data[0][0];
714      $aco_name = $aco_data[0][1];
715      $gacl->shift_acl($acl_id[0], NULL, NULL, NULL, NULL, array($aco_section=>array($aco_name)));
716      }
717     return;
718    }
719    return 0;
720   }
722   //
723   // This will return the number of aco objects
724   //  in a specified acl.
725   //   $acl_title = title of acl (string)
726   //   $return_value = return value of acl (string)
727   //
728   function acl_count_acos($acl_title, $return_value) {
729    global $phpgacl_location;
730    if (isset ($phpgacl_location)) {
731     include_once("$phpgacl_location/gacl_api.class.php");
732     $gacl = new gacl_api();
733     $acl_id = $gacl->search_acl(FALSE, FALSE, FALSE, FALSE, $acl_title, FALSE, FALSE, FALSE, $return_value);
734     $acl_data = $gacl->get_acl($acl_id[0]);
735     $aco_count = 0;
736     foreach ($acl_data['aco'] as $key => $value) {
737      $aco_count = $aco_count + count($acl_data['aco'][$key]);
738     }
739     return $aco_count;
740    }
741    return 0;
742   }
744   //
745   // Function to remove an element from an array
746   //
747   function remove_element($arr, $val){
748    $arr2 = array();
749    foreach ($arr as $value){
750     if ($value != $val) {
751      array_push($arr2,$value);
752     }
753    }
754    return $arr2;
755   }
756   /**
757   * Checks ACL
758   *
759   * Same Functionality in the Zend Module
760   * for ACL Check in Zend
761   * Path openemr/interface/modules/zend_modules/module/Application/src/Application/Model/ApplicationTable
762   * Function Name zAclCheck
763   *
764   * @param String $user_id Auth user Id
765   * $param String $section_identifier ACL Section id
766   * @return boolean
767   */
768   function zh_acl_check($user_id,$section_identifier){
769     $sql_user_acl = " SELECT
770                         COUNT(allowed) AS count
771                       FROM
772                         module_acl_user_settings AS usr_settings
773                         LEFT JOIN module_acl_sections AS acl_sections
774                             ON usr_settings.section_id = acl_sections.`section_id`
775                       WHERE
776                           acl_sections.section_identifier = ? AND usr_settings.user_id = ? AND usr_settings.allowed = ?";
777     $sql_user_group = " SELECT
778                           gagp.id AS group_id
779                         FROM
780                           gacl_aro AS garo
781                           LEFT JOIN `gacl_groups_aro_map` AS gamp
782                             ON garo.id = gamp.aro_id
783                           LEFT JOIN `gacl_aro_groups` AS gagp
784                             ON gagp.id = gamp.group_id
785                           RIGHT JOIN `users_secure` usr
786                             ON usr. username =  garo.value
787                         WHERE
788                           garo.section_value = ? AND usr. id = ?";
789     $res_groups     = sqlStatement($sql_user_group,array('users',$user_id));
791     // Prepare the group queries with the placemakers and binding array for the IN part
792     $groups_sql_param = array();
793     $groupPlacemakers = "";
794     $firstFlag = TRUE;
795     while($row = sqlFetchArray($res_groups)){
796       array_push($groups_sql_param,$row['group_id']);
797       if ($firstFlag) {
798         $groupPlacemakers = "?";
799         $firstFlag = FALSE;
800       }
801       else {
802         $groupPlacemakers .= ",?";
803       }
804     }
805     $sql_group_acl_base  = " SELECT
806                         COUNT(allowed) AS count
807                       FROM
808                         module_acl_group_settings AS group_settings
809                         LEFT JOIN module_acl_sections AS  acl_sections
810                           ON group_settings.section_id = acl_sections.section_id
811                       WHERE
812                         group_settings.group_id IN (".$groupPlacemakers.") AND acl_sections.`section_identifier` = ? ";
814     $sql_group_acl_allowed = $sql_group_acl_base . " AND group_settings.allowed = '1'";
816     // Complete the group queries sql binding array
817     array_push($groups_sql_param, $section_identifier);
819         $count_group_allowed    = 0;
820         $count_user_allowed     = 0;
822         $res_user_allowed       = sqlQuery($sql_user_acl,array($section_identifier,$user_id,1));
823         $count_user_allowed     = $res_user_allowed['count'];
825         $res_group_allowed      = sqlQuery($sql_group_acl_allowed, $groups_sql_param);
826         $count_group_allowed    = $res_group_allowed['count'];
828         if($count_user_allowed > 0)
829             return true;
830         elseif($count_group_allowed > 0)
831             return true;
832         else
833             return false;
834     }
836   // This generates an HTML options list for all ACOs.
837   // The caller inserts this between <select> and </select> tags.
838   //
839   function gen_aco_html_options($default='') {
840     global $phpgacl_location;
841     require_once("$phpgacl_location/gacl_api.class.php");
842     $s = '';
843     $gacl = new gacl_api();
844     // collect and sort all aco objects
845     $list_aco_objects = $gacl->get_objects(NULL, 0, 'ACO');
846     ksort($list_aco_objects);
847     foreach ($list_aco_objects as $seckey => $dummy) {
848       if (empty($dummy)) continue;
849       asort($list_aco_objects[$seckey]);
850       $aco_section_data = $gacl->get_section_data($seckey, 'ACO');
851       $aco_section_title = $aco_section_data[3];
852       $s .= "<optgroup label='" . xla($aco_section_title) . "'>\n";
853       foreach($list_aco_objects[$seckey] as $acokey) {
854         $aco_id = $gacl->get_object_id($seckey, $acokey,'ACO');
855         $aco_data = $gacl->get_object_data($aco_id, 'ACO');
856         $aco_title = $aco_data[0][3];
857         $optkey = "$seckey|$acokey";
858         $s .= "<option value='" . attr($optkey) . "'";
859         if ($optkey == $default) $s .= ' selected';
860         $s .= ">" . xlt($aco_title) . "</option>";
861       }
862       $s .= "</optgroup>";
863     }
864     return $s;
865   }
867   // Permissions check for an ACO in "section|aco" format.
868   // Note $return_value may be an array of return values.
869   //
870   function acl_check_aco_spec($aco_spec, $user='', $return_value='') {
871     if (empty($aco_spec)) return true;
872     $tmp = explode('|', $aco_spec);
873     if (!is_array($return_value)) $return_value = array($return_value);
874     foreach ($return_value as $rv) {
875       if (acl_check($tmp[0], $tmp[1], $user, $rv)) return true;
876     }
877     return false;
878   }
880   // Permissions check for a specified encounter form type.
881   // Note $return_value may be an array of return values.
882   //
883   function acl_check_form($formdir, $user='', $return_value='') {
884     require_once(dirname(__FILE__) . '/registry.inc');
885     $tmp = getRegistryEntryByDirectory($formdir, 'aco_spec');
886     return acl_check_aco_spec($tmp['aco_spec'], $user, $return_value);
887   }
889   // Permissions check for a specified issue type.
890   // Note $return_value may be an array of return values.
891   //
892   function acl_check_issue($type, $user='', $return_value='') {
893     require_once(dirname(__FILE__) . '/lists.inc');
894     global $ISSUE_TYPES;
895     if (empty($ISSUE_TYPES[$type][5])) return true;
896     return acl_check_aco_spec($ISSUE_TYPES[$type][5], $user, $return_value);
897   }
899   // Permissions check for a specified document category name.
900   // Note $return_value may be an array of return values.
901   //
902   function acl_check_cat_name($catname, $user='', $return_value='') {
903     $tmp = sqlQuery("SELECT aco_spec FROM categories WHERE name = ? ORDER BY id LIMIT 1",
904       array($catname));
905     if (empty($tmp['aco_spec'])) return true;
906     return acl_check_aco_spec($tmp['aco_spec'], $user, $return_value);
907   }