1 | <?php |
||||
2 | /** |
||||
3 | * EGroupware: Admin ACL |
||||
4 | * |
||||
5 | * @link http://www.egroupware.org |
||||
6 | * @author Ralf Becker <[email protected]> |
||||
7 | * @package admin |
||||
8 | * @copyright (c) 2013-16 by Ralf Becker <[email protected]> |
||||
9 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||||
10 | * @version $Id$ |
||||
11 | */ |
||||
12 | |||||
13 | use EGroupware\Api; |
||||
14 | use EGroupware\Api\Framework; |
||||
15 | use EGroupware\Api\Acl; |
||||
16 | use EGroupware\Api\Etemplate; |
||||
17 | |||||
18 | /** |
||||
19 | * UI for admin ACL |
||||
20 | * |
||||
21 | * Will also be extended by preferences_acl for user ACL |
||||
22 | */ |
||||
23 | class admin_acl |
||||
24 | { |
||||
25 | /** |
||||
26 | * Methods callable via menuaction |
||||
27 | * @var array |
||||
28 | */ |
||||
29 | public $public_functions = array( |
||||
30 | 'index' => true, |
||||
31 | ); |
||||
32 | |||||
33 | /** |
||||
34 | * Reference to global Acl class (instanciated for current user) |
||||
35 | * |
||||
36 | * @var Acl |
||||
37 | */ |
||||
38 | protected $acl; |
||||
39 | |||||
40 | /** |
||||
41 | * Constructor |
||||
42 | */ |
||||
43 | public function __construct() |
||||
44 | { |
||||
45 | $this->acl = $GLOBALS['egw']->acl; |
||||
46 | } |
||||
47 | |||||
48 | /** |
||||
49 | * Save run rights and refresh opener |
||||
50 | * |
||||
51 | * @param array $content |
||||
52 | */ |
||||
53 | protected function save_run_rights(array $content) |
||||
54 | { |
||||
55 | $old_apps = array_keys($this->acl->get_user_applications($content['acl_account'], false, false)); |
||||
56 | // add new apps |
||||
57 | $added_apps = array_diff($content['apps'], $old_apps); |
||||
58 | foreach($added_apps as $app) |
||||
59 | { |
||||
60 | $this->acl->add_repository($app, 'run', $content['acl_account'], 1); |
||||
61 | } |
||||
62 | // remove no longer checked apps |
||||
63 | $removed_apps = array_diff($old_apps, $content['apps']); |
||||
64 | $deleted_ids = array(); |
||||
65 | foreach($removed_apps as $app) |
||||
66 | { |
||||
67 | $this->acl->delete_repository($app, 'run', $content['acl_account']); |
||||
68 | $deleted_ids[] = $app.':'.$content['acl_account'].':run'; |
||||
69 | } |
||||
70 | //error_log(__METHOD__."() apps=".array2string($content['apps']).", old_apps=".array2string($old_apps).", added_apps=".array2string($added_apps).", removed_apps=".array2string($removed_apps)); |
||||
71 | |||||
72 | if (!$added_apps && !$removed_apps) |
||||
0 ignored issues
–
show
The expression
$removed_apps of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
73 | { |
||||
74 | // nothing changed --> nothing to do/notify |
||||
75 | } |
||||
76 | elseif (!$old_apps) |
||||
0 ignored issues
–
show
The expression
$old_apps of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
77 | { |
||||
78 | Framework::refresh_opener(lang('ACL added.'), 'admin', null, 'add'); |
||||
79 | } |
||||
80 | elseif (!$added_apps) |
||||
0 ignored issues
–
show
The expression
$added_apps of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
81 | { |
||||
82 | Framework::refresh_opener(lang('ACL deleted.'), 'admin', $deleted_ids, 'delete'); |
||||
83 | } |
||||
84 | else |
||||
85 | { |
||||
86 | Framework::refresh_opener(lang('ACL updated.'), 'admin', null, 'edit'); |
||||
87 | } |
||||
88 | } |
||||
89 | |||||
90 | /** |
||||
91 | * Save rights and refresh opener |
||||
92 | * |
||||
93 | * @param array $content |
||||
94 | */ |
||||
95 | protected function save_rights(array $content) |
||||
96 | { |
||||
97 | // assamble rights again |
||||
98 | $rights = (int)$content['preserve_rights']; |
||||
99 | foreach($content['acl'] as $right) |
||||
100 | { |
||||
101 | $rights |= $right; |
||||
102 | } |
||||
103 | $id = !empty($content['id']) ? $content['id'] : |
||||
104 | $content['acl_appname'].':'.$content['acl_account'].':'.$content['acl_location']; |
||||
105 | //error_log(__METHOD__."() id=$id, acl=".array2string($content['acl'])." --> rights=$rights"); |
||||
106 | |||||
107 | if ($this->acl->get_specific_rights_for_account($content['acl_account'], $content['acl_location'], $content['acl_appname']) == $rights) |
||||
108 | { |
||||
109 | // nothing changed --> nothing to do |
||||
110 | } |
||||
111 | elseif (!$rights) // all rights removed --> delete it |
||||
112 | { |
||||
113 | $this->acl->delete_repository($content['acl_appname'], $content['acl_location'], $content['acl_account']); |
||||
114 | Framework::refresh_opener(lang('ACL deleted.'), 'admin', $id, 'delete'); |
||||
115 | } |
||||
116 | else |
||||
117 | { |
||||
118 | $this->acl->add_repository($content['acl_appname'], $content['acl_location'], $content['acl_account'], $rights); |
||||
119 | if ($content['id']) |
||||
120 | { |
||||
121 | Framework::refresh_opener(lang('ACL updated.'), 'admin', $id, 'edit'); |
||||
122 | } |
||||
123 | else |
||||
124 | { |
||||
125 | Framework::refresh_opener(lang('ACL added.'), 'admin', $id, 'add'); |
||||
126 | } |
||||
127 | } |
||||
128 | } |
||||
129 | |||||
130 | /** |
||||
131 | * Callback for nextmatch to fetch Acl |
||||
132 | * |
||||
133 | * @param array $query |
||||
134 | * @param array &$rows=null |
||||
135 | * @return int total number of rows available |
||||
136 | */ |
||||
137 | public static function get_rows(array $query, array &$rows=null) |
||||
138 | { |
||||
139 | $so_sql = new Api\Storage\Base('phpgwapi', Acl::TABLE, null, '', true); |
||||
140 | |||||
141 | // client queries destinct rows by their row-id |
||||
142 | if (isset($query['col_filter']['id'])) |
||||
143 | { |
||||
144 | $query['col_filter'][] = $GLOBALS['egw']->db->concat('acl_appname',"':'",'acl_account',"':'",'acl_location'). |
||||
145 | ' IN ('.implode(',', array_map(array($GLOBALS['egw']->db, 'quote'), (array)$query['col_filter']['id'])).')'; |
||||
146 | unset($query['col_filter']['id']); |
||||
147 | } |
||||
148 | else |
||||
149 | { |
||||
150 | $memberships = $GLOBALS['egw']->accounts->memberships($query['account_id'], true); |
||||
151 | $memberships[] = $query['account_id']; |
||||
152 | |||||
153 | Api\Cache::setSession(__CLASS__, 'state', array( |
||||
154 | 'account_id' => $query['account_id'], |
||||
155 | 'filter' => $query['filter'], |
||||
156 | 'acl_appname' => $query['filter2'], |
||||
157 | )); |
||||
158 | |||||
159 | if ($GLOBALS['egw_info']['user']['preferences']['admin']['acl_filter'] != $query['filter']) |
||||
160 | { |
||||
161 | $GLOBALS['egw']->preferences->add('admin', 'acl_filter', $query['filter']); |
||||
162 | $GLOBALS['egw']->preferences->save_repository(false,'user',false); |
||||
163 | } |
||||
164 | switch($query['filter']) |
||||
165 | { |
||||
166 | case 'run': |
||||
167 | $query['col_filter']['acl_location'] = 'run'; |
||||
168 | $query['col_filter']['acl_account'] = $memberships; |
||||
169 | break; |
||||
170 | default: |
||||
171 | case 'other': |
||||
172 | //$query['col_filter'][] = "acl_location!='run'"; |
||||
173 | // remove everything not an account-id in location, like category based acl |
||||
174 | if (substr($GLOBALS['egw']->db->Type, 0, 5) == 'mysql') |
||||
175 | { |
||||
176 | $query['col_filter'][] = "acl_location REGEXP '^-?[0-9]+$'"; |
||||
177 | } |
||||
178 | else |
||||
179 | { |
||||
180 | $query['col_filter'][] = "acl_location SIMILAR TO '-?[0-9]+'"; |
||||
181 | } |
||||
182 | // get apps not using group-acl (eg. Addressbook) or using it only partialy (eg. InfoLog) |
||||
183 | $not_enum_group_acls = Api\Hooks::process('not_enum_group_acls', array(), true); |
||||
184 | //error_log(__METHOD__."(filter=$query[filter]) not_enum_group_acl=".array2string($not_enum_group_acls)); |
||||
185 | if ($not_enum_group_acls) |
||||
186 | { |
||||
187 | $sql = '(CASE acl_appname'; |
||||
188 | foreach($not_enum_group_acls as $app => $groups) |
||||
189 | { |
||||
190 | if ($groups === true) |
||||
191 | { |
||||
192 | $check = $query['account_id']; |
||||
193 | } |
||||
194 | else |
||||
195 | { |
||||
196 | $check = array_diff($memberships, $groups); |
||||
197 | //error_log(__METHOD__."() app=$app, array_diff(memberships=".array2string($memberships).", groups=".array2string($groups).")=".array2string($check)); |
||||
198 | if (!$check) continue; // would give sql error otherwise! |
||||
0 ignored issues
–
show
The expression
$check of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||
199 | } |
||||
200 | $sql .= ' WHEN '.$GLOBALS['egw']->db->quote($app).' THEN '.$GLOBALS['egw']->db->expression(Acl::TABLE, array( |
||||
201 | 'acl_account' => $check, |
||||
202 | )); |
||||
203 | } |
||||
204 | $sql .= ' ELSE '; |
||||
205 | } |
||||
206 | $sql .= $GLOBALS['egw']->db->expression(Acl::TABLE, array( |
||||
207 | 'acl_account' => $memberships, |
||||
208 | )); |
||||
209 | if ($not_enum_group_acls) $sql .= ' END)'; |
||||
210 | $query['col_filter'][] = $sql; |
||||
211 | break; |
||||
212 | |||||
213 | case 'own': |
||||
214 | $query['col_filter']['acl_location'] = $memberships; |
||||
215 | break; |
||||
216 | } |
||||
217 | // do NOT list group-memberships and other non-ACL stuff here |
||||
218 | $query['col_filter']['acl_appname'] = $query['filter2']; |
||||
219 | if (empty($query['col_filter']['acl_appname']) && $query['filter'] != 'run') |
||||
220 | { |
||||
221 | //$query['col_filter'][] = "NOT acl_appname IN ('phpgw_group','sqlfs')"; |
||||
222 | $query['col_filter']['acl_appname'] = array_keys($query['acl_rights']); |
||||
223 | } |
||||
224 | } |
||||
225 | $readonlys = array(); |
||||
226 | $total = $so_sql->get_rows($query, $rows, $readonlys); |
||||
227 | |||||
228 | foreach($rows as &$row) |
||||
229 | { |
||||
230 | // generate a row-id |
||||
231 | $row['id'] = $row['acl_appname'].':'.$row['acl_account'].':'.$row['acl_location']; |
||||
232 | |||||
233 | if ($row['acl_location'] == 'run') |
||||
234 | { |
||||
235 | $row['acl1'] = lang('run'); |
||||
236 | } |
||||
237 | else |
||||
238 | { |
||||
239 | if ($app !== $row['acl_appname']) Api\Translation::add_app($row['app_name']); |
||||
240 | foreach($query['acl_rights'][$row['acl_appname']] as $val => $label) |
||||
241 | { |
||||
242 | if ($row['acl_rights'] & $val) |
||||
243 | { |
||||
244 | $row['acl'.$val] = lang($label); |
||||
245 | } |
||||
246 | } |
||||
247 | } |
||||
248 | if (!self::check_access($row['acl_account'], $row['acl_location'], false)) // false: do NOT throw an exception! |
||||
249 | { |
||||
250 | $row['class'] = 'rowNoEdit'; |
||||
251 | } |
||||
252 | //error_log(__METHOD__."() $n: ".array2string($row)); |
||||
253 | } |
||||
254 | //error_log(__METHOD__."(".array2string($query).") returning ".$total); |
||||
255 | |||||
256 | // Get supporting or all apps for filter2 depending on filter |
||||
257 | if($query['filter'] == 'run') |
||||
258 | { |
||||
259 | $rows['sel_options']['filter2'] = array( |
||||
260 | '' => lang('All applications'), |
||||
261 | )+Etemplate\Widget\Select::app_options('enabled'); |
||||
262 | } |
||||
263 | else |
||||
264 | { |
||||
265 | $rows['sel_options']['filter2'] = array( |
||||
266 | array('value' => '', 'label' => lang('All applications')) |
||||
267 | ); |
||||
268 | $apps = Api\Hooks::process(array( |
||||
269 | 'location' => 'acl_rights', |
||||
270 | 'owner' => $query['account_id'], |
||||
271 | ), array(), true); |
||||
272 | foreach(array_keys($apps) as $appname) |
||||
273 | { |
||||
274 | $rows['sel_options']['filter2'][] = array( |
||||
275 | 'value' => $appname, |
||||
276 | 'label' => lang($appname) |
||||
277 | ); |
||||
278 | } |
||||
279 | usort($rows['sel_options']['filter2'], function($a,$b) { |
||||
280 | return strcasecmp($a['label'], $b['label']); |
||||
281 | }); |
||||
282 | } |
||||
283 | |||||
284 | return $total; |
||||
285 | } |
||||
286 | |||||
287 | /** |
||||
288 | * Check if current user has access to ACL setting of a given location |
||||
289 | * |
||||
290 | * @param int $account_id numeric account-id |
||||
291 | * @param int|string $location =null numeric account-id or "run" |
||||
292 | * @param boolean $throw =true if true, throw an exception if no access, instead of just returning false |
||||
293 | * @return boolean true if access is granted, false if notification_bo |
||||
294 | * @throws Api\Exception\NoPermission |
||||
295 | */ |
||||
296 | public static function check_access($account_id, $location=null, $throw=true) |
||||
297 | { |
||||
298 | static $admin_access=null; |
||||
299 | static $own_access=null; |
||||
300 | if (is_null($admin_access)) |
||||
301 | { |
||||
302 | $admin_access = isset($GLOBALS['egw_info']['user']['apps']['admin']) && |
||||
303 | !$GLOBALS['egw']->acl->check('account_access', 64, 'admin'); // ! because this denies access! |
||||
304 | $own_access = $admin_access || isset($GLOBALS['egw_info']['user']['apps']['preferences']); |
||||
305 | } |
||||
306 | if (!(int)$account_id || !((int)$account_id == (int)$GLOBALS['egw_info']['user']['account_id'] && $location !== 'run' ? |
||||
307 | $own_access : $admin_access)) |
||||
308 | { |
||||
309 | if ($throw) throw new Api\Exception\NoPermission(lang('Permission denied!!!')); |
||||
310 | return false; |
||||
311 | } |
||||
312 | return true; |
||||
313 | } |
||||
314 | |||||
315 | /** |
||||
316 | * Get the list of applications allowed for the given user |
||||
317 | * |
||||
318 | * The list of applications is added to the json response |
||||
319 | * |
||||
320 | * @param int $account_id |
||||
321 | */ |
||||
322 | public static function ajax_get_app_list($account_id) |
||||
323 | { |
||||
324 | $list = array(); |
||||
325 | if(self::check_access((int)$account_id,'run',false)) |
||||
326 | { |
||||
327 | $list = array_keys($GLOBALS['egw']->acl->get_user_applications((int)$account_id,false,false)); |
||||
328 | } |
||||
329 | Api\Json\Response::get()->data($list); |
||||
330 | } |
||||
331 | |||||
332 | /** |
||||
333 | * Change (add, modify, delete) an ACL entry |
||||
334 | * |
||||
335 | * Checks access and throws an exception, if a change is attempted without proper access |
||||
336 | * |
||||
337 | * @param string|array $ids "$app:$account:$location" string used as row-id in list |
||||
338 | * @param int $rights null to delete, or new rights |
||||
339 | * @param array $values Additional values from UI |
||||
340 | * @param string $etemplate_exec_id to check against CSRF |
||||
341 | * @throws Api\Exception\NoPermission |
||||
342 | */ |
||||
343 | public static function ajax_change_acl($ids, $rights, $values, $etemplate_exec_id) |
||||
344 | { |
||||
345 | Api\Etemplate\Request::csrfCheck($etemplate_exec_id, __METHOD__, func_get_args()); |
||||
346 | |||||
347 | try { |
||||
348 | foreach((array)$ids as $id) |
||||
349 | { |
||||
350 | list($app, $account_id, $location) = explode(':', $id, 3); |
||||
351 | |||||
352 | self::check_access($account_id, $location); // throws exception, if no rights |
||||
353 | |||||
354 | $acl = $GLOBALS['egw']->acl; |
||||
355 | |||||
356 | if($location == 'run') |
||||
357 | { |
||||
358 | $right_list = array(1 => 'run'); |
||||
359 | } |
||||
360 | else |
||||
361 | { |
||||
362 | $right_list = Api\Hooks::single(array( |
||||
363 | 'location' => 'acl_rights', |
||||
364 | 'owner' => $location, |
||||
365 | ), $app); |
||||
366 | } |
||||
367 | $current = (int)$acl->get_specific_rights_for_account($account_id,$location,$app); |
||||
368 | foreach(array_keys((array)$right_list) as $right) |
||||
369 | { |
||||
370 | $have_it = !!($current & $right); |
||||
371 | $set_it = !!($rights & $right); |
||||
372 | if($have_it == $set_it) continue; |
||||
373 | $data = array( |
||||
374 | 'allow' => $set_it, |
||||
375 | 'account' => $account_id, |
||||
376 | 'app' => $app, |
||||
377 | 'location' => $location, |
||||
378 | 'rights' => (int)$right |
||||
379 | // This is the documentation from policy app |
||||
380 | )+(array)$values['admin_cmd']; |
||||
381 | if($location == 'run') |
||||
382 | { |
||||
383 | $cmd = new admin_cmd_account_app($set_it,$account_id, $app, (array)$values['admin_cmd']); |
||||
384 | } |
||||
385 | else |
||||
386 | { |
||||
387 | $cmd = new admin_cmd_acl($data); |
||||
388 | } |
||||
389 | $cmd->run(); |
||||
390 | } |
||||
391 | } |
||||
392 | if (!(int)$rights) |
||||
393 | { |
||||
394 | if (count($ids) > 1) |
||||
395 | { |
||||
396 | $msg = lang('%1 ACL entries deleted.', count($ids)); |
||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with count($ids) .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
397 | } |
||||
398 | else |
||||
399 | { |
||||
400 | $msg = lang('ACL entry deleted.'); |
||||
401 | } |
||||
402 | } |
||||
403 | else |
||||
404 | { |
||||
405 | $msg = lang('ACL updated'); |
||||
406 | } |
||||
407 | Api\Json\Response::get()->data(array( |
||||
408 | 'msg' => $msg, |
||||
409 | 'ids' => $ids, |
||||
410 | 'type' => !(int)$rights ? 'delete' : 'add', |
||||
411 | )); |
||||
412 | } |
||||
413 | catch (Exception $e) { |
||||
414 | Api\Json\Response::get()->call('egw.message', $e->getMessage(), 'error'); |
||||
415 | } |
||||
416 | } |
||||
417 | |||||
418 | /** |
||||
419 | * New index page |
||||
420 | * |
||||
421 | * @param array $_content =null |
||||
422 | */ |
||||
423 | public function index(array $_content=null) |
||||
424 | { |
||||
425 | unset($_content); // not used, required by function signature |
||||
426 | |||||
427 | $tpl = new Etemplate('admin.acl'); |
||||
428 | |||||
429 | $content = array(); |
||||
430 | $account_id = isset($_GET['account_id']) && (int)$_GET['account_id'] ? |
||||
431 | (int)$_GET['account_id'] : $GLOBALS['egw_info']['user']['account_id']; |
||||
432 | $content['nm'] = array( |
||||
433 | 'get_rows' => 'admin_acl::get_rows', |
||||
434 | 'no_cat' => true, |
||||
435 | 'filter' => !empty($_GET['acl_filter']) ? $_GET['acl_filter'] : |
||||
436 | ($GLOBALS['egw_info']['flags']['currentapp'] != 'admin' ? 'other' : |
||||
437 | $GLOBALS['egw_info']['user']['preferences']['admin']['acl_filter']), |
||||
438 | 'filter2' => !empty($_GET['acl_app']) ? $_GET['acl_app'] : '', |
||||
439 | 'lettersearch' => false, |
||||
440 | 'order' => 'acl_appname', |
||||
441 | 'sort' => 'ASC', |
||||
442 | 'row_id' => 'id', |
||||
443 | 'account_id' => $account_id, |
||||
444 | 'actions' => self::get_actions(), |
||||
445 | 'acl_rights' => Api\Hooks::process(array( |
||||
446 | 'location' => 'acl_rights', |
||||
447 | 'owner' => $account_id, |
||||
448 | ), array(), true), |
||||
449 | ); |
||||
450 | $user = Api\Accounts::username($content['nm']['account_id']); |
||||
451 | $sel_options = array( |
||||
452 | 'filter' => array( |
||||
453 | 'other' => lang('Access to %1 data by others', $user), |
||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $user .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||
454 | 'own' => lang('%1 access to other data', $user), |
||||
455 | 'run' => lang('%1 run rights for applications', $user), |
||||
456 | ) |
||||
457 | ); |
||||
458 | |||||
459 | // Set this so if loaded via preferences, js is still properly |
||||
460 | // loaded into global app.admin |
||||
461 | $GLOBALS['egw_info']['flags']['currentapp'] = 'admin'; |
||||
462 | |||||
463 | $tpl->exec('admin.admin_acl.index', $content, $sel_options, array(), array(), 2); |
||||
464 | } |
||||
465 | |||||
466 | /** |
||||
467 | * Get actions for ACL |
||||
468 | * |
||||
469 | * @return array |
||||
470 | */ |
||||
471 | static function get_actions() |
||||
472 | { |
||||
473 | return array( |
||||
474 | 'edit' => array( |
||||
475 | 'caption' => 'Edit', |
||||
476 | 'default' => true, |
||||
477 | 'allowOnMultiple' => false, |
||||
478 | 'disableClass' => 'rowNoEdit', |
||||
479 | 'onExecute' => 'javaScript:app.admin.acl', |
||||
480 | ), |
||||
481 | 'add' => array( |
||||
482 | 'caption' => 'Add', |
||||
483 | 'disableClass' => 'rowNoEdit', |
||||
484 | 'onExecute' => 'javaScript:app.admin.acl', |
||||
485 | ), |
||||
486 | 'delete' => array( |
||||
487 | 'caption' => 'Delete', |
||||
488 | 'disableClass' => 'rowNoEdit', |
||||
489 | 'onExecute' => 'javaScript:app.admin.acl', |
||||
490 | ), |
||||
491 | ); |
||||
492 | } |
||||
493 | } |
||||
494 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.