1<?php 2/** 3 * Classes and functions for the template engine. 4 * 5 * @author The phpLDAPadmin development team 6 * @package phpLDAPadmin 7 */ 8 9/** 10 * Represents an attribute of a template. 11 * 12 * @package phpLDAPadmin 13 * @subpackage Templates 14 */ 15class Attribute { 16 # Attribute Name 17 public $name; 18 # Source of this attribute definition 19 protected $source; 20 21 # Current and Old Values 22 protected $oldvalues = array(); 23 protected $values = array(); 24 25 # MIN/MAX number of values 26 protected $min_value_count = -1; 27 protected $max_value_count = -1; 28 29 # Is the attribute internal 30 protected $internal = false; 31 # Has the attribute been modified 32 protected $modified = false; 33 # Is the attribute being deleted because of an object class removal 34 protected $forcedelete = false; 35 # Is the attribute visible 36 protected $visible = false; 37 protected $forcehide = false; 38 # Is the attribute modifiable 39 protected $readonly = false; 40 # LDAP attribute type MUST/MAY 41 protected $ldaptype = null; 42 # Attribute property type (eg password, select, multiselect) 43 protected $type = ''; 44 # Attribute value to keep unique 45 protected $unique = false; 46 47 # Display parameters 48 protected $display = ''; 49 protected $icon = ''; 50 protected $hint = ''; 51 # Helper details 52 protected $helper = array(); 53 protected $helpervalue = array(); 54 # Onchange details 55 protected $onchange = array(); 56 # Show spacer after this attribute is rendered 57 protected $spacer = false; 58 protected $verify = false; 59 60 # Component size 61 protected $size = 0; 62 # Value max length 63 protected $maxlength = 0; 64 # Text Area sizings 65 protected $cols = 0; 66 protected $rows = 0; 67 68 # Public for sorting 69 public $page = 1; 70 public $order = 255; 71 public $ordersort = 255; 72 public $rdn = false; 73 74 # Schema Aliases for this attribute (stored in lowercase) 75 protected $aliases = array(); 76 77 # Configuration for automatically generated values 78 protected $autovalue = array(); 79 protected $postvalue = array(); 80 81 public function __construct($name,$values,$server_id,$source=null) { 82 $server = $_SESSION[APPCONFIG]->getServer($server_id); 83 84 $sattr = $server->getSchemaAttribute($name); 85 if ($sattr) { 86 $this->name = $sattr->getName(false); 87 $this->setLDAPdetails($sattr); 88 89 } else 90 $this->name = $name; 91 92 $this->source = $source; 93 94 # XML attributes are shown by default 95 switch ($source) { 96 case 'XML': $this->show(); 97 $this->setXML($values); 98 99 break; 100 101 default: 102 if (! isset($values['values'])) 103 debug_dump_backtrace('no index "values"',1); 104 105 $this->initValue($values['values']); 106 } 107 108 # Should this attribute be hidden 109 if ($server->isAttrHidden($this->name)) 110 $this->forcehide = true; 111 112 # Should this attribute value be read only 113 if ($server->isAttrReadOnly($this->name)) 114 $this->readonly = true; 115 116 # Should this attribute value be unique 117 if ($server->isAttrUnique($this->name)) 118 $this->unique = true; 119 } 120 121 /** 122 * Return the name of the attribute. 123 * 124 * @param boolean $lower - Return the attribute in normal or lower case (default lower) 125 * @param boolean $real - Return the real attribute name (with ;binary, or just the name) 126 * @return string Attribute name 127 */ 128 public function getName($lower=true,$real=false) { 129 if ($real) 130 return $lower ? strtolower($this->name) : $this->name; 131 else 132 return $lower ? strtolower($this->real_attr_name()) : $this->real_attr_name(); 133 } 134 135 public function getValues() { 136 return $this->values; 137 } 138 139 public function getOldValues() { 140 return $this->oldvalues; 141 } 142 143 public function getValueCount() { 144 return count($this->values); 145 } 146 147 public function getSource() { 148 return $this->source; 149 } 150 151 /** 152 * Autovalue is called after the attribute is initialised, and thus the values from the ldap server will be set. 153 */ 154 public function autoValue($new_val) { 155 if ($this->values) 156 return; 157 158 $this->values = $new_val; 159 } 160 161 public function initValue($new_val) { 162 if ($this->values || $this->oldvalues) { 163 debug_dump(array('new_val'=>$new_val,'this'=>$this)); 164 debug_dump_backtrace('new and/or old values are set',1); 165 } 166 167 $this->values = $new_val; 168 } 169 170 public function clearValue() { 171 $this->values = array(); 172 } 173 174 public function setOldValue($val) { 175 $this->oldvalues = $val; 176 } 177 178 public function setValue($new_val) { 179 if ($this->values) { 180 if ($this->values == $new_val) 181 return; 182 183 if ($this->oldvalues) { 184 debug_dump($this); 185 debug_dump_backtrace('old values are set',1); 186 } else 187 $this->oldvalues = $this->values; 188 } 189 190 if ($new_val == $this->values) 191 return; 192 193 $this->values = $new_val; 194 $this->justModified(); 195 } 196 197 public function addValue($new_val,$i=-1) { 198 if ($i < 0) 199 $i = $this->getValueCount(); 200 201 $old_val = $this->getValue($i); 202 if (is_null($old_val) || ($old_val != $new_val)) 203 $this->justModified(); 204 205 $this->values[$i] = $new_val; 206 } 207 208 public function delValue($i=-1) { 209 if ($i < 0) 210 $this->setValue(array()); 211 212 if (! $this->hasBeenModified()) 213 $this->oldvalues = $this->values; 214 215 if (isset($this->values[$i])) { 216 unset($this->values[$i]); 217 $this->values = array_values($this->values); 218 $this->justModified(); 219 } 220 } 221 222 public function getValue($i) { 223 if (isset($this->values[$i])) 224 return $this->values[$i]; 225 else 226 return null; 227 } 228 229 public function getOldValue($i) { 230 if (isset($this->oldvalues[$i])) 231 return $this->oldvalues[$i]; 232 else 233 return null; 234 } 235 236 public function getMinValueCount() { 237 return $this->min_value_count; 238 } 239 240 public function setMinValueCount($min) { 241 $this->min_value_count = $min; 242 } 243 244 public function getMaxValueCount() { 245 return $this->max_value_count; 246 } 247 248 public function setMaxValueCount($max) { 249 $this->max_value_count = $max; 250 } 251 252 public function haveMoreValues() { 253 if ($this->getMaxValueCount() < 0 || ($this->getValueCount() < $this->getMaxValueCount())) 254 return true; 255 else 256 return false; 257 } 258 259 public function justModified() { 260 $this->modified = true; 261 } 262 263 public function hasBeenModified() { 264 return $this->modified; 265 } 266 267 public function isForceDelete() { 268 return $this->forcedelete; 269 } 270 271 public function setForceDelete() { 272 $this->forcedelete = true; 273 $this->oldvalues = $this->values; 274 $this->values = array(); 275 $this->justModified(); 276 } 277 278 public function isInternal() { 279 return $this->internal; 280 } 281 282 public function setInternal() { 283 $this->internal = true; 284 } 285 286 public function isRequired() { 287 if ($this->getMinValueCount() > 0) 288 return true; 289 elseif ($this->ldaptype == 'must') 290 return true; 291 elseif ($this->isRDN()) 292 return true; 293 else 294 return false; 295 } 296 297 public function isMay() { 298 if (($this->ldaptype == 'may') && ! $this->isRequired()) 299 return true; 300 else 301 return false; 302 } 303 304 public function setType($type) { 305 $this->type = strtolower($type); 306 } 307 308 public function getType() { 309 return $this->type; 310 } 311 312 public function setLDAPtype($type) { 313 $this->ldaptype = strtolower($type); 314 } 315 316 public function getLDAPtype() { 317 return $this->ldaptype; 318 } 319 320 public function setProperties($properties) { 321 foreach ($properties as $index => $value) { 322 if ($index == 'maxvalnb') { 323 $this->setMaxValueCount($value); 324 continue; 325 326 } elseif ($index == 'minvalnb') { 327 $this->setMinValueCount($value); 328 continue; 329 330 } elseif ($index == 'maxlength') { 331 $this->setMinValueCount($value); 332 continue; 333 334 } elseif ($index == 'hidden') { 335 $this->visible = $value; 336 continue; 337 338 } elseif (in_array($index,array('cols','rows'))) { 339 # @todo To be implemented 340 continue; 341 } 342 343 if (isset($this->$index)) 344 $this->$index = $value; 345 else { 346 debug_dump($this); 347 debug_dump_backtrace(sprintf('Unknown property (%s) with value (%s) for (%s)',$index,$value,$this->getName()),1); 348 } 349 } 350 } 351 352 public function setRequired() { 353 if ($this->getMinValueCount() <= 0) 354 $this->setMinValueCount(1); 355 } 356 357 public function setOptional() { 358 $this->setMinValueCount(0); 359 } 360 361 public function isReadOnly() { 362 return $this->readonly; 363 } 364 365 public function setReadOnly() { 366 $this->readonly = true; 367 } 368 369 public function isMultiple() { 370 return false; 371 } 372 373 public function isVisible() { 374 return $this->visible && (! $this->forcehide); 375 } 376 377 public function hide() { 378 $this->visible = false; 379 } 380 381 public function show() { 382 $this->visible = true; 383 } 384 385 public function haveFriendlyName() { 386 return $_SESSION[APPCONFIG]->haveFriendlyName($this); 387 } 388 389 public function getFriendlyName() { 390 if ($this->display) 391 return $this->display; 392 else 393 return $_SESSION[APPCONFIG]->getFriendlyName($this); 394 } 395 396 public function setDescription($description) { 397 $this->description = $description; 398 } 399 400 public function getDescription() { 401 return $this->description; 402 } 403 404 public function setIcon($icon) { 405 $this->icon = $icon; 406 } 407 408 public function getIcon() { 409 return $this->icon ? sprintf('%s/%s',IMGDIR,$this->icon) : ''; 410 } 411 412 public function getHint() { 413 return $this->hint; 414 } 415 416 public function setHint($hint) { 417 $this->hint = $hint; 418 } 419 420 public function getMaxLength() { 421 return $this->maxlength; 422 } 423 424 public function setMaxLength($maxlength) { 425 $this->maxlength = $maxlength; 426 } 427 428 public function getSize() { 429 return $this->size; 430 } 431 432 public function setSize($size) { 433 $this->size = $size; 434 } 435 436 public function getSpacer() { 437 return $this->spacer; 438 } 439 440 public function getPage() { 441 return $this->page; 442 } 443 public function setPage($page) { 444 $this->page = $page; 445 } 446 447 public function getOnChange() { 448 return $this->onchange; 449 } 450 451 public function getHelper() { 452 return $this->helper; 453 } 454 455 public function getHelperValue() { 456 return $this->helpervalue; 457 } 458 459 public function getVerify() { 460 return $this->verify; 461 } 462 463 public function setRDN($rdn) { 464 $this->rdn = $rdn; 465 } 466 467 /** 468 * Return if this attribute is an RDN attribute 469 * 470 * @return boolean 471 */ 472 public function isRDN() { 473 return $this->rdn; 474 } 475 476 /** 477 * Capture all the LDAP details we are interested in 478 * 479 * @param sattr Schema Attribute 480 */ 481 private function setLDAPdetails($sattr) { 482 # By default, set this as a MAY attribute, later processing should make it a MUST attribute if it is. 483 if (! $this->ldaptype) 484 $this->ldaptype = 'may'; 485 486 # Store our Aliases 487 foreach ($sattr->getAliases() as $alias) 488 array_push($this->aliases,strtolower($alias)); 489 490 if ($sattr->getIsSingleValue()) 491 $this->setMaxValueCount(1); 492 } 493 494 /** 495 * Return a list of aliases for this Attribute (as defined by the schema) 496 * This list will be lowercase. 497 */ 498 public function getAliases() { 499 return $this->aliases; 500 } 501 502 public function getAutoValue() { 503 return $this->autovalue; 504 } 505 506 public function getPostValue() { 507 return $this->postvalue; 508 } 509 510 public function setPostValue($postvalue) { 511 $this->postvalue = $postvalue; 512 } 513 514 public function setXML($values) { 515 # Mostly all the time, this should be an array 516 if (is_array($values)) 517 foreach ($values as $index => $value) 518 switch ($index) { 519 # Helpers should be accompanied with a <post> attribute. 520 case 'helper': 521 if (! isset($values['post']) && ! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning')) 522 system_message(array( 523 'title'=>sprintf('%s [<i>%s</i>]',('Missing [post] setting in XML file'),$index), 524 'body'=>('[helper] needs an accompanying [post] action.'), 525 'type'=>'warn')); 526 527 if (isset($value['value']) && ! is_array($value['value']) && preg_match('/^=php\.(\w+)\((.*)\)$/',$value['value'],$matches)) { 528 $this->helpervalue['function'] = $matches[1]; 529 $this->helpervalue['args'] = $matches[2]; 530 531 unset ($value['value']); 532 } 533 534 foreach ($value as $i => $detail) { 535 if (! in_array($i,array('default','display','id','value'))) { 536 if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning')) 537 system_message(array( 538 'title'=>sprintf('%s [<i>%s</i>]',('Unknown XML setting'),$i), 539 'body'=>sprintf('%s <small>[%s]</small>',('Unknown XML type setting for helper will be ignored.'),$detail), 540 'type'=>'warn')); 541 542 unset($value[$i]); 543 } 544 } 545 546 $this->$index = $value; 547 548 break; 549 550 case 'hidden': $value ? $this->visible = false : $this->visible = true; 551 break; 552 553 case 'spacer': $value ? $this->$index = true : $this->$index = false; 554 break; 555 556 # Essentially, we ignore type, it is used to select an Attribute type in the Factory. But we'll generated a warning if there is an unknown type. 557 case 'type': 558 if (! in_array($value,array('password','multiselect','select','textarea')) && ! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning')) 559 system_message(array( 560 'title'=>sprintf('%s [<i>%s</i>]',('Unknown XML setting'),$index), 561 'body'=>sprintf('%s <small>[%s]</small>',('Unknown XML type setting will be ignored.'),$value), 562 'type'=>'warn')); 563 564 break; 565 566 case 'post': 567 if (preg_match('/^=php\.(\w+)\((.*)\)$/',$value,$matches)) { 568 $this->postvalue['function'] = $matches[1]; 569 $this->postvalue['args'] = $matches[2]; 570 571 } else 572 if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning')) 573 system_message(array( 574 'title'=>sprintf('%s [<i>%s</i>]',('Unknown XML setting'),$index), 575 'body'=>sprintf('%s <small>[%s]</small>',('Unknown XML type setting will be ignored.'),$value), 576 'type'=>'warn')); 577 578 case 'value': 579 if (is_array($value)) 580 foreach ($value as $y) { 581 if (! $this->haveMoreValues()) { 582 system_message(array( 583 'title'=>('Automatically removed attribute values from template'), 584 'body'=>sprintf('%s <small>[%s]</small>',('Template defines more values than can be accepted by attribute.'),$this->getName(true)), 585 'type'=>'warn')); 586 587 $this->clearValue(); 588 589 break; 590 591 } else 592 $this->addValue($y); 593 } 594 595 else 596 # Check to see if the value is auto generated. 597 if (preg_match('/^=php\.(\w+)\((.*)\)$/',$value,$matches)) { 598 $this->autovalue['function'] = $matches[1]; 599 $this->autovalue['args'] = $matches[2]; 600 601 # We'll add a hint too 602 if (! $this->hint) 603 $this->hint = ('Automatically determined'); 604 605 } else 606 $this->addValue($value); 607 608 break; 609 610 # Queries 611 case 'ordersort': 612 613 # Creation/Editing Templates 614 case 'cols': 615 case 'default': 616 case 'display': 617 case 'hint': 618 case 'icon': 619 case 'maxlength': 620 case 'onchange': 621 case 'order': 622 case 'page': 623 case 'readonly': 624 case 'rows': 625 case 'size': 626 case 'values': 627 case 'verify': $this->$index = $value; 628 break; 629 630 case 'max': 631 if ($this->getMaxValueCount() == -1) 632 $this->setMaxValueCount($value); 633 634 default: 635 if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning')) 636 system_message(array( 637 'title'=>sprintf('%s [<i>%s</i>]',('Unknown XML setting'),$index), 638 'body'=>sprintf('%s <small>[%s]</small>',('Unknown attribute setting will be ignored.'),serialize($value)), 639 'type'=>'warn')); 640 } 641 642 elseif (is_string($values) && (strlen($values) > 0)) 643 $this->values = array($values); 644 } 645 646 /** 647 * Display the values removed in an attribute. 648 */ 649 public function getRemovedValues() { 650 return array_diff($this->getOldValues(),$this->getValues()); 651 } 652 653 /** 654 * Display the values removed in an attribute. 655 */ 656 public function getAddedValues() { 657 return array_diff($this->getValues(),$this->getOldValues()); 658 } 659 660 /** 661 * Prunes off anything after the ";" in an attr name. This is useful for 662 * attributes that may have ";binary" appended to their names. With 663 * real_attr_name(), you can more easily fetch these attributes' schema 664 * with their "real" attribute name. 665 * 666 * @param string $attr_name The name of the attribute to examine. 667 * @return string 668 */ 669 private function real_attr_name() { 670 return preg_replace('/;.*$/U','',$this->name); 671 } 672 673 /** 674 * Does this attribute need supporting JS 675 */ 676 public function needJS($type=null) { 677 if (is_null($type)) { 678 foreach (array('focus','blur','validate') as $type) 679 if ($this->needJS($type)) 680 return true; 681 682 return false; 683 684 } elseif ($type == 'focus') { 685 # We dont have any focus javascript routines. 686 return false; 687 688 } elseif ($type == 'blur') { 689 if ($this->onchange || $this->isRequired()) 690 return true; 691 else 692 return false; 693 694 } elseif ($type == 'validate') { 695 if ($this->isRequired()) 696 return true; 697 else 698 return false; 699 700 } else 701 debug_dump_backtrace(sprintf('Unknown JS request %s',$type),1); 702 } 703} 704?> 705