1<?php 2/** 3* 4* Database Management plugin: manages tables and column data 5* 6* The function action_db is called when the user has navigated to the database namespace 7* 8* @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 9* @author Langham Associates <enquiries@langhamAssociates.com> 10* v1.0.4 11*/ 12 13/* 14Description 15----------- 16A simple database management system which stores data in files in a 17namespace in the dokuwiki folder 18There is a new folder under dokuwiki named database (held as $dbName) 19This folder contains 20- a new "system" folder called "Create Table" 21- one folder per user table , e.g. "01-Countries" and "02-people" 22For any session, the record is assigned an id, which is the row number in the file 23 24User data is held in the folders with names of the form nn-Name , e.g. 2501-Countries 26 27When a user creates a table, a new folder is created, with the next sequence number assigned, e.g. 02-People 28 29Each folder holds two files and data within the files is pipe(|)-separated: 30 definition.txt holds the column definitions (see below) 31 data.txt holds the values in the columns 32 33There are two types of reference fields, where the field holds a pointer rather than a value. 34To implement this, there are two special types of column, over and above string , number etc. 35The concept of LOOKUP is that within one set of data (held in the language file) are held such things as gender 36If the column has type 101, this relates to the first row in the set, i.e. gender. 37The field then holds the number 1 or 2 to distinguish the value. 38The concept of REFERENCE is that a user table is defined with an ID as the first field. 39This will dynamically add it to the list of reference tables when a column is defined. 40If, for example, this was a table of countries, and a row with id = 1 and name = France existed, 41whenever a column was defined as referring to that table, if 1 was in the field, France would be displayed. 42The above is hidden from the user, since they only ever see the drop-downs showing France etc. 43 44 45The main objects are: 46Environment 47Session 48Table 49Column 50File 51Row 52Record 53 54 55Table consists of Columns 56File consists of Rows 57 58The data for a Table is held in a File 59 60When a row is read in from the file it is read into a Record 61 62Admin 63----- 64this involves treating definition.txt as a table with one record per column 65The elements in the definition of each column are 66name - a name for the column (not used) 67label - displayed on the screen 68mandatory - yes/no 69unique - yes/no - particularly need for reference tables for both the id 70and the value e.g. countries 71type - 1 String 72 2 Number 73 3 Date 74 101 Lookup Gender ) 75 102 Yes and No ) more can be added in lang.php 76 103 Lookup Title ) 77 1001 Reference Countries (for example) - added when table created 78with unique numeric id as first column 79visible - yes/no 80 81N.B The following are not permitted in v1.0 82Removing tables 83Removing columns 84 85The following are not recommended : 86Deleting or amending records in reference tables 87 88V1.0.1 89------ 90wild-cards in search 91Remove any HTML errors 92Correct sorting by reference column 93 94V1.0.2 95------ 96language-enable the following 97- data types 98- Referring to other tables 99- lookups 100ensure compatibility with IE 101 102V1.0.3 103------- 1041. allow fields to be hidden , additional column attribute called visible defaults to Yes 105 1062. New link fields 107new field type INTERNAL_LINK 108 - format [[wiki:aa:bb|Displayed Name]] 109 - display_for_change displays above 110 - display function displays "Displayed Name" as href to link with id=wiki:aa:bb 111 - the string is stored with : instead of | 112new field type EXTERNAL_LINK 113 - format [[http://....... |Displayed Name]] 114 - display_for_change displays above 115 - display function displays "Displayed Name" as href to link 116 - the string is stored with : instead of | 117Must sort correctly on links last element 118 1193. optimistic locking - lost updates 120 - check each original field value against current contents 121 - if any not the same there must have been an intermediate update 122N.B To implement Lost updates it is necessary to store the original valueson 123the update form and the delete form, these are then passed to the update function 124 125New lang entries needed for 126lost_update 127external links 128hidden 129 130v1.0.4 131------ 132Create the "Create table" folder if it is not there already 133This allows zip to hold only the code for database folder and to use Dokuwiki plugin manager 134*/ 135 136/** 137* Environment Class 138* 139* Establishes the location of the files 140* 141*/ 142class Environment { 143 var $URL; 144 var $TYPES=array(); // the names of the types read from the lang file 145 var $NUMBER_OF_BASIC_TYPES = 5; // the number of basic types string, number etc 146 var $TYPE_STRING = 1; 147 var $TYPE_NUMBER =2; 148 var $TYPE_DATE = 3; 149 var $TYPE_INTERNAL_LINK = 4; 150 var $TYPE_EXTERNAL_LINK = 5; 151 var $COLUMNS=array(); // holds the definition of the structure, e.g. column attributes 152 var $YES = 1; 153 var $LOOKUP_OFFSET = 100; // the first set of lookups is 101 154 var $REFERENCE_OFFSET = 1000; // the first reference table is 1001 155 var $TYPE_LOOKUP = 999; // the column is of type lookup 156 var $DICTIONARY_FOLDER = "Create table"; 157 var $DEBUG_FILE = "debug.txt"; 158 var $WILD_CARD = '%'; // can be used at the start or end of a filter 159 var $COLUMN_SEPARATOR='|'; // used to separate fields when the data is written to the file 160 var $COLON = ':'; // used to separate the elements in the link field 161 var $baseFolder ; 162 var $imagesFolder; 163 var $tableNames= array(); // the names of the tables 164/** 165* 166* Constructor 167* 168* @param none 169* @returns object 170* 171*/ 172 function Environment () { 173 global $dbName; 174 global $myLang; 175// Set up the main data types 176 $this->TYPES[1]=getMyLang('type_string'); 177 $this->TYPES[2]=getMyLang('type_number'); 178 $this->TYPES[3]=getMyLang('type_date'); 179 $this->TYPES[4]=getMyLang('type_internal_link'); 180 $this->TYPES[5]=getMyLang('type_external_link'); 181// The column parameters are set up here - the label comes from lang file 182 $this->COLUMNS['name'][1] ='name'; 183 $this->COLUMNS['name'][2] ='label'; 184 $this->COLUMNS['name'][3] ='mandatory'; 185 $this->COLUMNS['name'][4] ='unique'; 186 $this->COLUMNS['name'][5] ='type'; 187 $this->COLUMNS['name'][6] ='visible'; 188 $this->COLUMNS['mandatory'][1] =1; 189 $this->COLUMNS['mandatory'][2] =1; 190 $this->COLUMNS['mandatory'][3] =1; 191 $this->COLUMNS['mandatory'][4] =1; 192 $this->COLUMNS['mandatory'][5] =1; 193 $this->COLUMNS['mandatory'][6] =1; 194 $this->COLUMNS['unique'][1] =1; 195 $this->COLUMNS['unique'][2] =1; 196 $this->COLUMNS['unique'][3] =2; 197 $this->COLUMNS['unique'][4] =2; 198 $this->COLUMNS['unique'][5] =2; 199 $this->COLUMNS['unique'][6] =2; 200 $this->COLUMNS['type'][1] =1; 201 $this->COLUMNS['type'][2] =1; 202 $this->COLUMNS['type'][3] =102; 203 $this->COLUMNS['type'][4] =102; 204 $this->COLUMNS['type'][5] =999; 205 $this->COLUMNS['type'][6] =102; 206 $this->COLUMNS['visible'][1] =1; 207 $this->COLUMNS['visible'][2] =1; 208 $this->COLUMNS['visible'][3] =1; 209 $this->COLUMNS['visible'][4] =1; 210 $this->COLUMNS['visible'][5] =1; 211 $this->COLUMNS['visible'][6] =1; 212// Pick up the column label 213 for ($i=1;$i<= count($myLang['column_label']);$i++) 214 $this->COLUMNS['label'][$i] = getMyLang('column_label',$i); 215// The images oflder 216 $this->imagesFolder=DOKU_BASE.'lib/plugins/'.$dbName.'/images/'; 217// The base folder 218 $this->baseFolder = DOKU_INC.'data/pages/'.$dbName.'/'; 219 $this->URL = DOKU_URL.'doku.php?idx='.$dbName; 220// Begin add v1.0.4 221// Check if dictionary folder exists 222 $directoryName = $this->baseFolder.$this->DICTIONARY_FOLDER; 223 if (!file_exists($directoryName)) { 224 // echo "creating $this->baseFolder"; 225 mkdir("$this->baseFolder",0777); 226// echo ("creating $this->baseFolder$this->DICTIONARY_FOLDER"); 227 mkdir("$this->baseFolder$this->DICTIONARY_FOLDER",0777); 228 } 229// End add v1.0.4 230 231// Get list of table names excluding Dictionary 232 if ($handle = opendir($this->baseFolder)) { 233 while (false !== ($file = readdir($handle))) { 234 if ($file != "." && $file != ".." && $file != $this->DICTIONARY_FOLDER) { 235 $counter = abs(substr($file,0,strpos($file,'-'))); 236 $this->tableNames[$counter] = substr($file,3); 237 } 238 } 239 closedir($handle); 240 } 241 } 242/** 243* gets the folder name for a table 244* 245* @param number $p_id the id of the table 246* @returns string the folder name 247* 248*/ 249 function get_folder($p_id) { 250 $ret = $this->baseFolder; 251 if ($p_id<10 ) $id='0'.$p_id; 252 else $id = $p_id; 253// form the name of the folder based on <nn>-<name> 254 $ret .= $id."-".$this->tableNames[$p_id]."/"; 255 return $ret; 256 } 257} 258/** 259* Session Class 260* 261* Holds session-specific information 262* 263*/ 264class Session { 265 var $columnTypeList = array(); 266 var $lookupTitles = array(); 267 var $lookupOptions = array(); 268/** 269* Constructor 270* 271* Establishes the location of the files and any lookups 272* 273*/ 274 function Session() { 275 global $display; 276 global $environment; 277 global $auditTrail; 278 global $session; 279 global $myLang; 280// Get list of column types 281 $auditTrail->add_header("Session"); 282 for ($i=1;$i<=$environment->NUMBER_OF_BASIC_TYPES;$i++) { 283 $this->columnTypeList[$i] = $environment->TYPES[$i]; 284 } 285// Get the list of lookups 286 $auditTrail->add("Lookups"); 287// the lookups are in myLang$['lookup'] 288// Set up lookupTitles, lookupOptions and columnTypeList 289 for ($lookupCount=1; $lookupCount<=count($myLang['lookup']);$lookupCount++) { 290 $this->lookupTitles[$lookupCount] = getMyLang('lookup',$lookupCount,1); 291 $this->columnTypeList[$environment->LOOKUP_OFFSET+$lookupCount] 292 = getMyLang('prompt_looking_up').' '.getMyLang('lookup',$lookupCount,1); 293 for ($optionCount=2;$optionCount<=count($myLang['lookup'][$lookupCount]);$optionCount++) { 294 $this->lookupOptions[$lookupCount][$optionCount-1] = getMyLang('lookup',$lookupCount,$optionCount); 295 } 296 } 297 $counter=0; 298// Get the list of reference tables 299 $auditTrail->add("reference Tables"); 300 foreach ($environment->tableNames as $tableName) { 301 $counter++; 302 $tab = new Table($counter); 303 if ($tab->possibleReference) { 304 $this->columnTypeList[$environment->REFERENCE_OFFSET+$counter] 305 =getMyLang('prompt_referencing').' '.$tableName; 306 $auditTrail->add("reference Table ".$tableName); 307 } 308 } 309 $auditTrail->add_footer("Session"); 310 } 311/** 312* Determines whether or not the user has the necessary permissions to perform the action 313* 314* @param string $action - the action being taken 315* @returns boolean true if the user has the necessary permissions 316* (not convinced that the perms are being used correctly (should be binary mask) 317* 318*/ 319 function allowed ($action) { 320 global $auditTrail; 321 $INFO = pageinfo(); // picked up from the dokuwiki environment 322 $perm = $INFO['perm']; // the permissions of the current user 323 $auditTrail->add_header('Session->allowed'); 324// Decide on the level of permission required 325 if ($action== 'insertForm') $requiredLevel = AUTH_CREATE; 326 if ($action== 'insertAction') $requiredLevel = AUTH_CREATE; 327 if ($action== 'updateForm') $requiredLevel = AUTH_EDIT; 328 if ($action== 'updateaction') $requiredLevel = AUTH_EDIT; 329 if ($action== 'createTable') $requiredLevel = AUTH_ADMIN; 330 if ($action== 'createTableForm') $requiredLevel = AUTH_ADMIN; 331 if ($action== 'admin') $requiredLevel = AUTH_ADMIN; 332 if ($action== 'deleteForm') $requiredLevel = AUTH_DELETE; 333 if ($action== 'deleteAction') $requiredLevel = AUTH_DELETE; 334 $auditTrail->add('requiredLevel = '.$requiredLevel); 335 $auditTrail->add('perm = '.$perm); 336// Decide whether or not to procede 337 $auditTrail->add_footer('Session->allowed'); 338 if ($perm >= $requiredLevel) 339 return true; 340 else 341 return false; 342 } 343/** 344* Get the list of data type including lookups and references 345* 346* @param string $value the selected value which will be marked as selected 347* @param string $name e.g. "values" so that the names of the variables are values0 values1 etc 348* @param string $type if "search" the No Selection is added 349* @returns array list of options for data type 350* 351*/ 352 function list_of_types($value, $name, $type) { 353 global $environment; 354 global $myLang; 355 $list = "<select name='".$name."'>"; 356// For a search we need the No Selection option first 357 if ($type=="search") { 358 $list .= "<option value='' >"; 359 $list .= getMyLang('prompt_no_selection') ; 360 $list .= "</option>"; 361 } 362// The Basic types 363 for ($i=1;$i<=$environment->NUMBER_OF_BASIC_TYPES;$i++) { 364 $list .= "<option value = '".$i."'"; 365 if ($value == $i) $list .= " selected = 'selected' "; 366 $list .=">".$environment->TYPES[$i]."</option>"; 367 } 368 $lookups = $this->lookupTitles;; 369 $counter = $environment->LOOKUP_OFFSET; 370// The lookups 371 foreach ($lookups as $lookup) { 372 $counter +=1; 373 $list .= "<option value = '".$counter."'"; 374 if ($value == $counter) $list .= " selected ='selected' "; 375 $list .= '>'.getMyLang('prompt_looking_up').' '.$lookup.'</option>'; 376 } 377// The reference tables 378 for ($ptr =1;$ptr <=count($environment->tableNames);$ptr++) { 379 $tab = new Table($ptr); 380 if ($tab->possibleReference) { 381 $counter=$ptr+$environment->REFERENCE_OFFSET; 382 $list .= "<option value = '".$counter."'"; 383 if ($value == $counter) $list .= " selected ='selected' "; 384 385 $list .= '>'.getMyLang('prompt_referencing').' '.$tab->name.'</option>'; 386 } 387 } 388 $list .= "</select>"; 389 return $list; 390 } 391} 392/** 393* Messages Class 394* 395* Record and display the messages 396* 397*/ 398class Messages { 399 var $messageList = array(); 400 var $exist = false; 401 function Messages () { 402 $this->exist = false; 403 } 404/** 405* add the message to the list 406* 407* @param string $p_message the error message 408* @returns None 409* 410*/ 411 function add($p_message) { 412 $this->messageList[] = $p_message; 413 $this->exist = true; 414 } 415/** 416* display the messages 417* 418* @param none 419* @returns none 420* 421*/ 422 function fail_soft () { 423 global $auditTrail; 424/* Uncomment if debugging 425 $auditTrail->display(); 426*/ 427 } 428/** 429* display all the messages 430* 431* @param None 432* @returns None 433* 434*/ 435 function displayAll() { 436 global $display; 437 $display->output("<table border=1>"); 438 foreach($this->messageList as $message) { 439 $display->output("<tr><td align=center>".$message."</td></tr>"); 440 } 441 $display->output("</table>"); 442 } 443} 444/** 445* AuditTrail Class 446* 447* accumulates and formats audit trail info 448* 449*/ 450class AuditTrail { 451 var $messageList = array(); 452 var $indent; 453/** 454* Constructor 455* 456* @param none 457* @returns object 458* 459*/ 460 function AuditTrail () { 461 $this->indent=0; 462 } 463/** 464* add a message to the audit trail 465* 466* @param string $p_message the message 467* @returns none 468* 469*/ 470 function add($p_message) { 471 global $display; 472 $this->messageList[] = $this->tab().$p_message; 473 $display->debug_output($this->tab().$p_message); 474 } 475/** 476* add a header to the audit trail 477* 478* @param string $p_message the message 479* @returns none 480* 481*/ 482 function add_header($p_message) { 483 $this->indent++; 484 $this->add("<--- Start of ". $p_message."-->"); 485 } 486/** 487* add a footer to the audit trail 488* 489* @param string $p_message the message 490* @returns none 491* 492*/ 493 function add_footer($p_message) { 494 $this->add("<--- End of ". $p_message."-->"); 495 $this->indent--; 496 } 497/** 498* calculate the indentation for the audit trail 499* 500* @param string $p_message the message 501* @returns none 502* 503*/ 504 function tab() { 505 $t=''; 506 for ($i=0;$i<$this->indent;$i++) 507 $t .= '>>'; 508 return $t; 509 } 510/** 511* display the messages in the audit trail 512* 513* @param string $p_message the message 514* @returns none 515* 516*/ 517 function display() { 518 echo "<BR>Audit Trail"; 519 foreach($this->messageList as $message) 520 echo "<BR>".$message; 521 echo "<BR>"; 522 } 523} 524/** 525* Column Class 526* 527* holds info on a column in a table 528* 529*/ 530class Column { 531 var $id; 532 var $name; 533 var $label; 534 var $mandatory; 535 var $unique; 536 var $type; 537 var $visible; 538 var $isVisible; 539 var $allowNoSelection; 540/** 541* 542* Constructor 543* 544* @param number $p_id id of the column 545* @param string $p_name name of the column 546* @param string $p_label label for the column 547* @param number $p_mandatory lookup , 1=yes, 2= no 548* @param string $p_type type of the column, string, number, date, lookup or reference 549* @param string $p_visible visible , 1=yes, 2= no 550* @returns object 551* 552*/ 553 function Column ($p_id, $p_name, $p_label, $p_mandatory, $p_unique, $p_type, $p_visible) { 554 global $display; 555 global $environment; 556 global $auditTrail; 557 $auditTrail->add_header('Creating column '.$p_name); 558 559 $this->id = $p_id; 560 $this->name = $p_name; 561 $this->label = $p_label; 562 $this->mandatory = $p_mandatory; 563 $this->unique = $p_unique; 564 $this->type = $p_type; 565// allowNoSelection is the equivalent of optional 566 if ($this->mandatory == $environment->YES) $this->allowNoSelection=false; 567 else $this->allowNoSelection=true; 568// set up isVisible 569 $this->visible = $p_visible; 570 if ($this->visible == $environment->YES) $this->isVisible = true; 571 else $this->isVisible = false; 572 573 $auditTrail->add_footer('Creating column '.$p_name); 574 } 575/** 576* return the string to display the column for edit 577* 578* @param string $value the value to be displayed for edit 579* @returns string the HTML to be displayed 580* 581*/ 582 function display_for_change($value='',$type='search') { 583 global $environment; 584 global $session; 585 global $auditTrail; 586//The output used for the search in the list and for update and create 587 $auditTrail->add_header('Column - display_for_change column = '.$this->name); 588 $name = "values".$this->id; 589 $ret=''; 590//Convert the form held on the database to the form for display and change 591 $value = $this->fromDatabase($value); 592// When searching, you can have "No selection" 593 if ($type=='search') $noSelectionAllowed = true; 594 else $noSelectionAllowed = $this->allowNoSelection; // true if not mandatory 595 596 if ($this->type==$environment->TYPE_LOOKUP) { 597 $auditTrail->add('returning list_of_types'); 598 $ret=$session->list_of_types($value, $name,$type); 599 } 600 elseif ($this->type==$environment->TYPE_STRING 601 || $this->type==$environment->TYPE_NUMBER 602 || $this->type==$environment->TYPE_DATE 603 || $this->type==$environment->TYPE_INTERNAL_LINK 604 || $this->type==$environment->TYPE_EXTERNAL_LINK) { 605 $ret .= '<input type="text" class="edit" name="'.$name.'"'; 606 if ($value > ' ') 607 $ret .= ' value="'.$value.'"'; 608 $ret.=' />'; 609 } 610 elseif ($this->type>$environment->LOOKUP_OFFSET && $this->type<$environment->REFERENCE_OFFSET) { 611// It is a lookup 612 $list=$session->lookupOptions[$this->type - $environment->LOOKUP_OFFSET]; 613 $ret .= $this->drop_down($name,$list,$noSelectionAllowed,$value); 614 } 615 elseif ($this->type>$environment->REFERENCE_OFFSET) { 616//It is a reference table 617 $referenceTable = new Table($this->type - $environment->REFERENCE_OFFSET,"data"); 618//get all the records 619 $referenceTable->get_all(); 620// put items in list 621 $recCounter=0; 622 $listOfValues=array(); 623 foreach($referenceTable->recordObjs as $record) { 624 $recCounter++; 625 $auditTrail->add('Reference table = '.$record->values[1]); 626 $listOfPointers[$recCounter] = $record->values[1]; 627 $listOfValues[$recCounter]=$record->values[2]; 628 } 629 $sortedListObj = new SortedArray($listOfValues); 630 $sortedList = $sortedListObj->sortedList; 631 $counter = 0; 632 foreach($sortedList as $ptr) { 633 $counter++; 634 $sortedListOfPointers[$counter] = $listOfPointers[$ptr]; 635 $sortedListOfValues[$counter] = $listOfValues[$ptr]; 636 } 637 $ret .= $this->drop_down($name,$sortedListOfValues,$noSelectionAllowed,$value,$sortedListOfPointers); 638 } 639 $auditTrail->add_footer('column - display_for_change'); 640 return $ret; 641 } 642/** 643* return the string to display the original value on an edit form as a hidden field 644* 645* @param string $value the value of the field 646* @returns string the HTML to display 647* 648*/ 649 function display_original($p_counter, $p_value) { 650 $fieldName = "originals".$p_counter; 651 $ret = '<input type="hidden" name="'.$fieldName.'" value="'.$p_value.'">'; 652 return $ret; 653 } 654 655/** 656* prepare the field for inserting into/updating the database 657* 658* @param string $value the value of the field 659* @returns string 660* 661*/ 662 function toDatabase($value) { 663 global $environment; 664 global $messages; 665 $ret = $value; // default 666// No | within field unless link 667 $posOfPipe = strpos($value, $environment->COLUMN_SEPARATOR); 668// Now test if there is a pipe character 669 if ($posOfPipe === false) { 670// If there is no pipe and this is a link then there is a problem 671 if ($this->type == $environment->TYPE_INTERNAL_LINK 672 || $this->type == $environment->TYPE_EXTERNAL_LINK) { 673 $messages->add($this->label.getMyLang('err_dat_missing_pipe').$value); 674 } 675 } else { 676// But if there is a pipe and this is not a link then there is a problem 677 if ($this->type != $environment->TYPE_INTERNAL_LINK 678 && $this->type != $environment->TYPE_EXTERNAL_LINK) { 679 $messages->add($this->label.getMyLang('err_dat_extra_pipe').$value); 680 } 681 } 682// The display format of a link is either aaa:bbb:ccc|linkName or http://www...|linkName } 683// but the db version replaces the | with : 684 if ($this->type == $environment->TYPE_INTERNAL_LINK) { 685// convert the | into : 686 $ret = str_replace( $environment->COLUMN_SEPARATOR, $environment->COLON, $value); 687 } 688 if ($this->type == $environment->TYPE_EXTERNAL_LINK) { 689// convert the | into : 690 $ret = str_replace( $environment->COLUMN_SEPARATOR, $environment->COLON, $value); 691 } 692 return $ret; 693 } 694/** 695* convert the field from its form in the database 696* 697* @param string $value the value of the field 698* @returns string 699* 700*/ 701 function fromDatabase($value) { 702 global $environment; 703 $ret = $value; 704 if ($this->type == $environment->TYPE_INTERNAL_LINK 705 || $this->type == $environment->TYPE_EXTERNAL_LINK) { 706// convert the last : into | 707 if ($value>'') { 708 $ptr=strrpos ($value,$environment->COLON); // the last colon 709 $ret = substr($value,0,$ptr).$environment->COLUMN_SEPARATOR.substr($value,$ptr+1); 710 } 711 } 712 return $ret; 713 } 714/** 715* validate the value being entered for a field 716* 717* @param string $value the value of the field 718* @param object $messages the messages object 719* @returns none but message added if not valid 720* 721*/ 722 function validate ($value, $messages) { 723 global $environment; 724 global $myLang; 725 global $conf; 726// Number 727 if ($this->type == $environment->TYPE_NUMBER 728 || $this->type > $environment->NUMBER_OF_BASIC_TYPES) { 729 if (!is_numeric($value)) { 730 $messages->add($this->label.getMyLang('err_dat_typ_num').$value); 731 } 732 } 733// Date 734 if ($this->type == $environment->TYPE_DATE) { 735 if ($value>'' ) { 736 $day=substr($value,8,2); 737 $month = substr($value,5,2); 738 $year = substr($value,0,4); 739 if (substr($value,4,1) !='/' 740 ||substr($value,7,1) !='/' 741 ||!checkdate($month,$day,$year)) 742 $messages->add($this->label.getMyLang('err_dat_typ_dat').$value); 743 } 744 } 745// Internal Link 746 if ($this->type == $environment->TYPE_INTERNAL_LINK) { 747 if (substr($value,0,2) != '[[' 748 || substr($value,strlen($value)-2) != ']]' 749 || strpos($value, $environment->COLUMN_SEPARATOR) === false 750 ) { 751 $messages->add($this->label.getMyLang('err_dat_typ_int').$value); 752 } 753 } 754// External Link 755 if ($this->type == $environment->TYPE_EXTERNAL_LINK) { 756 if (substr($value,0,2) != '[[' 757 || substr($value,strlen($value)-2) != ']]' 758 || strpos($value, $environment->COLUMN_SEPARATOR) === false 759 ) { 760 $messages->add($this->label.getMyLang('err_dat_typ_ext').$value); 761 } 762 } 763// Mandatory 764 if ($this->mandatory==$environment->YES) { 765 if ($value=='') { 766 $messages->add($this->label.getMyLang('err_dat_typ_man')); 767 } 768 } 769 } 770/** 771* display the value of a field 772* 773* @param string $value the value of the field 774* @returns string 775* 776*/ 777 function display($value) { 778//The output used for the display only of values 779 global $environment; 780 global $session; 781 global $conf; 782// String or number 783 if ($this->type==$environment->TYPE_STRING 784 ||$this->type==$environment->TYPE_NUMBER) 785 $ret = $value; 786// Date 787 elseif ($this->type==$environment->TYPE_DATE) { 788/* 789 $dateFormat = $conf['dformat']; 790 $year = substr($value,0,4); 791 $month = substr($value,5,2); 792 $day = substr($value,8,2); 793 $dateAndTime = mktime(0,0,0,$month,$day,$year); 794 $ret = date($dateFormat, $dateAndTime); 795*/ 796 $ret = $value; 797 } 798// Internal Link 799 elseif ($this->type==$environment->TYPE_INTERNAL_LINK) { 800 $elements=explode($environment->COLON, $value); 801 if ($value>'') { 802 $last=count($elements)-1; 803 $name=$elements[$last]; 804 805 $ptr=strrpos ($value,$environment->COLON); // the last colon 806 $ret ='<a href="'.DOKU_URL.'doku.php?id='.substr($value,2,$ptr-2).'">'.substr($name,0,strlen($name)-2).'</a>'; 807 } 808 } 809// External Link 810 elseif ($this->type==$environment->TYPE_EXTERNAL_LINK) { 811 $elements=explode($environment->COLON, $value); 812 if ($value>'') { 813 $last=count($elements)-1; 814 $name=$elements[$last]; 815 $ptr=strrpos ($value,$environment->COLON); // the last colon 816 $ret ='<a href="'.substr($value,2,$ptr-2).'">'.substr($name,0,strlen($name)-2).'</a>'; 817 } 818 } 819// Lookup of column types (admin) 820 elseif ($this->type == $environment->TYPE_LOOKUP) { 821 $ret = $session->columnTypeList[$value]; 822 } 823// Lookup 824 elseif ($this->type>$environment->LOOKUP_OFFSET && $this->type<$environment->REFERENCE_OFFSET) { 825 $list=$session->lookupOptions[$this->type - $environment->LOOKUP_OFFSET]; 826 if ($value=='') $ret=''; 827 else $ret = $list[$value]; 828 } 829// Reference 830 elseif ($this->type>$environment->REFERENCE_OFFSET) { 831//Open the reference table 832 $referenceTable = new Table($this->type - $environment->REFERENCE_OFFSET,"data"); 833//get all the records 834 $referenceTable->get_all(); 835// put items in list 836 $recCounter=0; 837 foreach($referenceTable->recordObjs as $record) { 838 $recCounter++; 839 if ($value == $record->values[1]) 840 $ret = $record->values[2]; 841 } 842 } 843 return $ret; 844 } 845/** 846* construct the drop-down list for a field 847* 848* @param string $name the name of the column 849* @param array $values the list of values of the field 850* @param boolean $plusZero whether a zero value (No Selection) should be added 851* @param object $p_value the selected value 852* @param array $listOfPointers reference tables must have id as first field - this is the list of ids 853* @returns string the HTML for the list 854* 855*/ 856 function drop_down($name,$values,$plusZero=false,$p_value='',$listOfPointers='') { 857 global $myLang; 858 $ret = ''; 859 $ret .= "<select name='".$name."'>"; 860 $counter=0; 861// Is No Selection to be displayed at the top of the list 862 if ($plusZero) { 863 $ret .= "<option value='' >"; 864 $ret .= getMyLang('prompt_no_selection') ; 865 $ret .= "</option>"; 866 } 867 if (is_array($values)) { 868// The order of the values is determined by $listOfPointers if it exists 869 foreach($values as $value) { 870 $counter++; 871 $ret .= "<option value='"; 872 if (is_array($listOfPointers)) 873 $itemPointer = $listOfPointers[$counter]; 874 else 875 $itemPointer =$counter; 876 $ret .=$itemPointer. "'"; 877 if ($p_value!='' && $p_value==$itemPointer) 878 $ret .= " selected "; 879 $ret .= ">"; 880 $ret .= $value; 881 $ret .= "</option>"; 882 } 883 } 884 $ret .= "</select>"; 885 return $ret; 886 } 887} 888/** 889* Table Class 890* 891* holds the information on a table 892* 893*/ 894class Table { 895 var $id; 896 var $displayId; 897 var $isAdmin; 898 var $name; 899 var $columnObjs = array(); 900 var $recordObjs = array(); 901 var $populated = false; 902 var $possibleReference = false; 903/** 904* Constructor 905* 906* @param number/string $p_idOrName id of the table if it already 907exists or name if it is to be created 908* @returns object 909* 910*/ 911 function Table ($p_idOrName) { 912 global $display; 913 global $environment; 914 global $messages; 915 global $auditTrail; 916 global $session; 917 global $myLang; 918 $auditTrail->add_header("Table"); 919 $auditTrail->add("param = ".$p_idOrName); 920// The id is passed so this is an existing table 921 if (is_numeric($p_idOrName)) { 922 $p_id = $p_idOrName; 923 $this->displayId = $p_id; 924 $this->id= abs($p_id); 925// Get the folder name with this id 926 if (abs($this->id)>count($environment->tableNames)) { 927 $messages->add('TableDefinition : id too large'); 928 $messages->fail_soft(); 929 } 930 $display->debug_output ("creating table with id=".$this->id); 931 $this->name = $environment->tableNames[abs($p_id)]; 932 if ($p_id<0) { 933 $this->isAdmin=true; 934 $auditTrail->add('administering the table'); 935 } else { 936 $this->isAdmin=false; 937 $auditTrail->add('standard table'); 938 } 939// If this is admin definition then get from lang and hard-code 940 if ($this->isAdmin) { 941 for ($i=1;$i<=count($environment->COLUMNS['label']);$i++) { 942 $this->columnObjs[$i] = new Column($i 943 , $environment->COLUMNS['name'][$i] 944 , $environment->COLUMNS['label'][$i] 945 , $environment->COLUMNS['mandatory'][$i] 946 , $environment->COLUMNS['unique'][$i] 947 , $environment->COLUMNS['type'][$i] 948 , $environment->COLUMNS['visible'][$i] 949 ); 950 } 951 952 } else { 953 $this->columnObjs = $this->get_columns(); 954 } 955// Could this be a reference table 956 if ($this->columnObjs[1]->type==$environment->TYPE_NUMBER 957 && $this->columnObjs[1]->unique==$environment->YES) { 958 $auditTrail->add($this->name." is a reference table "); 959 $this->possibleReference = true; 960 } else { 961 $auditTrail->add($this->name." is not a reference table "); 962 $this->possibleReference = false; 963 } 964// Create Table option taken 965 }elseif ($p_idOrName == $environment->DICTIONARY_FOLDER ) { 966 $this->name = $environment->DICTIONARY_FOLDER; 967 $this->displayId = 0; 968 $this->id=0; 969// No parameter passed 970 } elseif ($p_idOrName == '') { 971 $messages->add("Invalid null table"); 972 $messages->fail_soft(); 973 } else { 974// This is a new table so create the folder and then the two files 975 $tableName = $p_idOrName; 976// Check that the name is different 977 $alreadyExists = false; 978 if (in_array($tableName,$environment->tableNames ,true)) 979 $alreadyExists = true; 980 if (!$alreadyExists) { 981 $tableId = count($environment->tableNames)+1; 982 $this->id=$tableId; 983 $this->isAdmin=false; 984 if ($tableId<10) $id='0'.$tableId; 985 else $id = $tableId; 986 $directoryName = $environment->baseFolder.$id.'-'.$tableName; 987 mkdir($directoryName,0777); 988 $environment = new Environment(); 989 $file = new File($this,"data"); 990 $file->create_file(); 991 $file = new File($this,"definition"); 992 $file->create_file(); 993 } else 994 $messages->add($tableName.getMyLang('err_tab_nam')); 995 } 996 $auditTrail->add_footer("Table"); 997 } 998/** 999* check if the row being inserted has been changed by another user 1000* 1001* @param number $recordPointer the record in question 1002* @returns boolean true if changed 1003* 1004*/ 1005 function hasChanged($p_id, $p_originals) { 1006 global $environment; 1007 global $messages; 1008 global $myLang; 1009// Get the current database values 1010 $this->get_all(); 1011// check all the original fields in this record 1012 $currentRecord =$this->get($p_id); 1013 $match=true; 1014// Compare $currentRecord->values with $p_originals 1015 $counter=0; 1016 foreach ($currentRecord->values as $currentValue) { 1017// check each field 1018 $counter++; 1019 if ($currentValue != $p_originals[$counter]) { 1020 $match=false; 1021 } 1022 } 1023// if the record does not match then return true - it has changed 1024 if (!$match) { 1025 $messages->add("****** ".getMyLang('err_lost_update') ." ******"); 1026 return true; 1027 } else { 1028// no problem so return false i.e. nothing has changed 1029 return false; 1030 } 1031 } 1032/** 1033* check if the row being inserted is unique or breaks the uniqueness of columns shown as unique 1034* 1035* @param array $values the values in the record 1036* @param number $recordPointer the record in question 1037* @returns boolean true if unique 1038* 1039*/ 1040 function isUnique($values,$recordPointer=0) { 1041 global $environment; 1042 global $messages; 1043 global $myLang; 1044 if ($recordPointer == 0) 1045 $thisMode="create"; 1046 else 1047 $thisMode="update"; 1048// populate if not already 1049 if (!$this->populated) $this->get_all(); 1050 $recordCounter = 0; 1051// check all the fields in each record 1052 foreach ($this->recordObjs as $record) { 1053 $recordCounter++; 1054 $match=true; 1055 $counter=0; 1056 foreach ($record->values as $value) { 1057// when updating - do not check the record itself 1058 if ($recordPointer!=$recordCounter) { 1059 $counter++; 1060// check each field 1061 if ($value != $values[$counter]) { 1062 $match=false; 1063 } 1064 } else 1065 $match=false; 1066// now check the unique columns 1067 if ($this->columnObjs[$counter]->unique == $environment->YES) { 1068 if ($values[$counter] == $value && $recordPointer != $recordCounter) { 1069 $messages->add('****** '.$this->columnObjs[$counter]->label." : ".getMyLang('err_dup_val') .' ******'); 1070 return false; 1071 } 1072 } 1073 } 1074// as soon as a record matches then return false 1075 if ($match) { 1076 $messages->add("****** ".getMyLang('err_dup_rec') ." ******"); 1077 return false; 1078 } 1079 } 1080// no match so return true 1081 return true; 1082 } 1083/** 1084* get the columns for this table 1085* 1086* @param none 1087* @returns array the columns 1088* 1089*/ 1090 function get_columns () { 1091 global $auditTrail; 1092 global $environment; 1093 $auditTrail->add_header('get_columns'); 1094 $definitionFile = new File($this, "definition"); 1095 $definitionFile->read_buffer(); 1096 $rowObjs=$definitionFile->rowObjs; 1097 $counter = 0; 1098 $columns = array(); 1099 foreach ($rowObjs as $rowObj) { 1100 $counter = $counter + 1; 1101 $fields = $rowObj->fields; 1102// Check on the visible, which may not be populated 1103 if ($fields[6] == '') $fields[6] = $environment->YES; 1104 if ($rowObj->raw>'') 1105 $columns[$counter] = 1106 new Column($counter, $fields[1],$fields[2],$fields[3],$fields[4], $fields[5], $fields[6]); 1107 } 1108 $auditTrail->add_footer('get_columns'); 1109 return $columns; 1110 } 1111/** 1112* filter the values in the table according to the values entered on the form 1113* 1114* @param array $filters array of filters to be applied 1115* @param array $sortedList the sorted list 1116* @returns array of strings 1117* 1118*/ 1119 function filter($filters,$sortedList) { 1120 $recCounter=0; 1121 $listCounter=0; 1122 global $display; 1123 global $environment; 1124 $filterExists = array(); 1125 $wildCardExists = array(); 1126 $wildCardAtStart = array(); 1127 $wildCardAtEnd = array(); 1128 1129 $display->debug_output("In filter recCounter= ".count($this->recordObjs)); 1130 $list=array(); 1131// Which fields should we look at? 1132 for ($colCounter=1; $colCounter<=count($this->columnObjs);$colCounter++) { 1133// Look at each field 1134 $type = $this->columnObjs[$colCounter]->type; 1135 $filterValue = $filters[$colCounter]; 1136 $filterExists [$colCounter] = false; 1137// check if there is a filter value for it 1138 if ($filterValue > ' ' ) { 1139 $filterExists [$colCounter] = true; 1140 if ($type= $environment->TYPE_STRING) { 1141 $posOfWildCard = strpos($filterValue, $environment->WILD_CARD); 1142 if ($posOfWildCard === false) $wildCardsExist [$colCounter] = false; 1143 else { 1144 $wildCardsExist [$colCounter] = true; 1145 $wildCardAtStart [$colCounter] = false; 1146 $wildCardAtEnd [$colCounter] = false; 1147// wildcard either at start or end or both 1148 if ($posOfWildCard == 0) { 1149 $wildCardAtStart [$colCounter] = true; 1150 } 1151 $posOfWildCard = strpos($filterValue, $environment->WILD_CARD,1); 1152 if ($posOfWildCard === false) $wildCardAtEnd [$colCounter] = false; 1153 else $wildCardAtEnd [$colCounter] = true; 1154 } 1155 } 1156 } 1157 } 1158// The list has already been sorted so we must filter the sorted list 1159 for( $recCounter=1; $recCounter<=count($this->recordObjs); $recCounter++) { 1160// Pick the item from the sorted list 1161 $recordObj = $this->recordObjs[$sortedList[$recCounter]]; 1162 $display->debug_output($recordObj->values[1]); 1163// Assume the row will be included unless it fails any of the filters 1164 $include=true; 1165// Test each value 1166 for ($colCounter=1;$colCounter<=count($this->columnObjs);$colCounter++) { 1167 $type = $this->columnObjs[$colCounter]->type; 1168 $ignore = false; 1169 if ($filterExists [$colCounter] ) { 1170 $value = $recordObj->values[$colCounter]; 1171// Offset fields with a value of zero are ignored since no selection has been made 1172 if ($value==0 && $type>$environment->LOOKUP_OFFSET) { 1173 $ignore = true; 1174 } 1175// As soon as any field fails the test we break out of the loop round the fields 1176 if (!$ignore) { 1177 if ($wildCardsExist[$colCounter]) { 1178 $filterValue = str_replace($environment->WILD_CARD,'',$filters[$colCounter]); 1179 $pos = strpos($value, $filterValue); 1180 if ($pos===false) { 1181 $include = false; 1182 break; 1183 } else { 1184//There is a wildcard and the string has been found but is it in the right place 1185 if ($wildCardAtEnd[$colCounter]) { 1186// If the wildcard is at the end then the find must be zero 1187 if ($pos!=0) { 1188 $include = false; 1189 break; 1190 } 1191 } 1192// if the wildcard is at the start then the last find must be at the end 1193// the search is in restToCheck then the last find is in restOfString 1194 if ($wildCardAtStart[$colCounter]) { 1195 $restToCheck = $value; 1196 $nextPos = $pos; 1197 while ($nextPos!=false) { 1198 $pos = $nextPos; 1199 $restOfString = substr($restToCheck, $nextPos); 1200 $restToCheck = substr($restToCheck, $nextPos+1); 1201 $nextPos= strpos($restToCheck, $filterValue); 1202 } 1203 if ($restOfString != $filterValue) { 1204 $include = false; 1205 break; 1206 } 1207 } 1208 } 1209 1210 } else { 1211// No wildcards so the test is simple - and if one fails we break out of the loop 1212 if ($filters[$colCounter] != $value) { 1213 $include=false; 1214 break; 1215 } 1216 } 1217 } 1218 } 1219 } 1220 if ($include) { 1221 $listCounter++; 1222 $list[$listCounter] = $recCounter; 1223 $display->debug_output("Adding record ".$recCounter); 1224 } 1225 } 1226 return $list; 1227 } 1228/** 1229* get all the records in this table 1230* 1231* @param none 1232* @returns row objects 1233* 1234*/ 1235 function get_all () { 1236 global $display; 1237 global $auditTrail; 1238 $auditTrail->add_header('get_all for table '.$this->name); 1239 $this->populated = true; 1240 $dataFile = new File($this,"data"); 1241 $dataFile->read_buffer(); 1242 $recCounter=0; 1243 $display->debug_output( "The contents of the table ".$this->name."=". $dataFile->buf); 1244 foreach($dataFile->rowObjs as $rowObj) { 1245 $recCounter=$recCounter + 1; 1246 $this->recordObjs[$recCounter] = new Record($this,$recCounter,$rowObj->fields); 1247 } 1248 $auditTrail->add_footer('get_all for table '.$this->name); 1249 return $dataFile->rowObjs; 1250 } 1251/** 1252* get a particular record 1253* 1254* @param number $p_id the record id 1255* @returns array of record objects 1256* 1257*/ 1258 function get($p_id) { 1259 global $display; 1260 $display->debug_output("Getting record with id=".$p_id." from table ".$this->name); 1261 return $this->recordObjs[$p_id]; 1262 } 1263/** 1264* create a new record 1265* 1266* @param array $p_values the values to be inserted into each column 1267* @returns none 1268* 1269*/ 1270 function create($p_values) { 1271 global $display; 1272 global $messages; 1273 if ($this->isUnique($p_values)) { 1274 $dataFile = new File($this,"data"); 1275 $dataFile->write_record($p_values); 1276 } 1277 } 1278/** 1279* update a record in this table 1280* 1281* @param number $p_id the id of the record to be updated 1282* @param array $p_values the values for each column 1283* @returns none 1284* 1285*/ 1286 function update($p_id,$p_values) { 1287 global $display; 1288 $display->debug_output("table:update : record ".$p_id." in table ".$this->name); 1289 $dataFile = new File($this,"data"); 1290 $dataFile->update($p_id, $p_values); 1291 } 1292/** 1293* delete a record in this table 1294* 1295* @param number $p_id the id of the record to be deleted 1296* @returns none 1297* 1298*/ 1299 function delete ($p_id) { 1300 $dataFile = new File($this,"data"); 1301 $dataFile->delete($p_id); 1302 } 1303} 1304/** 1305* ReferenceTable Class 1306* 1307* A sub-class of table specifically for the reference table 1308* 1309*/ 1310class ReferenceTable extends Table { 1311 var $list; 1312/** 1313* 1314* Constructor 1315* 1316* @param none 1317* @returns object the reference table contains the list 1318* 1319*/ 1320 function ReferenceTable ($id) { 1321 global $auditTrail; 1322 $auditTrail->add_header("ReferenceTable"); 1323 $this->Table($id); 1324 $this->get_all(); 1325 $counter=0; 1326 foreach ($this->recordObjs as $rec) { 1327 $this->list[$rec->values[1]] = $rec->values[2]; 1328 } 1329 $auditTrail->add_footer("ReferenceTable"); 1330 } 1331/** 1332* Get the list of lookups e.g. Gender, Title 1333* 1334* @param none 1335* @returns the list of lookups e.g. Gender 1336* 1337*/ 1338 function get_list () { 1339 return $this->list; 1340 } 1341} 1342/** 1343* Record Class 1344* 1345* Holds information on each record in each table 1346* 1347*/ 1348class Record { 1349 var $tableObj; 1350 var $id; 1351 var $values; 1352/** 1353* 1354* Constructor 1355* 1356* @param table object $p_tableObj the table to which this record belongs 1357* @param number $p_recordId the ID of the record 1358* @param array $p_values an array containing the fields 1359* @returns object 1360* 1361*/ 1362 function Record ($p_tableObj,$p_recordId,$p_values='') { 1363 global $auditTrail; 1364 $auditTrail->add_header('Record creation '.$p_tableObj->name); 1365 1366 $this->tableObj = $p_tableObj; 1367 $this->values = $p_values; 1368 if (count($p_values) < count($this->tableObj->columnObjs)) 1369 for ($counter=count($p_values)+1; $counter<=count($this->tableObj->columnObjs);$counter++) 1370 $this->values[$counter]=''; 1371 $this->id=$p_recordId; 1372 $auditTrail->add_footer('Record creation '.$p_tableObj->name); 1373 } 1374} 1375/** 1376* File Class 1377* 1378* Holds the information on a physical file 1379* 1380*/ 1381class File { 1382 var $name; 1383 var $buf; 1384 var $rowObjs = array(); 1385 var $CR ; 1386 var $ASCILF=10; 1387/** 1388* 1389* Constructor 1390* 1391* @param table object or string $p_tableObjOrName the table object to which this file belongs or the name of a non-database file 1392* @param string $type 'data' for a data file, 'definition' for a definition file and 'debug' for a log file 1393* @returns object 1394* 1395*/ 1396 function File ($p_tableObjOrName, $type) { 1397 global $environment; 1398 $this->CR= chr(13); 1399 if ($type == "data" || $type == "definition") 1400 $this->file_maker($p_tableObjOrName, $type); 1401// This is a general file create and the name has been passed as the first param 1402 else { 1403 $this->name = $environment->baseFolder.$environment->DICTIONARY_FOLDER.'/'.$p_tableObjOrName; 1404 } 1405 } 1406/** 1407* Extends the constructor for files associated with user tables as opposed 1408to debug files etc 1409* 1410* @param table object $p_tableObj 1411* @param string $type definition or data 1412* @returns object 1413* 1414*/ 1415 function file_maker($p_tableObj, $type) { 1416 global $environment; 1417 global $display; 1418 global $session; 1419 $dbFolder = $environment->get_folder($p_tableObj->id); 1420 if ($p_tableObj->isAdmin) { 1421 if ($type=="definition") 1422// v1.0.2 this was originally taken from a file - it is now a mix of hard-coding and $lang 1423 $this->name = 'definition.txt'; 1424 else 1425 $this->name = $dbFolder."definition.txt"; 1426 } 1427 else { 1428 if ($type=="definition") 1429 $this->name = $dbFolder."definition.txt"; 1430 else 1431 $this->name = $dbFolder."data.txt"; 1432 } 1433 $display->debug_output( "The file name = ".$this->name); 1434 } 1435/** 1436* Creates this file 1437* 1438* @param none 1439* @returns none 1440* 1441*/ 1442 function create_file() { 1443 global $messages; 1444 $handle = fopen($this->name,"w"); 1445 if (!$handle) 1446 $messages->add("Unable to open the file ".$this->name." when attempting to create it"); 1447 else 1448 fclose($handle); 1449 } 1450/** 1451* Deletes this file 1452* 1453* @param none 1454* @returns none 1455* 1456*/ 1457 function delete_file() { 1458 if ($this->exists()) 1459 unlink($this->name); 1460 } 1461/** 1462* Does this file exist 1463* 1464* @param none 1465* @returns boolean 1466* 1467*/ 1468 function exists () { 1469 if (file_exists($this->name)) 1470 return true; 1471 else 1472 return false; 1473 } 1474/** 1475* Reads in the contents of this file into rowObjs 1476* 1477* @param none 1478* @returns none 1479* 1480*/ 1481 function read_buffer () { 1482 global $display; 1483 global $auditTrail; 1484 global $messages; 1485 $auditTrail->add_header('read_buffer'); 1486// Intercept the admin definition 1487 if (!$this->exists()) { 1488 $messages->add('Unable to open the file '.$this->name.' when attempting to read'); 1489 } else { 1490 $handle = fopen($this->name,"r"); 1491 $display->debug_output( "<br>read_buffer opening ".$this->name); 1492 $buf = ''; 1493// The filesize is cached and should be cleared 1494 clearstatcache(); 1495 if (filesize($this->name) > 0 ) 1496 $buf = fread($handle,filesize($this->name)); 1497 fclose($handle); 1498 $auditTrail->add( "read in ".$buf); 1499 $this->buf = $buf; 1500// get the rows 1501 $rows = explode($this->CR,$buf); 1502// get the columns 1503 $counter = 0; 1504 foreach ($rows as $row) { 1505 if (ord(substr($row,0,1)) == $this->ASCILF) 1506 $row = substr($row,1); 1507 if (strlen($row)>0) { 1508 $counter = $counter + 1; 1509 $this->rowObjs[$counter] = new Row($row); 1510 } 1511 } 1512 $auditTrail->add_footer('read_buffer'); 1513 } 1514 } 1515/** 1516* writes record to this file 1517* 1518* @param array $p_values the values to be written into the columns of this new record 1519* @returns none 1520* 1521*/ 1522 function write_record ($p_values) { 1523 global $messages; 1524 global $environment; 1525 if ($this->exists()) { 1526 $handle = fopen($this->name,"a"); 1527 } else { 1528 $handle = fopen($this->name,"w"); 1529 } 1530 if (!$handle) { 1531 $messages->add('Unable to open the file '.$this->name.' when attempting to write'); 1532 } else { 1533 $sep=''; 1534 $buf=''; 1535 if (is_array($p_values)) { 1536 foreach($p_values as $value) { 1537 $buf.= $sep.$value; 1538 $sep=$environment->COLUMN_SEPARATOR; 1539 } 1540 } else { 1541 $buf.= $p_values; 1542 } 1543 if (fwrite ($handle,$buf.$this->CR) === FALSE) 1544 $messages->add('Error writing to the file '.$this->name); 1545 fclose($handle); 1546 } 1547 } 1548/** 1549* Deletes a record 1550* 1551* @param number $p_id ID of the record to be deleted 1552* @returns none 1553* 1554*/ 1555 function delete ($p_id) { 1556 global $messages; 1557 $this->read_buffer(); 1558 $handle = fopen($this->name,"w"); 1559 if (!$handle) { 1560 $messages->add("Unable to open the file ".$this->name." when attempting to delete"); 1561 } else { 1562 for ($counter=1;$counter<$p_id;$counter++) 1563 fwrite($handle,$this->rowObjs[$counter]->raw.$this->CR); 1564 1565// Skip the record 1566// Write the rest 1567 for ($counter=$p_id+1;$counter<=count($this->rowObjs);$counter++) 1568 fwrite($handle,$this->rowObjs[$counter]->raw.$this->CR); 1569 fclose($handle); 1570 } 1571 } 1572/** 1573* Update a record in this file 1574* 1575* @param number $p_id ID of the record to be deleted from the file 1576* @param array $p_values the values to be inserted into each column 1577* @returns none 1578* 1579*/ 1580 function update ($p_id, $p_values) { 1581 global $display; 1582 global $messages; 1583 global $environment; 1584 $display->debug_output( "file:update updating rec ".$p_id."in ".$this->name); 1585 $this->read_buffer(); 1586 $display->debug_output( "first line = ".$this->rowObjs[1]->raw); 1587 $handle = fopen($this->name,"w"); 1588 if (!$handle) 1589 $messages->add("Unable to open the file ".$this->name." when attempting to update"); 1590 else { 1591 for ($counter=1;$counter<$p_id;$counter++) 1592 fwrite($handle,$this->rowObjs[$counter]->raw.$this->CR); 1593// Create the record 1594 $sep=''; 1595 $buf=''; 1596 foreach($p_values as $value) { 1597 $buf.= $sep.$value; 1598 $sep=$environment->COLUMN_SEPARATOR; 1599 } 1600 fwrite ($handle,$buf); 1601 fwrite($handle,$this->CR); 1602//Write the rest 1603 for ($counter=$p_id+1;$counter<=count($this->rowObjs);$counter++) 1604 fwrite($handle,$this->rowObjs[$counter]->raw.$this->CR); 1605 fclose($handle); 1606 } 1607 } 1608} 1609/** 1610* Row Class 1611* 1612* Holds the information on a row in a file 1613* 1614*/ 1615class Row { 1616 var $fields = array(); 1617 var $raw; 1618/** 1619* 1620* Constructor 1621* 1622* @param srtring $row the raw data including the pip separator 1623* @returns object 1624* 1625*/ 1626 function Row($row) { 1627 global $auditTrail; 1628 global $environment; 1629 $auditTrail->add_header('Creating Row using '.$row); 1630 $this->raw = $row; 1631 $elements=explode($environment->COLUMN_SEPARATOR, $row); 1632 $counter = 0; 1633 foreach($elements as $element) { 1634 $counter = $counter + 1; 1635 $this->fields[$counter] = $element; 1636 $auditTrail->add('Element Number '.$counter.' = '.$element); 1637 } 1638 $auditTrail->add_footer('Creating Row '); 1639 } 1640} 1641/** 1642* Display Class 1643* 1644* Manages the display to the screen 1645* 1646*/ 1647class Display { 1648 var $debug=false ; 1649 var $IDX; 1650 var $currentSteps =0; 1651/** 1652* 1653* Constructor 1654* 1655* @param none 1656* @returns object 1657* 1658*/ 1659 function Display() { 1660 global $dbName; 1661 $this->IDX ='<input type="hidden" name="id" value="start" />'; 1662 $this->IDX .='<input type="hidden" name="idx" value="'.$dbName.'" 1663/>'; 1664 } 1665/** 1666* Displays the form for creating a record 1667* 1668* @param table object $tab the table in which the record will be created 1669* @param messages object $messages the messages object so that any errors are trapped and displayed 1670* @param string array $values the values to be placed in the fields in case there have been errors 1671* @returns none 1672* 1673*/ 1674 function create_form ($tab, $messages, $values='') { 1675 global $environment; 1676 global $myLang; 1677// Indent 1678 $this->output ('<div class="level2">'); 1679// The table name 1680 $this->output ('<h1>'.$tab->name.'</h1>'); 1681 if ($tab->isAdmin) $title = getMyLang('prompt_col'); 1682 else $title = getMyLang('prompt_rec'); 1683// The title ie. Creating Records 1684 $this->output ('<h2>'.getMyLang('prompt_cre').' '.$title.'</h2>'); 1685 if ($messages->exist) 1686 $messages->displayAll(); 1687// Indent 1688 $this->output ('<div class="level3">'); 1689 1690 $this->output ($this->form_start()); 1691 $this->output ('<table border=1>'); 1692 $counter=0; 1693 foreach($tab->columnObjs as $column) { 1694 $counter++; 1695 $this->output ('<tr>'); 1696 $this->output ('<th>'); 1697 $this->output ($column->label); 1698 $this->output ('</th>'); 1699 $this->output ('<td>'); 1700// If there were validation messages, redisplay values 1701 $name = "values".$counter; 1702 if (is_array($values)) $this->output($column->display_for_change($values[$counter],'create')); 1703 else 1704 $this->output($column->display_for_change('','create')); 1705 $this->output ('</td>'); 1706 $this->output ('</tr>'); 1707 } 1708 $this->output ('</table>'); 1709 $this->output ('<span style="white-space: nowrap;">'); // This form seems to behave differently from the others 1710 $this->output($this->button('insertAction',getMyLang('btn_cre_cre') ,false, $tab->displayId)); 1711 $this->output ($this->form_end()); 1712// The Home button 1713 $this->output($this->button('home',getMyLang('btn_home') ,true)); 1714// The Back button 1715 $this->output($this->button('listall',getMyLang('btn_back') ,true, $tab->displayId)); 1716 $this->output ('</span>'); 1717 $this->output('</div>'); 1718 $this->output ('</div>'); 1719 } 1720/** 1721* Displays the form for editing a record 1722* 1723* @param record object $p_recordObj the record to be edited 1724* @param messages object $messages the messages object so that any errors are trapped and displayed 1725* @param string array $values the values to be placed in the fields 1726* @returns none 1727* 1728*/ 1729 function edit_form($p_recordObj,$messages,$values='') { 1730// $p_recordObj has the current db values, $values has the values from the last editing (if they exist) 1731 global $environment; 1732 global $myLang; 1733 $tableObj=$p_recordObj->tableObj; 1734// Indent 1735 $this->output ('<div class="level2">'); 1736// The table name 1737 $this->output ('<h1>'.$tableObj->name.'</h1>'); 1738 if ($tab->isAdmin) $title = getMyLang('prompt_col'); 1739 else $title = getMyLang('prompt_rec'); 1740// The title ie. Creating Records 1741 $this->output ('<h2>'.getMyLang('prompt_edt').' '.$title.'</h2>'); 1742 if ($messages->exist) 1743 $messages->displayAll(); 1744 $columnObjs = $tableObj->columnObjs; 1745// Indent 1746 $this->output ('<div class="level3">'); 1747// Start the form 1748 $this->output ($this->form_start()); 1749// Start of table 1750 $this->output( "<table border=1>"); 1751 for($counter=1;$counter<count($columnObjs)+1;$counter++) { 1752 $column = $columnObjs[$counter]; 1753 $this->output('<tr>'); 1754 $this->output('<th>'); 1755 $this->output($columnObjs[$counter]->label); 1756 $this->output ('</th>'); 1757 $this->output ('<td>'); 1758 if (is_array($values)) 1759 $this->output($column->display_for_change($values[$counter],'update')); 1760 else 1761 $this->output($column->display_for_change($p_recordObj->values[$counter],'update')); 1762 $this->output('</td>'); 1763 $this->output('</tr>'); 1764 } 1765 $this->output('</table>'); 1766// Now for the original db values as hidden fields 1767 for($counter=1;$counter<count($columnObjs)+1;$counter++) { 1768 $column = $columnObjs[$counter]; 1769 $fieldName = "originals".$counter; 1770 $this->output($column->display_original($counter, $p_recordObj->values[$counter])); 1771 } 1772// Update button 1773 $this->output($this->button('updateAction',getMyLang('btn_edt_upd'),false, $tableObj->displayId,$p_recordObj->id)); 1774 $this->output($this->form_end()); 1775// The Home button 1776 $this->output($this->button('home',getMyLang('btn_home') ,true)); 1777// The Back button 1778 $this->output($this->button('listall',getMyLang('btn_back') ,true, $tableObj->displayId)); 1779 1780 $this->output('</div>'); 1781 $this->output('</div>'); 1782 } 1783/** 1784* Displays the form for deleting a record 1785* 1786* @param record object $p_recordObj the record to be deleted 1787* @param messages object $messages the messages object so that any errors are trapped and displayed 1788* @returns none 1789* 1790*/ 1791 function delete_form($p_recordObj,$messages) { 1792 global $environment; 1793 global $myLang; 1794 $tableObj=$p_recordObj->tableObj; 1795// Indent 1796 $this->output ('<div class="level2">'); 1797// The table name 1798 $this->output ('<h1>'.$tableObj->name.'</h1>'); 1799 if ($tableObj->isAdmin) $title = getMyLang('prompt_col'); 1800 else $title = getMyLang('prompt_rec'); 1801// The title ie. Deleting ..... 1802 $this->output ('<h2>'.getMyLang('prompt_del_rec').'</h2>'); 1803 if ($messages->exist) 1804 $messages->displayAll(); 1805 $columnObjs = $tableObj->columnObjs; 1806// Indent 1807 $this->output ('<div class="level3">'); 1808 $this->output ($this->form_start()); 1809 $this->output( "<table border=1>"); 1810// Display the contents 1811 for($counter=1;$counter<count($columnObjs)+1;$counter++) { 1812 $this->output('<tr>'); 1813 $this->output('<th>'); 1814 $this->output($columnObjs[$counter]->label); 1815 $this->output('</th>'); 1816 $this->output('<td>'); 1817 1818 $this->output($columnObjs[$counter]->display($p_recordObj->values[$counter])); 1819 $this->output('</td>'); 1820 $this->output('</tr>'); 1821 } 1822// Now for the original db values as hidden fields 1823 for($counter=1;$counter<count($columnObjs)+1;$counter++) { 1824 $column = $columnObjs[$counter]; 1825 $fieldName = "originals".$counter; 1826 $this->output($column->display_original($counter, $p_recordObj->values[$counter])); 1827 } 1828// Display the buttons 1829 $this->output('</table>'); 1830 $this->output($this->button('deleteAction',getMyLang('btn_del_cnf'),false, 1831 $tableObj->displayId,$p_recordObj->id)); 1832 $this->output ($this->form_end()); 1833// The Home button 1834 $this->output($this->button('home',getMyLang('btn_home') ,true)); 1835// The Back button 1836 $this->output($this->button('listall',getMyLang('btn_back') ,true, $tableObj->displayId)); 1837 $this->output('</div>'); 1838 $this->output ('</div>'); 1839 } 1840/** 1841* Displays all the records in a table for sorting, searching etc 1842* 1843* @param table object $tab the table whose contents are to be displayed 1844* @param array $list the contents to be displayed 1845* @param array $sortedList the sorted list of record IDs 1846* @param number $sortedColumnId the column on which it has been sorted 1847* @returns none 1848* 1849*/ 1850 function list_all($tab, $list,$sortedList='',$sortedColumnId=0) { 1851 global $environment; 1852 global $myLang; 1853 $numberOfCells = count($tab->columnObjs)+3; 1854 $this->output ('<div class="level2">'); 1855// The title 1856 $this->output ('<h1>'.$tab->name.'</h1>'); 1857// The Home button 1858 $this->output($this->button('home',getMyLang('btn_home') ,true)); 1859//The create button 1860 $prompt = getMyLang('btn_lst_cre_new_rec'); 1861 if ($tab->isAdmin) $prompt=getMyLang('btn_lst_cre_new_col'); 1862 $this->output($this->button('insertForm',$prompt,true, $tab->displayId)); 1863//The Admin button 1864 if (!$tab->isAdmin) { 1865 $this->output($this->button('admin',getMyLang('btn_adm_tab_str'),true, $tab->displayId)); 1866 } else { 1867 $this->output($this->button('listall',getMyLang('btn_lst_tab_cnt') ,true, $tab->id)); 1868 } 1869//************************************************************************************ 1870 1871 $this->output ($this->form_start()); 1872 $this->output ('<table class="inline">'); 1873 $colCounter=0; 1874 $this->output ('<thead>'); 1875 $this->output ('<tr>'); 1876// The No sort radio button 1877 $this->output ('<th align=center>'); 1878 $this->output (getMyLang('rad_lst_no_srt')); 1879 $toGo = '<input type="radio" name="sort" value="0"'; 1880 if ($sortedColumnId==0) 1881 $toGo .=' checked '; 1882 $toGo .= '/>'; 1883 $this->output ($toGo); 1884 $this->output ('</th>'); 1885 foreach($tab->columnObjs as $column) { 1886 $colCounter++; 1887 if ($column->isVisible) { 1888 $this->output ("<th>"); 1889// The Sort radio button 1890 $this->output ($column->label); 1891 $toGo = '<input type="radio" name="sort" value="'.$colCounter.'"'; 1892 if ($colCounter==$sortedColumnId) 1893 $toGo .=' checked '; 1894 $toGo .= '/>'; 1895 $this->output ($toGo); 1896 $this->output ('</th>'); 1897 } 1898 } 1899 $this->output ('</tr>'); 1900//The filter cells 1901 $this->output ('<tr>'); 1902// The Search row of filters and the Search button 1903 $colCounter=0; 1904 $this->output ('<td class="rightalign">'); 1905 $this->output($this->iconButton('list','search.png', getMyLang('btn_lst_srch_srt'), $tab->displayId)); 1906 $this->output ('</td>'); 1907 foreach($tab->columnObjs as $column) { 1908 $colCounter++; 1909 if ($column->isVisible) { 1910 $this->output ('<td>'); 1911 $this->output ($column->display_for_change('','search')); 1912 $this->output ('</td>'); 1913 } 1914 } 1915 $this->output ('</tr>'); 1916 $this->output ('</thead>'); 1917//************************************************************************************** 1918 $this->output ('<tbody>'); 1919// the rest of the main table 1920 $recCounter = 0; 1921 $columnCount=count($tab->columnObjs); 1922//The row begins 1923 for ($recCounter=1;$recCounter<=count($tab->recordObjs);$recCounter++) { 1924 $recPointer= $sortedList[$recCounter]; 1925 $record=$tab->recordObjs[$recPointer]; 1926//Check against the filter list 1927 $okToDisplay = false; 1928 if (in_array($recCounter,$list,true)) 1929 $okToDisplay = true; 1930 if ($okToDisplay) { 1931 $this->output ("<tr>"); 1932// Each column in the row 1933 $this->output ('<td>'); 1934// The Edit button 1935 $this->output($this->iconButton('updateForm','edit.png',getMyLang('btn_lst_edt'), $tab->displayId,$recPointer)); 1936 if (!$tab->isAdmin) { 1937// The Delete button 1938 $this->output($this->iconButton('deleteForm','delete.png',getMyLang('btn_lst_del'), $tab->displayId,$recPointer)); 1939 } 1940 $this->output ('</td>'); 1941// The columns displayed 1942 for ($fieldCounter=1;$fieldCounter<=$columnCount;$fieldCounter++) { 1943 $column = $tab->columnObjs[$fieldCounter]; 1944 if ($column->isVisible) { 1945 $value = $record->values[$fieldCounter]; 1946 $this->output ('<td>'); 1947 $this->output ($tab->columnObjs[$fieldCounter]->display($value)); 1948 $this->output ('</td>'); 1949 } 1950 } 1951 $this->output ("</tr>"); 1952 } 1953 } 1954 $this->output ('</tbody>'); 1955 $this->output ('</table>'); 1956 $this->output ($this->form_end()); 1957//************************************************************************************ 1958 $this->output ('</div>'); 1959 } 1960/** 1961* Displays the form for creating a new table 1962* 1963* @param none 1964* @returns none 1965* 1966*/ 1967 function createTableForm() { 1968 global $environment; 1969 global $messages; 1970 global $myLang; 1971 $this->output ('<h1>'.getMyLang('ttl_cre_tab').'</h1>'); 1972 if ($messages->exist) $messages->displayAll(); 1973 $this->output ('<table>'); 1974 $this->output ($this->form_start()); 1975 $this->output('<tr>'); 1976 $this->output('<td>'); 1977 $this->output(getMyLang('prompt_ent_tab_name')); 1978 $this->output('</td>'); 1979 $this->output('<td>'); 1980 $this->output('<input type="text" name="tableName" size=30 />'); 1981 $this->output('</td>'); 1982 $this->output('</tr>'); 1983 $this->output('</table>'); 1984 $this->output($this->button('createTable',getMyLang('btn_cre_new_tab'),false)); 1985 $this->output($this->form_end()); 1986// The Home button 1987 $this->output($this->button('home',getMyLang('btn_home') ,true)); 1988 } 1989/** 1990* Constructs the HTML form start tag 1991* 1992* @param none 1993* @returns string the HTML form end tag 1994* 1995*/ 1996 function form_start() { 1997 global $environment; 1998 $ret = '<form method="post" action="'.$environment->URL.'">'; 1999 return $ret; 2000 } 2001/** 2002* Displays a button if permitted 2003* 2004* @param string $action the action taken 2005* @param string $name the name of the button 2006* @param boolean $withTopAndTail true if the <form> and </form> are to be included 2007* @param number $table the ID of the table 2008* @param number $record the ID of the record 2009* @returns string The HTML required 2010* 2011*/ 2012 function button ($action, $name, $withTopAndTail=false, $table='', $record='') { 2013 $ret=''; 2014 global $session; 2015 global $auditTrail; 2016 $auditTrail->add_header('button action = '.$action.' name = '.$name); 2017 if ($session->allowed($action)) { 2018 if ($withTopAndTail) $ret .= $this->form_start(); 2019 $ret .= $this->IDX; 2020 $ret .='<input type="hidden" name="action" value="'.$action.'" />'; 2021 if ($table!='') $ret .= '<input type="hidden" name="table" value="'.$table.'" />'; 2022 if ($record!='') $ret .= '<input type="hidden" name="record" value="'.$record.'" />'; 2023 $ret .='<input type="submit" value="'.$name.'" '; 2024 $ret .= 'class="button" />'; 2025 if ($withTopAndTail) $ret .= $this->form_end(); 2026 } 2027 $auditTrail->add_footer('button action = '.$action.' name = '.$name); 2028 return $ret; 2029 } 2030/** 2031* Displays a button icon if permitted 2032* 2033* @param string $action the action taken 2034* @param string $image the image to be displayed 2035* @param string $title the title for the hint 2036* @param number $table the ID of the table 2037* @param number $record the ID of the record 2038* @returns string The HTML required 2039* 2040*/ 2041 function iconButton ($action, $image, $title, $table='', $record='') { 2042 $ret=''; 2043 global $session; 2044 global $auditTrail; 2045 global $environment; 2046 $auditTrail->add_header('button action = '.$action.' name = '.$name); 2047 if ($session->allowed($action)) { 2048 $ret .= $this->IDX; 2049 $ret .= '<input type="image" src="'.$environment->imagesFolder.$image.'" name="fn['.$action.']['.$table.$environment->COLUMN_SEPARATOR.$record.']" title="'.$title.'" alt="'.$title.'" />'; 2050 } 2051 $auditTrail->add_footer('iconButton action = '.$action.' name = '.$name); 2052 return $ret; 2053 } 2054/** 2055* Constructs the HTML form end tag 2056* 2057* @param none 2058* @returns string the HTML form end tag 2059* 2060*/ 2061 function form_end() { 2062 $ret ='</form>'; 2063 return $ret; 2064 } 2065/** 2066* Outputs/renders to the screen 2067* 2068* @param string $p_string the string to be output 2069* @param number $p_indent = -1 : reduce indent 2070* = 0 ; leave indent 2071* = +1 : increase indent 2072* @returns none 2073* 2074*/ 2075 function output ($p_string, $p_indent=0) { 2076 if ($p_indent==0) { 2077 if (substr($p_string,0,3)=='</t') $this->currentSteps--; 2078 } 2079 $INCREMENT = 2; // for the indent of the HTML 2080 2081 ptln( $p_string, $this->currentSteps*$INCREMENT); 2082 if ($p_indent==0) { 2083 if (substr($p_string,0,2)=='<t') $this->currentSteps++; 2084 } 2085 } 2086/** 2087* Outputs to the debug file if the debug flag is set to true 2088* 2089* @param string $p_string the string to be output 2090* @returns none 2091* 2092*/ 2093 function debug_output ($p_string) { 2094 global $environment; 2095 if ($this->debug) { 2096 $file = new File($environment->DEBUG_FILE,"debug"); 2097 $file->write_record($p_string); 2098 } 2099 } 2100/** 2101* the default screen 2102* 2103* @param none 2104* @returns none 2105* 2106*/ 2107 function wiki () { 2108 } 2109} 2110/** 2111* TestObj Class 2112* 2113* Used specifically for the sort 2114* 2115*/ 2116class TestObj { 2117 var $id; 2118 var $name; 2119/** 2120* 2121* Constructor 2122* 2123* @param number $id the ID of the element 2124* @param string $name the name of the element 2125* @returns object 2126* 2127*/ 2128 function TestObj($id,$name) 2129 { 2130 $this->id = $id; 2131 $this->name = $name; 2132 } 2133/** 2134* This is the static comparing function: 2135* 2136* @param string $a the string to be compared 2137* @param string $b the string to be compared 2138* @returns boolean 0 if =, 1 if a>b, else -1 2139* 2140*/ 2141 function cmp_obj($a, $b) 2142 { 2143 $al = strtolower($a->name); 2144 $bl = strtolower($b->name); 2145 if ($al == $bl) { 2146 return 0; 2147 } 2148 return ($al > $bl) ? +1 : -1; 2149 } 2150} 2151/** 2152* SortedArray Class 2153* 2154* Holds the sorted array specifically for sorting 2155* 2156*/ 2157class SortedArray { 2158 var $sortedList = array(); 2159/** 2160* 2161* Constructor 2162* 2163* @param array $list the array to be sorted 2164* @returns object 2165* 2166*/ 2167 function SortedArray($list) { 2168 $recCounter=0; 2169 foreach($list as $entry) { 2170 $recCounter++; 2171 $toBeSorted[]=new TestObj($recCounter,$entry); 2172 } 2173 usort ($toBeSorted,array("TestObj","cmp_obj")); 2174 $counter=0; 2175 foreach($toBeSorted as $testObj) { 2176 $counter++; 2177 $this->sortedList[$counter] = $testObj->id; 2178 } 2179 } 2180} 2181/** 2182* Main program which takes the appropriate action 2183* 2184* @param none 2185* @returns none 2186* 2187*/ 2188function action_db() { 2189 global $environment; 2190 global $display; 2191 global $session; 2192 global $IDX; 2193 global $dbName; 2194 global $messages; 2195 global $auditTrail; 2196 global $myLang; 2197// Set up by action.php 2198 global $action; 2199 global $tableId; 2200 global $recordId; 2201 2202 $display = new Display(); 2203 $auditTrail = new AuditTrail(); 2204 $INFO = pageinfo(); 2205 $auditTrail->add_header("action_db"); 2206 $auditTrail->add('action = '.$action.' table = '.$tableId.' record = '.$recordId); 2207 $messages = new Messages(); 2208// Check whether the debug flag is set 2209 if (isset($_REQUEST['debug'])) { 2210 if ($_REQUEST['debug']=='yes') { 2211 $file=new File($environment->DEBUG_FILE,"debug"); 2212 $file->create_file(); 2213 $display->debug=true; 2214 } elseif ($_REQUEST['debug']=='no') { 2215 $file=new File($environment->DEBUG_FILE,"debug"); 2216 $file->delete_file(); 2217 $display->debug=false; 2218 } 2219 } 2220 $session = new Session(); 2221// Check if it has come from the wiki directly 2222 if ($action =='') { 2223// It has come directly from the wiki 2224 $action = "listall"; 2225 $command = substr($IDX,strlen($dbName)+1); 2226 $tableId = substr($command,0,2); 2227// Pick up the Create Table option 2228 if ($IDX==$dbName.':'.$environment->DICTIONARY_FOLDER) 2229 $action='createTableForm'; 2230 else { 2231// make sure all is OK 2232 $tab=new Table($tableId); 2233// if there was a problem then report it 2234 if ($messages->exist) 2235 $action="messages"; 2236 } 2237 } 2238 $auditTrail->add("action=".$action); 2239// Check whether the user can carry out this action 2240 if (!$session->allowed($action)) { 2241 $action= "message"; 2242 $message=getMyLang('msg_wrn_priv'); 2243 $messages->add($message); 2244 $action = "messages"; 2245 } 2246 $auditTrail->add("action=".$action); 2247// Now handle the various actions 2248// action = messages 2249 if ($action=="messages") 2250 $messages->displayAll(); 2251// action = home 2252 if ($action == "home") { 2253 $display->wiki(); 2254 } 2255// action = createTable 2256 if ($action == "createTable") { 2257 $tableName = ''; 2258 if (isset($_REQUEST["tableName"])) 2259 $tableName = $_REQUEST["tableName"]; 2260 if ($tableName > '') { 2261 $tab = new Table($tableName); 2262 } else { 2263 $messages->add(getMyLang('msg_wrn_tab_nam') ); 2264 } 2265 if ($messages->exist) { 2266 $action = "createTableForm"; 2267 } else { 2268 $tableId = - $tab->id; 2269 $messages->add(getMyLang('msg_tab_cre')); 2270 $action = "insertForm"; 2271 } 2272 } 2273// action = admin 2274 if ($action=="admin") { 2275 $auditTrail->add("action=".$action." tableId is ".$tableId."will be negative"); 2276 $tableId = - $tableId; 2277 $action="listall"; 2278 } 2279// action = insertAction 2280 if ($action == "insertAction") { 2281 global $display; 2282 $tab=new Table ($tableId); 2283 for ($counter=1;$counter<=count($tab->columnObjs);$counter++) { 2284 $test="values".$counter; 2285 if (isset($_REQUEST[$test])) { 2286 $values[$counter]= $_REQUEST[$test]; 2287 $column = $tab->columnObjs[$counter]; 2288 $column->validate($values[$counter], $messages); 2289 $values[$counter] = $column->toDatabase($values[$counter]); 2290 } 2291 } 2292 $display->debug_output ( "val=".$values[1]." and ".$values[2]); 2293 if ($messages->exist) { 2294 $action = "insertForm"; 2295 } else { 2296 $tab->create($values); 2297 if ($messages->exist) 2298 $action="insertForm"; 2299 else 2300 $action="listall"; 2301 } 2302 } 2303// action = updateAction 2304 if ($action == "updateAction") { 2305 global $display; 2306 $tab=new Table ($tableId); 2307 $done = false; 2308 $display->debug_output ("main:update action: table= ".$tab->name); 2309 for ($counter=1;$counter<=count($tab->columnObjs);$counter++) { 2310 $column = $tab->columnObjs[$counter]; 2311// Get the changed values from the form 2312 $test="values".$counter; 2313 if (isset($_REQUEST[$test])) { 2314 $values[$counter]= $_REQUEST[$test]; 2315 $column->validate($values[$counter], $messages); 2316 $values[$counter] = $column->toDatabase($values[$counter]); 2317 } 2318// Now to get the originals 2319 $test="originals".$counter; 2320 if (isset($_REQUEST[$test])) { 2321 $originals[$counter]= $_REQUEST[$test]; 2322 } 2323 } 2324// The array values now has the values after being changed 2325// $originals has the original values stored as hidden fields on the form 2326 if ($messages->exist) { 2327// Problems with the validation so try again 2328 $action = "updateForm"; 2329 } else { 2330 if (!$tab->isUnique($values,$recordId)) { 2331 $action = "updateForm"; 2332 } else { 2333 if ($tab->hasChanged($recordId, $originals)) { 2334 $values = ''; // to force the refresh of the values in the screen 2335 $action = "updateForm"; 2336 } else { 2337 $tab->update($recordId, $values); 2338 if ($messages->exist) { 2339// Problems with the update so try again 2340 $action = "updateForm"; 2341 } else { 2342 $action="listall"; 2343 } 2344 } 2345 } 2346 } 2347 } 2348// action = deleteAction 2349 if ($action == "deleteAction") { 2350 global $display; 2351 $tab=new Table ($tableId); 2352 $display->debug_output ("main:delete action: table= ".$tab->name); 2353 for ($counter=1;$counter<=count($tab->columnObjs);$counter++) { 2354 $column = $tab->columnObjs[$counter]; 2355// Now to get the originals 2356 $test="originals".$counter; 2357 if (isset($_REQUEST[$test])) { 2358 $originals[$counter] = $_REQUEST[$test]; 2359 } 2360 } 2361 if ($tab->hasChanged($recordId, $originals)) { 2362 $action = "deleteForm"; 2363 } else { 2364 $tab->delete($recordId); 2365 if ($messages->exist) 2366// Problems with the delete so try again 2367 $action = "deleteForm"; 2368 else 2369 $action = "listall"; 2370 } 2371 } 2372// action = list or listall 2373 if ($action == "list" || $action == "listall") { 2374 $auditTrail->add("action=".$action." tableId is ".$tableId); 2375 $tab=new Table ($tableId); 2376 $tab->get_all(); 2377 $sortedColumnId=0; 2378 $filters=array(); 2379 $sortedList = array(); 2380// **************** Any Sorting ? ************************************************ 2381 if (isset($_REQUEST["sort"]) && $_REQUEST["sort"]>'0') { 2382 $sortedColumnId = $_REQUEST["sort"]; 2383// Prepare the sort array in $list 2384// If this is a link column then we should sort on the name of the link, i.e. the last element 2385 if ($tab->columnObjs[$sortedColumnId]->type == $environment->TYPE_EXTERNAL_LINK 2386 ||$tab->columnObjs[$sortedColumnId]->type == $environment->TYPE_INTERNAL_LINK) { 2387 $counter=0; 2388 foreach($tab->recordObjs as $recordObj) { 2389 $counter++; 2390 $value = $recordObj->values[$sortedColumnId]; 2391 $elements=explode($environment->COLON, $value); 2392 $name=$elements[count($elements)-1]; 2393 $list[$counter] = $name; 2394 } 2395 } 2396// If this is a reference column then sort on the second column in the reference table 2397 elseif ($tab->columnObjs[$sortedColumnId]->type >= $environment->REFERENCE_OFFSET) { 2398 $refTableID = $tab->columnObjs[$sortedColumnId]->type - $environment->REFERENCE_OFFSET; 2399 $refTable = new ReferenceTable($refTableID); 2400 $baseList = $refTable->get_list(); 2401 $counter = 0; 2402 foreach($tab->recordObjs as $recordObj) { 2403 $counter++; 2404 $list[$counter] = $baseList[$recordObj->values[$sortedColumnId]]; 2405 } 2406// Any other type just sort on that column 2407 } else { 2408 $counter=0; 2409 foreach($tab->recordObjs as $recordObj) { 2410 $counter++; 2411 $list[$counter] = $recordObj->values[$sortedColumnId]; 2412 } 2413 } 2414// now do the sorting - the results are in sortedList as pointers 2415 $sortedListObj = new SortedArray($list); 2416 $sortedList = $sortedListObj->sortedList; 2417 } else { 2418// No Sorting required just put consecutive integers in $sortedList 2419 $counter=0; 2420 foreach ($tab->recordObjs as $recordObj) { 2421 $counter++; 2422 $sortedList[$counter] = $counter; 2423 } 2424 } 2425//check if any filters have been applied but not if it's listall 2426 if ($action != "listall") { 2427 for ($counter=1;$counter<=count($tab->columnObjs);$counter++) { 2428 $test="values".$counter; 2429 if (isset($_REQUEST[$test])) 2430 $filters[$counter]= $_REQUEST[$test]; 2431 else $filters[$counter]=''; 2432 } 2433 } 2434 $list=$tab->filter($filters,$sortedList); 2435 $display->list_all($tab, $list, $sortedList, $sortedColumnId); 2436 } 2437// action = createTableForm 2438 if ($action == 'createTableForm' ) { 2439 $display->createTableForm(); 2440 } 2441// action = insertForm 2442 if ($action == "insertForm") { 2443 $auditTrail->add("Calling new Table with id = ".$tableId); 2444 $tab=new Table ($tableId); 2445 $display->create_form($tab,$messages,$values); 2446 } 2447// action = updateForm 2448 if ($action == "updateForm") { 2449 $tab=new Table ($tableId); 2450// If messages are empty then this must be the first time so store the originals 2451 if ($tab->possibleReference) { 2452 $messages->add(getMyLang('msg_ref_tab_wng_1')); 2453 $messages->add(getMyLang('msg_ref_tab_wng_2')); 2454 $messages->add(getMyLang('msg_ref_tab_wng_3')); 2455 } 2456 $tab->get_all(); 2457 $rec=$tab->get($recordId); 2458 $display->edit_form($rec,$messages,$values); 2459 } 2460// action = deleteForm 2461 if ($action == "deleteForm") { 2462 $tab=new Table ($tableId); 2463 if ($tab->possibleReference) { 2464 $messages->add(getMyLang('msg_ref_tab_wng_1')); 2465 $messages->add(getMyLang('msg_ref_tab_wng_2')); 2466 $messages->add(getMyLang('msg_ref_tab_wng_3')); 2467 } 2468 $tab->get_all(); 2469 $rec=$tab->get($recordId); 2470 $display->delete_form($rec, $messages); 2471 } 2472 $auditTrail->add_footer("action_db"); 2473} 2474/** 2475* Get the translated element in $lang 2476* 2477* @param $id1 first id of the lang element 2478* @param $id2 second id of the lang element 2479* @param $id3 third id of the lang element 2480* @returns string translation 2481* 2482*/ 2483function getMyLang($id1,$id2='',$id3='') { 2484 global $myLang; 2485 if ($id3>'') $value = $myLang[$id1][$id2][$id3]; 2486 elseif ($id2>'') $value = $myLang[$id1][$id2]; 2487 else $value = $myLang[$id1]; 2488 2489 return utf8_encode($value); 2490} 2491?> 2492