1<?php 2/** 3 * ACL administration functions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 * @author Anika Henke <anika@selfthinker.org> (concepts) 8 * @author Frank Schubert <frank@schokilade.de> (old version) 9 */ 10 11/** 12 * All DokuWiki plugins to extend the admin function 13 * need to inherit from this class 14 */ 15class admin_plugin_acl extends DokuWiki_Admin_Plugin 16{ 17 public $acl = null; 18 protected $ns = null; 19 /** 20 * The currently selected item, associative array with id and type. 21 * Populated from (in this order): 22 * $_REQUEST['current_ns'] 23 * $_REQUEST['current_id'] 24 * $ns 25 * $ID 26 */ 27 protected $current_item = null; 28 protected $who = ''; 29 protected $usersgroups = array(); 30 protected $specials = array(); 31 32 /** 33 * return prompt for admin menu 34 */ 35 public function getMenuText($language) 36 { 37 return $this->getLang('admin_acl'); 38 } 39 40 /** 41 * return sort order for position in admin menu 42 */ 43 public function getMenuSort() 44 { 45 return 1; 46 } 47 48 /** 49 * handle user request 50 * 51 * Initializes internal vars and handles modifications 52 * 53 * @author Andreas Gohr <andi@splitbrain.org> 54 */ 55 public function handle() 56 { 57 global $AUTH_ACL; 58 global $ID; 59 global $auth; 60 global $config_cascade; 61 global $INPUT; 62 63 // fresh 1:1 copy without replacements 64 $AUTH_ACL = file($config_cascade['acl']['default']); 65 66 // namespace given? 67 if ($INPUT->str('ns') == '*') { 68 $this->ns = '*'; 69 } else { 70 $this->ns = cleanID($INPUT->str('ns')); 71 } 72 73 if ($INPUT->str('current_ns')) { 74 $this->current_item = array('id' => cleanID($INPUT->str('current_ns')), 'type' => 'd'); 75 } elseif ($INPUT->str('current_id')) { 76 $this->current_item = array('id' => cleanID($INPUT->str('current_id')), 'type' => 'f'); 77 } elseif ($this->ns) { 78 $this->current_item = array('id' => $this->ns, 'type' => 'd'); 79 } else { 80 $this->current_item = array('id' => $ID, 'type' => 'f'); 81 } 82 83 // user or group choosen? 84 $who = trim($INPUT->str('acl_w')); 85 if ($INPUT->str('acl_t') == '__g__' && $who) { 86 $this->who = '@'.ltrim($auth->cleanGroup($who), '@'); 87 } elseif ($INPUT->str('acl_t') == '__u__' && $who) { 88 $this->who = ltrim($who, '@'); 89 if ($this->who != '%USER%' && $this->who != '%GROUP%') { #keep wildcard as is 90 $this->who = $auth->cleanUser($this->who); 91 } 92 } elseif ($INPUT->str('acl_t') && 93 $INPUT->str('acl_t') != '__u__' && 94 $INPUT->str('acl_t') != '__g__') { 95 $this->who = $INPUT->str('acl_t'); 96 } elseif ($who) { 97 $this->who = $who; 98 } 99 100 // handle modifications 101 if ($INPUT->has('cmd') && checkSecurityToken()) { 102 $cmd = $INPUT->extract('cmd')->str('cmd'); 103 104 // scope for modifications 105 if ($this->ns) { 106 if ($this->ns == '*') { 107 $scope = '*'; 108 } else { 109 $scope = $this->ns.':*'; 110 } 111 } else { 112 $scope = $ID; 113 } 114 115 if ($cmd == 'save' && $scope && $this->who && $INPUT->has('acl')) { 116 // handle additions or single modifications 117 $this->deleteACL($scope, $this->who); 118 $this->addOrUpdateACL($scope, $this->who, $INPUT->int('acl')); 119 } elseif ($cmd == 'del' && $scope && $this->who) { 120 // handle single deletions 121 $this->deleteACL($scope, $this->who); 122 } elseif ($cmd == 'update') { 123 $acl = $INPUT->arr('acl'); 124 125 // handle update of the whole file 126 foreach ($INPUT->arr('del') as $where => $names) { 127 // remove all rules marked for deletion 128 foreach ($names as $who) 129 unset($acl[$where][$who]); 130 } 131 // prepare lines 132 $lines = array(); 133 // keep header 134 foreach ($AUTH_ACL as $line) { 135 if ($line{0} == '#') { 136 $lines[] = $line; 137 } else { 138 break; 139 } 140 } 141 // re-add all rules 142 foreach ($acl as $where => $opt) { 143 foreach ($opt as $who => $perm) { 144 if ($who[0]=='@') { 145 if ($who!='@ALL') { 146 $who = '@'.ltrim($auth->cleanGroup($who), '@'); 147 } 148 } elseif ($who != '%USER%' && $who != '%GROUP%') { #keep wildcard as is 149 $who = $auth->cleanUser($who); 150 } 151 $who = auth_nameencode($who, true); 152 $lines[] = "$where\t$who\t$perm\n"; 153 } 154 } 155 // save it 156 io_saveFile($config_cascade['acl']['default'], join('', $lines)); 157 } 158 159 // reload ACL config 160 $AUTH_ACL = file($config_cascade['acl']['default']); 161 } 162 163 // initialize ACL array 164 $this->initAclConfig(); 165 } 166 167 /** 168 * ACL Output function 169 * 170 * print a table with all significant permissions for the 171 * current id 172 * 173 * @author Frank Schubert <frank@schokilade.de> 174 * @author Andreas Gohr <andi@splitbrain.org> 175 */ 176 public function html() 177 { 178 echo '<div id="acl_manager">'.NL; 179 echo '<h1>'.$this->getLang('admin_acl').'</h1>'.NL; 180 echo '<div class="level1">'.NL; 181 182 echo '<div id="acl__tree">'.NL; 183 $this->makeExplorer(); 184 echo '</div>'.NL; 185 186 echo '<div id="acl__detail">'.NL; 187 $this->printDetail(); 188 echo '</div>'.NL; 189 echo '</div>'.NL; 190 191 echo '<div class="clearer"></div>'; 192 echo '<h2>'.$this->getLang('current').'</h2>'.NL; 193 echo '<div class="level2">'.NL; 194 $this->printAclTable(); 195 echo '</div>'.NL; 196 197 echo '<div class="footnotes"><div class="fn">'.NL; 198 echo '<sup><a id="fn__1" class="fn_bot" href="#fnt__1">1)</a></sup>'.NL; 199 echo '<div class="content">'.$this->getLang('p_include').'</div>'; 200 echo '</div></div>'; 201 202 echo '</div>'.NL; 203 } 204 205 /** 206 * returns array with set options for building links 207 * 208 * @author Andreas Gohr <andi@splitbrain.org> 209 */ 210 protected function getLinkOptions($addopts = null) 211 { 212 $opts = array( 213 'do'=>'admin', 214 'page'=>'acl', 215 ); 216 if ($this->ns) $opts['ns'] = $this->ns; 217 if ($this->who) $opts['acl_w'] = $this->who; 218 219 if (is_null($addopts)) return $opts; 220 return array_merge($opts, $addopts); 221 } 222 223 /** 224 * Display a tree menu to select a page or namespace 225 * 226 * @author Andreas Gohr <andi@splitbrain.org> 227 */ 228 protected function makeExplorer() 229 { 230 global $conf; 231 global $ID; 232 global $lang; 233 234 $ns = $this->ns; 235 if (empty($ns)) { 236 $ns = dirname(str_replace(':', '/', $ID)); 237 if ($ns == '.') $ns =''; 238 } elseif ($ns == '*') { 239 $ns =''; 240 } 241 $ns = utf8_encodeFN(str_replace(':', '/', $ns)); 242 243 $data = $this->makeTree($ns); 244 245 // wrap a list with the root level around the other namespaces 246 array_unshift($data, array( 'level' => 0, 'id' => '*', 'type' => 'd', 247 'open' =>'true', 'label' => '['.$lang['mediaroot'].']')); 248 249 echo html_buildlist( 250 $data, 251 'acl', 252 array($this, 'makeTreeItem'), 253 array($this, 'makeListItem') 254 ); 255 } 256 257 /** 258 * get a combined list of media and page files 259 * 260 * also called via AJAX 261 * 262 * @param string $folder an already converted filesystem folder of the current namespace 263 * @param string $limit limit the search to this folder 264 * @return array 265 */ 266 public function makeTree($folder, $limit = '') 267 { 268 global $conf; 269 270 // read tree structure from pages and media 271 $data = array(); 272 search($data, $conf['datadir'], 'search_index', array('ns' => $folder), $limit); 273 $media = array(); 274 search($media, $conf['mediadir'], 'search_index', array('ns' => $folder, 'nofiles' => true), $limit); 275 $data = array_merge($data, $media); 276 unset($media); 277 278 // combine by sorting and removing duplicates 279 usort($data, array($this, 'treeSort')); 280 $count = count($data); 281 if ($count>0) for ($i=1; $i<$count; $i++) { 282 if ($data[$i-1]['id'] == $data[$i]['id'] && $data[$i-1]['type'] == $data[$i]['type']) { 283 unset($data[$i]); 284 $i++; // duplicate found, next $i can't be a duplicate, so skip forward one 285 } 286 } 287 return $data; 288 } 289 290 /** 291 * usort callback 292 * 293 * Sorts the combined trees of media and page files 294 */ 295 public function treeSort($a, $b) 296 { 297 // handle the trivial cases first 298 if ($a['id'] == '') return -1; 299 if ($b['id'] == '') return 1; 300 // split up the id into parts 301 $a_ids = explode(':', $a['id']); 302 $b_ids = explode(':', $b['id']); 303 // now loop through the parts 304 while (count($a_ids) && count($b_ids)) { 305 // compare each level from upper to lower 306 // until a non-equal component is found 307 $cur_result = strcmp(array_shift($a_ids), array_shift($b_ids)); 308 if ($cur_result) { 309 // if one of the components is the last component and is a file 310 // and the other one is either of a deeper level or a directory, 311 // the file has to come after the deeper level or directory 312 if (empty($a_ids) && $a['type'] == 'f' && (count($b_ids) || $b['type'] == 'd')) return 1; 313 if (empty($b_ids) && $b['type'] == 'f' && (count($a_ids) || $a['type'] == 'd')) return -1; 314 return $cur_result; 315 } 316 } 317 // The two ids seem to be equal. One of them might however refer 318 // to a page, one to a namespace, the namespace needs to be first. 319 if (empty($a_ids) && empty($b_ids)) { 320 if ($a['type'] == $b['type']) return 0; 321 if ($a['type'] == 'f') return 1; 322 return -1; 323 } 324 // Now the empty part is either a page in the parent namespace 325 // that obviously needs to be after the namespace 326 // Or it is the namespace that contains the other part and should be 327 // before that other part. 328 if (empty($a_ids)) return ($a['type'] == 'd') ? -1 : 1; 329 if (empty($b_ids)) return ($b['type'] == 'd') ? 1 : -1; 330 return 0; //shouldn't happen 331 } 332 333 /** 334 * Display the current ACL for selected where/who combination with 335 * selectors and modification form 336 * 337 * @author Andreas Gohr <andi@splitbrain.org> 338 */ 339 protected function printDetail() 340 { 341 global $ID; 342 343 echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL; 344 345 echo '<div id="acl__user">'; 346 echo $this->getLang('acl_perms').' '; 347 $inl = $this->makeSelect(); 348 echo '<input type="text" name="acl_w" class="edit" value="'.(($inl)?'':hsc(ltrim($this->who, '@'))).'" />'.NL; 349 echo '<button type="submit">'.$this->getLang('btn_select').'</button>'.NL; 350 echo '</div>'.NL; 351 352 echo '<div id="acl__info">'; 353 $this->printInfo(); 354 echo '</div>'; 355 356 echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL; 357 echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL; 358 echo '<input type="hidden" name="do" value="admin" />'.NL; 359 echo '<input type="hidden" name="page" value="acl" />'.NL; 360 echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'.NL; 361 echo '</div></form>'.NL; 362 } 363 364 /** 365 * Print info and editor 366 * 367 * also loaded via Ajax 368 */ 369 public function printInfo() 370 { 371 global $ID; 372 373 if ($this->who) { 374 $current = $this->getExactPermisson(); 375 376 // explain current permissions 377 $this->printExplanation($current); 378 // load editor 379 $this->printAclEditor($current); 380 } else { 381 echo '<p>'; 382 if ($this->ns) { 383 printf($this->getLang('p_choose_ns'), hsc($this->ns)); 384 } else { 385 printf($this->getLang('p_choose_id'), hsc($ID)); 386 } 387 echo '</p>'; 388 389 echo $this->locale_xhtml('help'); 390 } 391 } 392 393 /** 394 * Display the ACL editor 395 * 396 * @author Andreas Gohr <andi@splitbrain.org> 397 */ 398 protected function printAclEditor($current) 399 { 400 global $lang; 401 402 echo '<fieldset>'; 403 if (is_null($current)) { 404 echo '<legend>'.$this->getLang('acl_new').'</legend>'; 405 } else { 406 echo '<legend>'.$this->getLang('acl_mod').'</legend>'; 407 } 408 409 echo $this->makeCheckboxes($current, empty($this->ns), 'acl'); 410 411 if (is_null($current)) { 412 echo '<button type="submit" name="cmd[save]">'.$lang['btn_save'].'</button>'.NL; 413 } else { 414 echo '<button type="submit" name="cmd[save]">'.$lang['btn_update'].'</button>'.NL; 415 echo '<button type="submit" name="cmd[del]">'.$lang['btn_delete'].'</button>'.NL; 416 } 417 418 echo '</fieldset>'; 419 } 420 421 /** 422 * Explain the currently set permissions in plain english/$lang 423 * 424 * @author Andreas Gohr <andi@splitbrain.org> 425 */ 426 protected function printExplanation($current) 427 { 428 global $ID; 429 global $auth; 430 431 $who = $this->who; 432 $ns = $this->ns; 433 434 // prepare where to check 435 if ($ns) { 436 if ($ns == '*') { 437 $check='*'; 438 } else { 439 $check=$ns.':*'; 440 } 441 } else { 442 $check = $ID; 443 } 444 445 // prepare who to check 446 if ($who{0} == '@') { 447 $user = ''; 448 $groups = array(ltrim($who, '@')); 449 } else { 450 $user = $who; 451 $info = $auth->getUserData($user); 452 if ($info === false) { 453 $groups = array(); 454 } else { 455 $groups = $info['grps']; 456 } 457 } 458 459 // check the permissions 460 $perm = auth_aclcheck($check, $user, $groups); 461 462 // build array of named permissions 463 $names = array(); 464 if ($perm) { 465 if ($ns) { 466 if ($perm >= AUTH_DELETE) $names[] = $this->getLang('acl_perm16'); 467 if ($perm >= AUTH_UPLOAD) $names[] = $this->getLang('acl_perm8'); 468 if ($perm >= AUTH_CREATE) $names[] = $this->getLang('acl_perm4'); 469 } 470 if ($perm >= AUTH_EDIT) $names[] = $this->getLang('acl_perm2'); 471 if ($perm >= AUTH_READ) $names[] = $this->getLang('acl_perm1'); 472 $names = array_reverse($names); 473 } else { 474 $names[] = $this->getLang('acl_perm0'); 475 } 476 477 // print permission explanation 478 echo '<p>'; 479 if ($user) { 480 if ($ns) { 481 printf($this->getLang('p_user_ns'), hsc($who), hsc($ns), join(', ', $names)); 482 } else { 483 printf($this->getLang('p_user_id'), hsc($who), hsc($ID), join(', ', $names)); 484 } 485 } else { 486 if ($ns) { 487 printf($this->getLang('p_group_ns'), hsc(ltrim($who, '@')), hsc($ns), join(', ', $names)); 488 } else { 489 printf($this->getLang('p_group_id'), hsc(ltrim($who, '@')), hsc($ID), join(', ', $names)); 490 } 491 } 492 echo '</p>'; 493 494 // add note if admin 495 if ($perm == AUTH_ADMIN) { 496 echo '<p>'.$this->getLang('p_isadmin').'</p>'; 497 } elseif (is_null($current)) { 498 echo '<p>'.$this->getLang('p_inherited').'</p>'; 499 } 500 } 501 502 503 /** 504 * Item formatter for the tree view 505 * 506 * User function for html_buildlist() 507 * 508 * @author Andreas Gohr <andi@splitbrain.org> 509 */ 510 protected function makeTreeItem($item) 511 { 512 $ret = ''; 513 // what to display 514 if (!empty($item['label'])) { 515 $base = $item['label']; 516 } else { 517 $base = ':'.$item['id']; 518 $base = substr($base, strrpos($base, ':')+1); 519 } 520 521 // highlight? 522 if (($item['type']== $this->current_item['type'] && $item['id'] == $this->current_item['id'])) { 523 $cl = ' cur'; 524 } else { 525 $cl = ''; 526 } 527 528 // namespace or page? 529 if ($item['type']=='d') { 530 if ($item['open']) { 531 $img = DOKU_BASE.'lib/images/minus.gif'; 532 $alt = '−'; 533 } else { 534 $img = DOKU_BASE.'lib/images/plus.gif'; 535 $alt = '+'; 536 } 537 $ret .= '<img src="'.$img.'" alt="'.$alt.'" />'; 538 $ret .= '<a href="'. 539 wl('', $this->getLinkOptions(array('ns'=> $item['id'], 'sectok'=>getSecurityToken()))). 540 '" class="idx_dir'.$cl.'">'; 541 $ret .= $base; 542 $ret .= '</a>'; 543 } else { 544 $ret .= '<a href="'. 545 wl('', $this->getLinkOptions(array('id'=> $item['id'], 'ns'=>'', 'sectok'=>getSecurityToken()))). 546 '" class="wikilink1'.$cl.'">'; 547 $ret .= noNS($item['id']); 548 $ret .= '</a>'; 549 } 550 return $ret; 551 } 552 553 /** 554 * List Item formatter 555 * 556 * @param array $item 557 * @return string 558 */ 559 public function makeListItem($item) 560 { 561 return '<li class="level' . $item['level'] . ' ' . 562 ($item['open'] ? 'open' : 'closed') . '">'; 563 } 564 565 566 /** 567 * Get current ACL settings as multidim array 568 * 569 * @author Andreas Gohr <andi@splitbrain.org> 570 */ 571 public function initAclConfig() 572 { 573 global $AUTH_ACL; 574 global $conf; 575 $acl_config=array(); 576 $usersgroups = array(); 577 578 // get special users and groups 579 $this->specials[] = '@ALL'; 580 $this->specials[] = '@'.$conf['defaultgroup']; 581 if ($conf['manager'] != '!!not set!!') { 582 $this->specials = array_merge( 583 $this->specials, 584 array_map( 585 'trim', 586 explode(',', $conf['manager']) 587 ) 588 ); 589 } 590 $this->specials = array_filter($this->specials); 591 $this->specials = array_unique($this->specials); 592 sort($this->specials); 593 594 foreach ($AUTH_ACL as $line) { 595 $line = trim(preg_replace('/#.*$/', '', $line)); //ignore comments 596 if (!$line) continue; 597 598 $acl = preg_split('/[ \t]+/', $line); 599 //0 is pagename, 1 is user, 2 is acl 600 601 $acl[1] = rawurldecode($acl[1]); 602 $acl_config[$acl[0]][$acl[1]] = $acl[2]; 603 604 // store non-special users and groups for later selection dialog 605 $ug = $acl[1]; 606 if (in_array($ug, $this->specials)) continue; 607 $usersgroups[] = $ug; 608 } 609 610 $usersgroups = array_unique($usersgroups); 611 sort($usersgroups); 612 ksort($acl_config); 613 614 $this->acl = $acl_config; 615 $this->usersgroups = $usersgroups; 616 } 617 618 /** 619 * Display all currently set permissions in a table 620 * 621 * @author Andreas Gohr <andi@splitbrain.org> 622 */ 623 protected function printAclTable() 624 { 625 global $lang; 626 global $ID; 627 628 echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL; 629 if ($this->ns) { 630 echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL; 631 } else { 632 echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL; 633 } 634 echo '<input type="hidden" name="acl_w" value="'.hsc($this->who).'" />'.NL; 635 echo '<input type="hidden" name="do" value="admin" />'.NL; 636 echo '<input type="hidden" name="page" value="acl" />'.NL; 637 echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'.NL; 638 echo '<div class="table">'; 639 echo '<table class="inline">'; 640 echo '<tr>'; 641 echo '<th>'.$this->getLang('where').'</th>'; 642 echo '<th>'.$this->getLang('who').'</th>'; 643 echo '<th>'.$this->getLang('perm').'<sup><a id="fnt__1" class="fn_top" href="#fn__1">1)</a></sup></th>'; 644 echo '<th>'.$lang['btn_delete'].'</th>'; 645 echo '</tr>'; 646 foreach ($this->acl as $where => $set) { 647 foreach ($set as $who => $perm) { 648 echo '<tr>'; 649 echo '<td>'; 650 if (substr($where, -1) == '*') { 651 echo '<span class="aclns">'.hsc($where).'</span>'; 652 $ispage = false; 653 } else { 654 echo '<span class="aclpage">'.hsc($where).'</span>'; 655 $ispage = true; 656 } 657 echo '</td>'; 658 659 echo '<td>'; 660 if ($who{0} == '@') { 661 echo '<span class="aclgroup">'.hsc($who).'</span>'; 662 } else { 663 echo '<span class="acluser">'.hsc($who).'</span>'; 664 } 665 echo '</td>'; 666 667 echo '<td>'; 668 echo $this->makeCheckboxes($perm, $ispage, 'acl['.$where.']['.$who.']'); 669 echo '</td>'; 670 671 echo '<td class="check">'; 672 echo '<input type="checkbox" name="del['.hsc($where).'][]" value="'.hsc($who).'" />'; 673 echo '</td>'; 674 echo '</tr>'; 675 } 676 } 677 678 echo '<tr>'; 679 echo '<th class="action" colspan="4">'; 680 echo '<button type="submit" name="cmd[update]">'.$lang['btn_update'].'</button>'; 681 echo '</th>'; 682 echo '</tr>'; 683 echo '</table>'; 684 echo '</div>'; 685 echo '</div></form>'.NL; 686 } 687 688 /** 689 * Returns the permission which were set for exactly the given user/group 690 * and page/namespace. Returns null if no exact match is available 691 * 692 * @author Andreas Gohr <andi@splitbrain.org> 693 */ 694 protected function getExactPermisson() 695 { 696 global $ID; 697 if ($this->ns) { 698 if ($this->ns == '*') { 699 $check = '*'; 700 } else { 701 $check = $this->ns.':*'; 702 } 703 } else { 704 $check = $ID; 705 } 706 707 if (isset($this->acl[$check][$this->who])) { 708 return $this->acl[$check][$this->who]; 709 } else { 710 return null; 711 } 712 } 713 714 /** 715 * adds new acl-entry to conf/acl.auth.php 716 * 717 * @author Frank Schubert <frank@schokilade.de> 718 */ 719 public function addOrUpdateACL($acl_scope, $acl_user, $acl_level) 720 { 721 global $config_cascade; 722 723 // first make sure we won't end up with 2 lines matching this user and scope. See issue #1115 724 $this->deleteACL($acl_scope, $acl_user); 725 $acl_user = auth_nameencode($acl_user, true); 726 727 // max level for pagenames is edit 728 if (strpos($acl_scope, '*') === false) { 729 if ($acl_level > AUTH_EDIT) $acl_level = AUTH_EDIT; 730 } 731 732 $new_acl = "$acl_scope\t$acl_user\t$acl_level\n"; 733 734 return io_saveFile($config_cascade['acl']['default'], $new_acl, true); 735 } 736 737 /** 738 * remove acl-entry from conf/acl.auth.php 739 * 740 * @author Frank Schubert <frank@schokilade.de> 741 */ 742 public function deleteACL($acl_scope, $acl_user) 743 { 744 global $config_cascade; 745 $acl_user = auth_nameencode($acl_user, true); 746 747 $acl_pattern = '^'.preg_quote($acl_scope, '/').'[ \t]+'.$acl_user.'[ \t]+[0-8].*$'; 748 749 return io_deleteFromFile($config_cascade['acl']['default'], "/$acl_pattern/", true); 750 } 751 752 /** 753 * print the permission radio boxes 754 * 755 * @author Frank Schubert <frank@schokilade.de> 756 * @author Andreas Gohr <andi@splitbrain.org> 757 */ 758 protected function makeCheckboxes($setperm, $ispage, $name) 759 { 760 global $lang; 761 762 static $label = 0; //number labels 763 $ret = ''; 764 765 if ($ispage && $setperm > AUTH_EDIT) $setperm = AUTH_EDIT; 766 767 foreach (array(AUTH_NONE,AUTH_READ,AUTH_EDIT,AUTH_CREATE,AUTH_UPLOAD,AUTH_DELETE) as $perm) { 768 $label += 1; 769 770 //general checkbox attributes 771 $atts = array( 'type' => 'radio', 772 'id' => 'pbox'.$label, 773 'name' => $name, 774 'value' => $perm ); 775 //dynamic attributes 776 if (!is_null($setperm) && $setperm == $perm) $atts['checked'] = 'checked'; 777 if ($ispage && $perm > AUTH_EDIT) { 778 $atts['disabled'] = 'disabled'; 779 $class = ' class="disabled"'; 780 } else { 781 $class = ''; 782 } 783 784 //build code 785 $ret .= '<label for="pbox'.$label.'"'.$class.'>'; 786 $ret .= '<input '.buildAttributes($atts).' /> '; 787 $ret .= $this->getLang('acl_perm'.$perm); 788 $ret .= '</label>'.NL; 789 } 790 return $ret; 791 } 792 793 /** 794 * Print a user/group selector (reusing already used users and groups) 795 * 796 * @author Andreas Gohr <andi@splitbrain.org> 797 */ 798 protected function makeSelect() 799 { 800 $inlist = false; 801 $usel = ''; 802 $gsel = ''; 803 804 if ($this->who && 805 !in_array($this->who, $this->usersgroups) && 806 !in_array($this->who, $this->specials)) { 807 if ($this->who{0} == '@') { 808 $gsel = ' selected="selected"'; 809 } else { 810 $usel = ' selected="selected"'; 811 } 812 } else { 813 $inlist = true; 814 } 815 816 echo '<select name="acl_t" class="edit">'.NL; 817 echo ' <option value="__g__" class="aclgroup"'.$gsel.'>'.$this->getLang('acl_group').'</option>'.NL; 818 echo ' <option value="__u__" class="acluser"'.$usel.'>'.$this->getLang('acl_user').'</option>'.NL; 819 if (!empty($this->specials)) { 820 echo ' <optgroup label=" ">'.NL; 821 foreach ($this->specials as $ug) { 822 if ($ug == $this->who) { 823 $sel = ' selected="selected"'; 824 $inlist = true; 825 } else { 826 $sel = ''; 827 } 828 829 if ($ug{0} == '@') { 830 echo ' <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL; 831 } else { 832 echo ' <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL; 833 } 834 } 835 echo ' </optgroup>'.NL; 836 } 837 if (!empty($this->usersgroups)) { 838 echo ' <optgroup label=" ">'.NL; 839 foreach ($this->usersgroups as $ug) { 840 if ($ug == $this->who) { 841 $sel = ' selected="selected"'; 842 $inlist = true; 843 } else { 844 $sel = ''; 845 } 846 847 if ($ug{0} == '@') { 848 echo ' <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL; 849 } else { 850 echo ' <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL; 851 } 852 } 853 echo ' </optgroup>'.NL; 854 } 855 echo '</select>'.NL; 856 return $inlist; 857 } 858} 859