1<?php 2 3/** 4 * Addressbook Plugin 5 * 6 * @license GPL2 7 * @author Gero Gothe <gero.gothe@medizindoku.de> 8 * 9 */ 10 11// must be run within Dokuwiki 12if(!defined('DOKU_INC')) die(); 13 14define('ADRESSBOOK_SQL',false); # for development purposes 15 16class syntax_plugin_addressbook extends DokuWiki_Syntax_Plugin { 17 18 public $editor = false; # Does user have editing rights for contacts? 19 public $loggedin = false; # User logged in? 20 21 function getSort(){ 22 return 158; 23 } 24 25 public function getType() { 26 return 'substition'; 27 } 28 29 /** 30 * Paragraph Type 31 */ 32 public function getPType() { 33 return 'block'; 34 } 35 36 37 function __construct(){ 38 global $INFO; 39 if ($INFO['ismanager'] === true) $this->editor = true; 40 if (isset($INFO['userinfo'])) $this->loggedin = true; 41 } 42 43 /** 44 * @param string $mode 45 */ 46 public function connectTo($mode) {$this->Lexer->addEntryPattern('\[ADDRESSBOOK.*?', $mode, 'plugin_addressbook');} 47 48 public function postConnect() { $this->Lexer->addExitPattern('\]','plugin_addressbook'); } 49 50 /** 51 * Handler to prepare matched data for the rendering process 52 */ 53 public function handle($match, $state, $pos, Doku_Handler $handler) { 54 55 if ($state == DOKU_LEXER_UNMATCHED) { 56 if ($match==':') return 'LOOKUP'; 57 if ($match[0]==':') $match = substr($match,1); 58 59 return trim($match); 60 } 61 return false; 62 } 63 64 65 /** 66 * @param $mode string output format being rendered 67 * @param $renderer Doku_Renderer the current renderer object 68 * @param $data array data created by handler() 69 * @return boolean rendered correctly? 70 */ 71 public function render($mode, Doku_Renderer $renderer, $data) { 72 global $ID; 73 74 if($mode == 'xhtml') { 75 $renderer->info['cache'] = false; 76 77 # addressbook_debug_show(); 78 79 if ($_REQUEST['Submit'] == $this->getLang('exec cancel')){ 80 unset($_REQUEST); 81 unset ($cinfo); 82 $action = $data; 83 } 84 85 # Main action given by tag data 86 if (!isset($_REQUEST['Submit'])) $action = $data; 87 88 89 /* Save a contact 90 * 91 * On fail: show edit form again 92 */ 93 if ($_REQUEST['Submit']==$this->getLang('exec save')) $action = "savedata"; 94 95 # Certain actions could cause double saving, which is avoided by counting 96 if ($action=='savedata' && $this->saveOnce == 0 && $this->editor){ 97 $this->saveOnce++; 98 $contact_id = $_REQUEST['editcontact']; 99 $cinfo = $this->loadFormData(); # Loads form data concerning the contact 100 $res = $this->saveData($cinfo); 101 if (!$res) { 102 $action = 'edit'; 103 $contact_id = $_REQUEST['contactid']; 104 } else { # Clear all 105 unset($_REQUEST); 106 unset ($cinfo); 107 $action = $data; 108 } 109 } 110 111 112 /* Directly show contact card by tag 113 * 114 * Cards are only display, when there is NO edit or save action 115 */ 116 if (substr($data,0,7) == 'contact' && 117 !isset($_REQUEST['editcontact']) && 118 $action != 'edit' 119 ) { 120 $renderer->doc .= $this->showcontact(intval(substr($data,8)),$ID); 121 return; #no following actions 122 } 123 124 125 if (substr($data,0,5) == 'index' && 126 !isset($_REQUEST['editcontact'])) { 127 # showcontact once before if necessary 128 if (isset($_REQUEST['showcontact']) && $this->showCount==0) { 129 $this->showCount++; 130 $out = $this->showcontact($_REQUEST['showcontact'],$ID); 131 if ($out !== false) $renderer->doc .= $out.'<br>'; 132 } 133 # now show index 134 135 # keyword 'departments' 136 if (strpos($data,'departments') > 0) { 137 $list = $this->getList(false,'department,surname,firstname,cfunction'); 138 $renderer->doc .= $this->buildIndex($list,'department',$ID); 139 } else $renderer->doc .= $this->buildIndex(false,false,$ID); 140 141 return; # no following actions 142 } 143 144 145 # --------------------------------------------------------# 146 # only one instance beyond this point 147 $this->instance++; 148 if ($this->instance > 1) return; 149 # --------------------------------------------------------# 150 151 152 # Generate printable list 153 if (substr($data,0,5) == 'print') { 154 155 $pList = false; 156 $sep = false; 157 158 $params = $this->getValue($data,''); 159 160 if (isset($params['department'])) $sep = 'department'; 161 162 # Select one department 163 if (isset($params['select'])) { 164 $pList = $this->getList(Array('department' => $params['select'])); 165 $sep = false; 166 } 167 168 $renderer->doc .= $this->buildPrintList($pList,$sep); 169 170 return; 171 } 172 173 174 /* Edit contact or add a new contact 175 * 176 * No futher actions are performed after an edit 177 */ 178 if ($action == 'addcontact' && $this->editor) { # Add a new contact. Can be overwritten by edit 179 $contact_id = 'new'; 180 $action = 'edit'; # redefine action 181 } 182 183 if (isset($_REQUEST['editcontact']) && $this->editor) { # Override new contact if the action is to edit an existing one 184 $contact_id = $_REQUEST['editcontact']; 185 $cinfo = $this->getContactData($contact_id); 186 $action = 'edit'; 187 } 188 189 if ($action == 'edit' && $this->editor) { 190 $out = $this->buildForm($contact_id,$cinfo); 191 $renderer->doc .= $out; 192 return; # no following actions 193 } 194 195 196 # Show search box 197 if ($action == 'search' || $_REQUEST['Submit'] == $this->getLang('exec search')) { 198 $out = $this->searchDialog(); 199 $renderer->doc .= $out; 200 } 201 202 203 if ($_REQUEST['Submit'] == $this->getLang('exec search')) { 204 $list = $this->searchDB($_REQUEST['searchtext']); 205 if ($list != false){ 206 if (count($list)<5) { 207 foreach ($list as $l) $renderer->doc .= $this->showcontact($l['id'],$ID); 208 } else $renderer->doc .= $this->buildIndex($list,false,$ID); 209 } 210 } 211 212 213 /* Show contact per request 214 * can only be shown once due to the instance count above 215 * 216 * placed below the searchbox 217 */ 218 if (isset($_REQUEST['showcontact']) && $this->showCount==0) { 219 $this->showCount++; 220 $out = $this->showcontact($_REQUEST['showcontact'],$ID); 221 if ($out !== false) $renderer->doc .= $out.'<br>'; 222 } 223 224 225 # Delete a contact 226 if (isset($_REQUEST['erasecontact']) && $this->editor){ 227 $this->deleteContact($_REQUEST['erasecontact']); 228 } 229 230 return true; 231 } 232 233 return false; 234 } 235 236 237 function searchDialog(){ 238 global $ID; 239 $out = ''; 240 241 $out .= '<div class="plugin_addressbook_searchbox">'; 242 243 $out .= '<form enctype="multipart/form-data" action="'.wl($ID).'" method="POST">'; 244 $out .= '<span>'.$this->getLang('addressbook').'</span> <input type="text" name="searchtext" placeholder="'.$this->getLang('form search').'" value="'.$_REQUEST['searchtext'].'">'; 245 $out .= '<input type="submit" name="Submit" value="'.$this->getLang('exec search').'" />'; 246 247 $out .= '</form>'; 248 $out .= '</div>'; 249 250 return $out; 251 } 252 253 254 function buildForm($contact_id,$cinfo){ 255 global $ID; 256 $out = '<div class="plugin_addressbook_editform">'; 257 258 if ($contact_id == 'new') {$out .= '<h2>'.$this->getLang('header add').'</h2>';} else {$out .= '<h2>'.$this->getLang('header edit').'</h2>';} 259 260 $out .= '<br><form enctype="multipart/form-data" action="'.wl($ID).'" method="POST">'; 261 $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="2200000" />'; 262 $out .= '<input type="hidden" name="contactid" value="'.$contact_id.'" />'; 263 $out .= '<input type="text" name="firstname" placeholder="'.$this->getLang('form firstname').'" value="'.$cinfo['firstname'].'">'; 264 $out .= '<input type="text" name="surname" placeholder="'.$this->getLang('form surname').'" value="'.$cinfo['surname'].'"><br>'; 265 $out .= '<input type="text" name="cfunction" placeholder="'.$this->getLang('form function').'" value="'.$cinfo['cfunction'].'">'; 266 $out .= '<input type="text" name="department" placeholder="'.$this->getLang('form department').'" value="'.$cinfo['department'].'"><br>'; 267 $out .= '<input type="text" name="tel1" placeholder="'.$this->getLang('form tel1').'" value="'.$cinfo['tel1'].'">'; 268 $out .= '<input type="text" name="tel2" placeholder="'.$this->getLang('form tel2').'" value="'.$cinfo['tel2'].'"><br>'; 269 $out .= '<input type="text" name="fax" placeholder="'.$this->getLang('form fax').'" value="'.$cinfo['fax'].'"><br>'; 270 $out .= '<input type="text" name="email" placeholder="'.$this->getLang('form email').'" value="'.$cinfo['email'].'"><br>'; 271 $out .= '<br>'.$this->getLang('form description').':<br><textarea name="description">'.$cinfo['description'].'</textarea><br><br>'; 272 273 $out .= '<div class="photoupload">'; 274 if (isset($_REQUEST['blob'])) $cinfo['photo'] = $_REQUEST['blob']; 275 if ($cinfo['photo'] != false) { 276 $out .= "<img style='float:left;max-width:120px' src='data:image/jpg;base64,".($cinfo['photo'])."'>"; 277 $out .= '<br><input type="checkbox" id="removephoto" name="removephoto" value="Remove photo"> '; 278 $out .= '<label for="removephoto">'.$this->getLang('form remove').'</label><br><br>'; 279 $out .= $this->getLang('form upload info2').'.<br>'; 280 $out .= '<input type="hidden" name="blob" value="'.($cinfo['photo']).'">'; 281 } 282 283 $out .= '</div>'; 284 $out .= $this->getLang('form upload').': <input name="photo" type="file" /> '.$this->getLang('form upload info').'.<br>'; 285 286 287 288 $out .= '<br><input type="submit" name="Submit" value="'.$this->getLang('exec save').'" />'; 289 $out .= '<input type="submit" name="Submit" value="'.$this->getLang('exec cancel').'" />'; 290 $out .= '</form>'; 291 $out .= "<div class='id'>ID: $contact_id</div>"; 292 $out .= '</div>'; 293 294 return $out; 295 } 296 297 function showcontact($cid,$target = false){ 298 299 $r = $this->getContactData($cid); 300 301 if ($res === false) return false; 302 303 $out =''; 304 305 $out .= '<div class="plugin_addressbook_singlecontact">'; 306 307 $out .= '<div class="content">'; 308 309 $out .= '<div class="data">'; 310 311 # Name if existant 312 $out .= '<b>'.$r['surname'] .($r['firstname'] <> ''? ', '.$r['firstname']:'').'</b>'; 313 if (strlen($r['surname'] .$r['firstname'])>0) $out .= '<br>'; 314 315 # Function/department if existant 316 if ($r['surname'].$r['firstname'] == '') $out .= '<b>'; 317 318 if ($r['department'].$r['cfunction'] != '') $out .= $this->names(array($r['cfunction'],$r['department'])); 319 320 if (strlen($r['cfuntion'] .$r['department'])>0) $out .= '<br>'; 321 if ($r['surname'].$r['firstname'] == '') $out .= '</b>'; 322 323 # Telephone 324 if ($r['tel1'].$r['tel2'] <> '') $out .= '<br>Tel.: '.$this->names(array($r['tel1'],$r['tel2']),' / '); 325 326 # Fax 327 if ($r['fax']<>'') $out .= '<br>Fax: '.$r['fax']; 328 329 # Mail 330 if ($r['email']<>'') $out .= '<br>Mail: <a href="mailto:'.$r['email'].'">'.$r['email'].'</a>'; 331 332 $out .= '</div>'; 333 334 if ($r['photo'] != false) $out .= "<img class='photo' src='data:image/jpg;base64,".($r['photo'])."'>"; 335 336 $out .= '</div>'; 337 338 if ($r['description']<>'') $out .= $r['description']; 339 340 if ($this->loggedin) { 341 $out .= '<div class="footer">'; 342 343 $out .= 'Nr. '.$r['id']; 344 345 if ($this->editor && $target != false) { 346 $out .= '<span class="buttons">'; 347 $out .= '<a href="'.wl($target,'editcontact='.$r['id']).'">'.$this->getLang('exec edit').'</a>'; 348 $out .= '<a href="'.wl($target,'erasecontact='.$r['id']).'" onclick="return confirm(\'Sure?\');">'.$this->getLang('exec delete').'</a>'; 349 $out .= '</span>'; 350 } 351 352 $out .= '</div>'; 353 } 354 355 $out .= '</div>'; 356 357 return $out; 358 } 359 360 361 /* Get single contact data per id 362 * 363 * @param id: id in the database (unique) 364 * 365 * @return: 366 * - false if id is not found 367 * - array containing all data of the contact 368 */ 369 function getContactData($cid){ 370 try { 371 $db_helper = plugin_load('helper', 'addressbook_db'); 372 $sqlite = $db_helper->getDB(); 373 } catch (Exception $e) { 374 msg($e->getMessage(), -1); 375 return false; 376 } 377 378 $sql = "SELECT * FROM addresslist WHERE id = $cid"; 379 $query = $sqlite->query($sql); 380 381 if (ADRESSBOOK_SQL) msg("<code>$sql</code>",2); 382 383 if ($sqlite->res2count($query) ==0){ 384 msg ("Contact not found (id: $cid)",-1); 385 return false; 386 } 387 388 $res = $sqlite->res2arr($query)[0]; 389 390 return $res; 391 } 392 393 394 /* 395 * @return: Array - Contact data in the sequence they should be displayed 396 * ! result does not contain the photo and the id 397 */ 398 function getKeys(){ 399 return Array('firstname','surname','cfunction','department','tel1','tel2','fax','email','description'); 400 } 401 402 403 /* Loads the data from the $_REQUEST-Variables into an array 404 * the image is loaded as a blob 405 * 406 * @return array 407 */ 408 function loadFormData(){ 409 $res = Array(); 410 411 $keys = $this->getKeys();#Array('firstname','surname','cfunction','description'); 412 413 foreach ($keys as $k) $res[$k] = $_REQUEST[$k]; 414 415 # Validate and load photo data 416 if (isset($_FILES) && $_FILES['photo']['error'] == UPLOAD_ERR_OK && $_FILES['photo']['tmp_name']!='') { 417 if (filesize($_FILES['photo']['tmp_name']) > (2*1024*1024)) { 418 msg('Uploaded photo exceeds 2 MB. Not processed',-1); 419 $res['photo'] = false; 420 } elseif (exif_imagetype($_FILES['photo']['tmp_name']) != IMAGETYPE_JPEG){ 421 msg('Image ist not *.jpg file. Not processed.',-1); 422 $res['photo'] = false; 423 } else { 424 $pic = $this->scaleJPG($_FILES['photo']['tmp_name']); 425 $res['photo'] = base64_encode($pic); 426 unset($pic); 427 } 428 } else { 429 $res['photo'] = false; 430 if ($_FILES['photo']['error'] != UPLOAD_ERR_OK && $_FILES['photo']['tmp_name']!='' ) msg('Image could not be uploaded. Error code: '.$_FILES['photo']['error'],-1); 431 } 432 433 return $res; 434 } 435 436 /* SaveData-Function: Saves Data to an existing contact or adds a new contact 437 * 438 * @param $info: Array containing the form data 439 * 440 * additions params used: 441 * $_REQUEST['blob'] - contains the blob of an existing id 442 * $_REQUEST['contactid'] - the id of the existing contact or "new" for a new one 443 */ 444 function saveData($info){ 445 #msg(print_r($info,true)); 446 447 if ($info['surname'] =='' && $info['cfunction']=='') { 448 msg('Please enter either a last name or a function.',-1); 449 return false; 450 } else { 451 try { 452 $db_helper = plugin_load('helper', 'addressbook_db'); 453 $sqlite = $db_helper->getDB(); 454 455 } catch (Exception $e) { 456 msg($e->getMessage(), -1); 457 return false; 458 } 459 460 $keys = array_keys($info); 461 462 # Use existing photo in existing id 463 if ($_REQUEST['contactid'] != 'new' && isset($_REQUEST['blob']) && $_REQUEST['removephoto'] != 'Remove photo' && $info['photo']== false) { 464 $info['photo'] = $_REQUEST['blob']; 465 # msg("Keep existing photo",2); 466 } 467 468 if ($info['photo']!== false) $blob = $info['photo']; 469 470 # Add new contact 471 if ($_REQUEST['contactid'] == 'new') { 472 #if ($info['photo']!== false) $blob = $info['photo']; 473 $sql = "INSERT INTO addresslist 474 (".implode(',',$keys).") VALUES 475 ("; 476 477 foreach ($keys as $k) { 478 if ($k != 'photo') $sql .= "'".$info[$k]."',"; 479 if ($k == 'photo') $sql .= "'$blob'"; 480 } 481 482 $sql .= ')'; 483 484 unset ($blob); 485 486 $res = $sqlite->query($sql); 487 488 if (ADRESSBOOK_SQL) msg("<code>$sql</code>",2); 489 490 msg("Added new contact",1); 491 return true; 492 } else { 493 494 # Update existing contact 495 496 $sql = "UPDATE addresslist SET "; 497 498 foreach ($keys as $k) { 499 if ($k != 'photo') $sql .= " $k = '".$info[$k]."', "; 500 if ($k == 'photo') $sql .= " $k = '$blob'"; 501 } 502 503 $sql .= " WHERE id = ".$_REQUEST['contactid']; 504 505 if (ADRESSBOOK_SQL) msg("<code>$sql</code>",2); 506 507 $res = $sqlite->query($sql); 508 msg("Contact data updated",1); 509 return true; 510 } 511 } 512 } 513 514 515 function deleteContact($cid){ 516 try { 517 $db_helper = plugin_load('helper', 'addressbook_db'); 518 $sqlite = $db_helper->getDB(); 519 } catch (Exception $e) { 520 msg($e->getMessage(), -1); 521 return false; 522 } 523 524 $sql = "DELETE FROM addresslist WHERE id = $cid"; 525 $sqlite->query($sql); 526 527 if (ADRESSBOOK_SQL) msg("<code>$sql</code>",2); 528 529 msg('Contact deleted',1); 530 531 } 532 533 /* Scale image to a maximum size (either width or height maximum) 534 * from jpg to jpg 535 * 536 * @param $filename: name of source file 537 * @param $max: maximum width or heigth (depending on which is longer) 538 * @param $quality: compression rate 539 * 540 * return: blob with jpg 541 */ 542 function scaleJPG($filename,$max=120,$quality=70){ 543 544 # calculate new dimensions 545 list($width, $height) = getimagesize($filename); 546 547 if ($width > $height) {$percent = $max/$width;} else {$percent = $max/$height;} 548 549 $newwidth = $width * $percent; 550 $newheight = $height * $percent; 551 552 # load image 553 $thumb = imagecreatetruecolor($newwidth, $newheight); 554 $source = imagecreatefromjpeg($filename); 555 556 # scale 557 imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height); 558 559 # output 560 ob_start(); 561 imagejpeg($thumb,NULL,$quality); 562 $result = ob_get_contents(); 563 ob_end_clean(); 564 565 return $result; 566 } 567 568 569 /* Searches the database for the occurence of search terms. 570 * The search uses AND-operator for multiple terms 571 * 572 * @param $text: search terms separated with a blank space 573 * 574 * return: 575 * - boolean false: no matches 576 * - array with matches 577 */ 578 function searchDB($text=false,$order='surname,firstname'){ 579 if ($text == false || strlen($text) < 2) {msg("Invalid search.");return;} 580 581 try { 582 $db_helper = plugin_load('helper', 'addressbook_db'); 583 $sqlite = $db_helper->getDB(); 584 } catch (Exception $e) { 585 msg($e->getMessage(), -1); 586 return false; 587 } 588 589 $text = explode(" ",$text); 590 591 $sql = "select * from addresslist WHERE instr(lower(surname || firstname || tel1 || tel2 || fax || description || cfunction || department) ,'".$text[0]."') > 0"; 592 for ($c=1;$c<count($text);$c++) $sql .= " AND instr(lower(' ' || surname || firstname || tel1 || tel2 || fax || description || cfunction || department) ,'".$text[$c]."') > 0"; 593 $sql .= " ORDER BY $order"; 594 595 $query = $sqlite->query($sql); 596 $res = $sqlite->res2arr($query); 597 598 if (ADRESSBOOK_SQL) msg("<code>$sql</code>",2); 599 600 if ($sqlite->res2count($sqlite->query($sql)) == 0) { 601 msg("No matches found",2); 602 return false; 603 } 604 605 return $res; 606 } 607 608 609 function getList($filters=false,$order="surname,firstname,cfunction,department"){ 610 try { 611 $db_helper = plugin_load('helper', 'addressbook_db'); 612 $sqlite = $db_helper->getDB(); 613 } catch (Exception $e) { 614 msg($e->getMessage(), -1); 615 return false; 616 } 617 618 # Get all elements if no filters are set 619 if ($filters === false){ 620 $sql = "select * from addresslist ORDER BY $order"; 621 } 622 623 # Get one department 624 if (isset($filters['department'])){ 625 $sql = "select * from addresslist WHERE UPPER(department) = UPPER('".$filters['department']."') ORDER BY $order"; 626 } 627 628 $query = $sqlite->query($sql); 629 $res = $sqlite->res2arr($query); 630 631 if (ADRESSBOOK_SQL) msg("<code>$sql</code>",2); 632 633 # return false if no matches are found 634 if ($sqlite->res2count($sqlite->query($sql)) == 0) { 635 msg("No matches found for list",2); 636 return false; 637 } 638 639 # Adjust content for sorting purposes when information is missing / not stated 640 foreach ($res as &$r) { 641 if ($r['surname'] == '' && $r['department'] == '') $r['department'] = $this->getLang('departments'); 642 if ($r['surname'] != '' && $r['department'] == '') $r['department'] = $this->getLang('general'); 643 } 644 645 return $res; 646 } 647 648 649 /* Creates a list of values from a column. Each element is listed 650 * once. 651 * 652 * @param string $column: choose column from which to get data 653 * @param boolean $htmlselect: creates output string containing html for a dropdown box 654 * 655 * @return: 656 * - array: elements founds 657 * - string: with html for checkbox 658 */ 659 function getCriteria($column,$htmlselect = true){ 660 $allowed = array('cfunction','department'); 661 if (!in_array($column,$allowed)) return false; 662 663 try { 664 $db_helper = plugin_load('helper', 'addressbook_db'); 665 $sqlite = $db_helper->getDB(); 666 } catch (Exception $e) { 667 msg($e->getMessage(), -1); 668 return false; 669 } 670 671 $sql = "SELECT DISTINCT $column FROM addresslist WHERE $column NOT LIKE '' ORDER by $column"; 672 673 $query = $sqlite->query($sql); 674 $res = $sqlite->res2arr($query); 675 676 if (ADRESSBOOK_SQL) msg("<code>$sql</code>",2); 677 678 # return false if no matches are found 679 if ($sqlite->res2count($sqlite->query($sql)) == 0) { 680 #msg("No matches found for criteria",2); 681 return false; 682 } 683 684 foreach ($res as $r) $n[] =$r[$column]; 685 if ($htmlselect){ 686 $res = ''; 687 $res .= ucfirst($column); 688 $res .= '<select name="column" id="column">'; 689 $res .= "<option value='all'>All</option>"; 690 foreach ($n as $s) $res .= "<option value='$s'>$s</option>"; 691 $res .= '</select>'; 692 return $res; 693 } 694 695 return $n; 696 } 697 698 /* Helper function, similar to implode 699 * Adds string elements to an array only if it is not empty and then implodes them 700 */ 701 function names($list,$symbol=', '){ 702 $res = Array(); 703 foreach ($list as $l) if ($l != '') $res[]=$l; 704 return implode($symbol,$res); 705 } 706 707 708 /* Helper function 709 * Return array with parameter=>value pairs 710 * 711 * @param string $params = parameters in form "<somet_text>?param1=value1¶m2=value2...paramN=valueN" 712 713 * 714 * @return array(parameter1 => value1, ...) 715 */ 716 function getValue($params){ 717 $params = substr($params,strpos($params,'?')+1); 718 $opts = explode('&',$params); 719 720 foreach ($opts as $o) { 721 if (strpos($o,'=') == 0) {$res[$o] = false;} else { 722 $t = explode('=',$o); 723 $res[$t[0]] = $t[1]; 724 } 725 } 726 727 return $res; 728 } 729 730 731 /* Build an index showing contacts 732 * 733 * @param $list: list of contacts 734 * @param $separator = db_field for which headers are created in the list. 735 */ 736 function buildIndex($list=false,$separator=false,$target=false){ 737 738 # if no list ist stated, get all. If no entry in DB, return 739 if ($list===false){ 740 $list =$this->getList(); 741 if ($list === false) return; 742 } 743 744 # Sort by Surname or Function->if no surname ist stated 745 if (!$separator) usort($list,'contact_custom_double_sort'); 746 747 $out .= $this->getLang('elements').': '.count($list); 748 $out .= '<div class="addressbook_list" style="column-width:20em;margin-top:3px;">'; 749 750 751 $sep = ''; 752 foreach ($list as $r){ 753 754 if ($separator !== false){ 755 if ($sep != $r[$separator]) { 756 $sep = $r[$separator]; 757 $out .= '<h3>'.$r[$separator].'</h3>'; 758 } 759 } 760 761 $out .= '<span>'; 762 763 if ($r['surname'].$r['firstname'] <> '') {$names = true;} else {$names = false;} 764 765 if ($target != false) $out .= '<a href="'.wl($target,'showcontact='.$r['id']).'">'; 766 767 $out .= $r['surname'] .($r['firstname'] <> ''? ', '.$r['firstname']:''); 768 if (!$names) $out .= $this->names(array($r['cfunction'],$r['department'])); 769 770 if ($target != false) $out .= '</a>'; 771 772 if ($names && $r['cfunction'].$r['department'] <>'') $out .= ' ('.$this->names(array($r['cfunction'],$r['department'])).')'; 773 774 if ($r['tel1'].$r['tel2'] <> '') $out .= ' Tel: '.$this->names(array($r['tel1'],$r['tel2'])); 775 776 $out .= '</span>'; 777 } 778 $out .= '</div>'; 779 780 return $out; 781 782 } 783 784 785 /* Builds a printable contact list 786 * 787 * @param array $list = list of contact entries in format array[1..n](db_field => value) 788 * 789 * @param string $separator = name of database field. This name is added as a 790 * header between the contact entries. Important: The 791 * entries should be sorted in first place according 792 * to this speparator, otherweise there will be as many 793 * headers as contacts!. 794 * Allowed separators: 'department' 795 * 796 * @param integer $entriesperpage = amount of list items per page, must be even! 797 * @param 798 */ 799 function buildPrintList($list=false,$separator = false,$entriesperpage = 80){ 800 801 # validation: separator type correct 802 $allowed_separators = Array('department'); 803 if (!in_array($separator,$allowed_separators)) $separator = false; 804 805 # validation entries per page must be even 806 if ($entriesperpage % 2 == 1) $entriesperpage++; 807 808 # if no list ist stated, get all. If no entry in DB, return 809 if ($list===false){ 810 $list =$this->getList(false,($separator == false? '': "$separator,").'surname,firstname,cfunction'); 811 if ($list === false) return; 812 } 813 814 # Sort by Surname or Function->if no surname ist stated 815 if (!$separator) usort($list,'contact_custom_double_sort'); 816 817 $amount = count($list); 818 $pages = ceil($amount/$entriesperpage); 819 820 # $separator = 'department'; 821 # process list before generating the table 822 if ($separator == 'department'){ 823 $dep = $list[$c+1]['department']; 824 $insert = Array(); 825 $i_count = 0; 826 for ($c=0;$c<$amount;$c++) { 827 if ($list[$c+1]['department'] != $dep) { 828 829 830 $i_count++; 831 832 if ($c+$i_count % $entriesperpage > 0) { 833 834 $insert[] = array('position' => $c+$i_count, 'title' =>true, 'cfunction' => ''); 835 $i_count++; 836 } 837 838 $insert[] = array('position' => $c+$i_count, 'title' =>true, 'cfunction' => $list[$c+1]['department']); 839 840 841 $dep = $list[$c+1]['department']; 842 843 } 844 845 } 846 847 foreach ($insert as $i){ 848 849 unset($temp); 850 for ($c=0;$c<count($list);$c++){ 851 852 if ($c==$i['position']){ 853 $temp[] = array('cfunction'=>$i['cfunction'],'title' => true); 854 } 855 856 $temp[] = $list[$c]; 857 858 } 859 $list = $temp; 860 861 } 862 863 $amount = count($list); 864 $pages = ceil($amount/$entriesperpage); 865 866 } 867 868 869 for ($p=0;$p<$pages;$p++) { 870 871 $out .= '<table class="plugin_addressbook_print">'; 872 873 for ($row=0;$row<$entriesperpage/2;$row++) { 874 875 unset($i); 876 $i[] = ($p * $entriesperpage) + $row; 877 $i[] = ($p * $entriesperpage) + $row + ($entriesperpage/2); 878 $col = 0; 879 880 #if ($i[0] < $amount) 881 $out .= '<tr'.($row % 2 == 1? ' style="background:lightgray"':'').'>'; 882 883 foreach ($i as $d) { 884 # Output title 885 if ($separator != false && $list[$d]['title'] == true) { 886 $out .= '<td style="font-weight:bold;text-decoration:underline;font-size:12px;text-align:left;background:white" colspan=4>'.$list[$d]['cfunction'].'</td>'; 887 $col++; 888 if ($col < count($i)) $out .= '<td style="background:white;width:10px;"></td>'; 889 } 890 891 # Output contact data 892 if ($d < $amount && !isset($list[$d]['title'])) { 893 894 $out .= '<td style="text-align:left">'.$this->names(array($list[$d]['cfunction'],$list[$d]['surname']),' ').'</td>'; 895 $out .= '<td>'.$list[$d]['tel1'].'</td>'; 896 $out .= '<td>'.$list[$d]['tel2'].'</td>'; 897 $out .= '<td>'.$list[$d]['fax'].'</td>'; 898 899 $col++; 900 if ($col < count($i)) $out .= '<td style="background:white;width:10px;"></td>'; 901 } 902 903 # Fill with empty cells if there are no entries, so that the table is continued 904 if ($d> $amount) { 905 $out.= '<td colspan=4 style="background:white;">'.str_repeat(' ',15).'</td>'; 906 $col++; 907 if ($col < count($i)) $out .= '<td style="background:white;width:10px;"></td>'; 908 } 909 910 } 911 912 $out .= '</tr>'; 913 914 } 915 916 $out .= '</table>'; 917 918 } 919 920 return $out; 921 922 } 923 924 925 /* Copies the first entry of the database multiple time for testing purposes 926 * Beware: This can take minutes! 927 * 928 * @param $n: amount of copie to be made 929 */ 930 function fillDB($n=0){ 931 try { 932 $db_helper = plugin_load('helper', 'addressbook_db'); 933 $sqlite = $db_helper->getDB(); 934 } catch (Exception $e) { 935 msg($e->getMessage(), -1); 936 return false; 937 } 938 939 $sql = "select * from addresslist WHERE id = 1"; 940 941 $query = $sqlite->query($sql); 942 $res = $sqlite->res2arr($query)[0]; 943 unset($res['id']); 944 945 for ($c=0;$c<$n;$c++){ 946 $sql = "INSERT INTO addresslist 947 (firstname,surname,cfunction,tel1,tel2,fax,email,department,description,photo) VALUES 948 ("; 949 foreach ($res as $k=>$r) $sql.= "'$r'".($k=='photo'? ')':','); 950 $query = $sqlite->query($sql); 951 } 952 } 953 954} 955 956 957/* Inspired by https://www.php.net/manual/de/function.asort.php 958 * 959 * Callback function to sort the contact list by surname OR 960 * cfunction if nor surname ist stated 961 * 962 * */ 963function contact_custom_double_sort($a,$b) { 964 if ($a['surname'] == '') $a['surname'] = $a['cfunction']; 965 if ($b['surname'] == '') $b['surname'] = $b['cfunction']; 966 return $a['surname'] > $b['surname']; 967} 968 969 970function addressbook_debug_show($direct=true){ 971 $out = '<pre>'.print_r($_REQUEST,true).'</pre>'; 972 if ($direct) echo $out; 973 return $out; 974} 975