1<?php 2 /******************************** 3 OSBib: 4 A collection of PHP classes to create and manage bibliographic formatting for OS bibliography software 5 using the OSBib standard. 6 7 Released through http://bibliophile.sourceforge.net under the GPL licence. 8 Do whatever you like with this -- some credit to the author(s) would be appreciated. 9 10 If you make improvements, please consider contacting the administrators at bibliophile.sourceforge.net 11 so that your improvements can be added to the release package. 12 13 Mark Grimshaw 2005 14 http://bibliophile.sourceforge.net 15 ********************************/ 16 17 /** Description of class BIBFORMAT 18 * Format a bibliographic resource for output. 19 * 20 * @author Mark Grimshaw 21 * @version 1 22 */ 23class BIBFORMAT 24{ 25 /** 26 * $dir is the path to STYLEMAP.php etc. 27 */ 28 function BIBFORMAT($dir = FALSE, $bibtex = FALSE, $preview = FALSE) 29 { 30 //05/05/2005 G.GARDEY: add a last "/" to $stylePath if not present. 31 $this->preview = $preview; 32 if(!$this->preview) // Not javascript preview 33 { 34 $dir = trim($dir); 35 if(!$dir){ 36 $this->dir = dirname(__FILE__) . "/"; 37 } 38 else{ 39 $this->dir = $dir; 40 if($dir[strlen($dir)-1] != "/"){ 41 $this->dir .= "/"; 42 } 43 } 44 $this->bibtexParsePath = $this->dir . "format/bibtexParse"; 45 } 46 else // preview 47 $this->dir = ''; 48 $this->bibtex = $bibtex; 49 if($this->bibtex) 50 { 51 include_once($this->dir."STYLEMAPBIBTEX.php"); 52 $this->styleMap = new STYLEMAPBIBTEX(); 53 } 54 else 55 { 56 include_once($this->dir."STYLEMAP.php"); 57 $this->styleMap = new STYLEMAP(); 58 } 59 include_once($this->dir."UTF8.php"); 60 $this->utf8 = new UTF8(); 61 /** 62 * Highlight preg pattern and CSS class for HTML display 63 */ 64 $this->patterns = FALSE; 65 $this->patternHighlight = FALSE; 66 /** 67 * Output medium: 68 * Defaul 'html' 69 */ 70 $this->output = 'html'; 71 $this->previousCreator = ''; 72 /** 73 * Switch editor and author positions in the style definition for a book in which there are only editors 74 */ 75 $this->editorSwitch = FALSE; 76 /** 77 * Load month arrays 78 */ 79 $this->loadArrays(); 80 /** 81 * Convert the entry to produce utf8 82 * Defaut: 'FALSE', we assume that the entries are already clean 83 */ 84 $this->convertEntry=FALSE; 85 } 86 /** 87 * Read the chosen bibliographic style and create arrays based on resource type. 88 * 89 * @author Mark Grimshaw 90 * @version 1 91 * 92 * @param $stylePath The path where the styles are. 93 * @param $style The requested bibliographic output style. 94 * @return BOOLEAN 95 */ 96 function loadStyle($stylePath, $style) 97 { 98 //05/05/2005 G.GARDEY: add a last "/" to $stylePath if not present. 99 $stylePath = trim($stylePath); 100 if($stylePath[strlen($stylePath)-1] != "/"){ 101 $stylePath .= "/"; 102 } 103 $uc = $stylePath . strtolower($style) . "/" . strtolower($style) . ".xml"; 104 $lc = $stylePath . strtolower($style) . "/" . strtoupper($style) . ".xml"; 105 $styleFile = file_exists($uc) ? $uc : $lc; 106 if(!$fh = fopen($styleFile, "r")) 107 return array(FALSE, FALSE, FALSE); 108 include_once($this->dir."PARSEXML.php"); 109 $parseXML = new PARSEXML($this); 110 list($info, $citation, $common, $types) = $parseXML->extractEntries($fh); 111 fclose($fh); 112 return array($info, $citation, $common, $types); 113 } 114 /** 115 * Transform the raw data from the XML file into usable arrays 116 * 117 * @author Mark Grimshaw 118 * @version 1 119 * 120 * @param $common Array of global formatting data 121 * @param $types Array of style definitions for each resource type 122 */ 123 function getStyle($common, $types) 124 { 125 $this->commonToArray($common); 126 $this->typesToArray($types); 127 } 128 /** 129 * Reformat the array representation of common styling into a more useable format. 130 * 'common' styling refers to formatting that is common to all resource types such as creator formatting, title 131 * capitalization etc. 132 * 133 * @author Mark Grimshaw 134 * @version 1 135 * 136 * @param $common nodal array representation of XML data 137 * @return flattened array representation for easier use. 138 */ 139 function commonToArray($common) 140 { 141 foreach($common as $array) 142 { 143 if(array_key_exists('_NAME', $array) && array_key_exists('_DATA', $array)) 144 $this->style[$array['_NAME']] = $array['_DATA']; 145 } 146 } 147 /** 148 * Reformat the array representation of resource types into arrays based on the type. 149 * 150 * @param $types nodal array representation of XML data 151 */ 152 function typesToArray($types) 153 { 154 foreach($types as $resourceArray) 155 { 156 /** 157 * The resource type which will be our array name 158 */ 159 $type = $resourceArray['_ATTRIBUTES']['name']; 160 $styleDefinition = $resourceArray['_ELEMENTS']; 161 foreach($styleDefinition as $array) 162 { 163 if(array_key_exists('_NAME', $array) && array_key_exists('_DATA', $array) 164 && array_key_exists('_ELEMENTS', $array)) 165 { 166 if($array['_NAME'] == 'fallbackstyle') 167 { 168 $this->fallback[$type] = $array['_DATA']; 169 break; 170 } 171 if($array['_NAME'] == 'ultimate') 172 { 173 $this->{$type}['ultimate'] = $array['_DATA']; 174 continue; 175 } 176 foreach($array['_ELEMENTS'] as $elements) 177 { 178 if($array['_NAME'] == 'independent') 179 { 180 $split = split("_", $elements['_NAME']); 181 $this->{$type}[$array['_NAME']][$split[1]] 182 = $elements['_DATA']; 183 } 184 else 185 $this->{$type}[$array['_NAME']][$elements['_NAME']] 186 = $elements['_DATA']; 187 } 188 } 189 } 190 /** 191 * Backup each $this->$type array. If we need to switch editors, it's faster to restore each 192 * $this->$type array from this backup than to reload the style file and parse it. 193 */ 194 if(isset($this->$type)) 195 $this->backup[$type] = $this->$type; 196 } 197 } 198 /** 199 * Restore each $this->type array from $this->backup 200 * 201 * @author Mark Grimshaw 202 * @version 1 203 */ 204 function restoreTypes() 205 { 206 foreach($this->backup as $type => $array) 207 $this->$type = $array; 208 } 209 /** 210 * Perform pre-processing on the raw SQL array 211 * 212 * @author Mark Grimshaw 213 * @version 1 214 * 215 * @param $type The resource type 216 * @param $row Associate array of raw SQL data 217 * @return $row Processed row of raw SQL data 218 */ 219 function preProcess($type, $row) 220 { 221 /** 222 * Ensure that $this->item is empty for each resource!!!!!!!!!! 223 */ 224 $this->item = array(); 225 // Map this system's resource type to OSBib's resource type 226 $this->type = array_search($type, $this->styleMap->types); 227 if($this->bibtex && array_key_exists('author', $row)) 228 { 229 $row['creator1'] = $row['author']; 230 unset($row['author']); 231 } 232 if($this->bibtex && array_key_exists('editor', $row)) 233 { 234 $row['creator2'] = $row['editor']; 235 unset($row['editor']); 236 } 237 /** 238 * Set any author/editor re-ordering for book and book_article type. 239 */ 240 if(!$this->preview && (($type == 'book') || ($type == 'book_article')) && 241 $row['creator2'] && !$row['creator1'] && $this->style['editorSwitch'] && 242 array_key_exists('author', $this->$type)) 243 { 244 $row['creator1'] = $row['creator2']; 245 $row['creator2'] = FALSE; 246 include_once($this->dir . "PARSESTYLE.php"); 247 $editorArray = PARSESTYLE::parseStringToArray($type, $this->style['editorSwitchIfYes'], 248 $this->styleMap); 249 if(!empty($editorArray) && array_key_exists('editor', $editorArray)) 250 { 251 $this->{$type}['author'] = $editorArray['editor']; 252 unset($this->{$type}['editor']); 253 $this->editorSwitch = TRUE; 254 } 255 } 256 /** 257 * If $row comes in in BibTeX format, process and add items to $this->item 258 */ 259 if($this->bibtex) 260 { 261 if(!$this->type) 262 { 263 list($type, $row) = $this->preProcessBibtex($row, $type); 264 } else 265 list($type, $row) = $this->preProcessBibtex($row, $this->type); 266 } 267 /** 268 * Ensure that for theses types, the first letter of type and label are capitalized (e.g. 'Master's Thesis'). 269 */ 270 if($type == 'thesis') 271 { 272 if(($key = array_search('type', $this->styleMap->$type)) !== FALSE) 273 { 274 if(isset($row[$key])) 275 $row[$key] = ucfirst($row[$key]); 276 } 277 if(($key = array_search('label', $this->styleMap->$type)) !== FALSE) 278 { 279 if(isset($row[$key])) 280 $row[$key] = ucfirst($row[$key]); 281 } 282 } 283 /** 284 * Set to catch-all generic style. For all keys except named database fields, creator1 and year1, 285 * we only print if the value in $this->styleMap matches the value in 286 * $this->styleMap->generic for each key. 287 */ 288 if(!isset($this->$type)) 289 { 290 $fallback = $this->fallback[$type]; 291 $type = $fallback; 292 } 293 $this->type = $type; 294 /** 295 * Add BibTeX entry to $this->item 296 */ 297 if($this->bibtex) 298 { 299 foreach($row as $field => $value) 300 { 301 if(array_key_exists($field, $this->styleMap->$type) && 302 !array_key_exists($this->styleMap->{$type}[$field], $this->item)) 303 $this->addItem($row[$field], $field); 304 } 305 } 306 return $row; 307 } 308 /** 309 * Preprocess BibTeX-type entries 310 * @author Mark Grimshaw 311 * @version 1 312 * 313 * @param assoc. array of elements for one bibtex entry 314 * @param string resource type 315 * @return string resource type 316 * @return array resource assoc. array of elements for one bibtex entry 317 */ 318 function preProcessBibtex(&$row, $type) 319 { 320 //05/05/2005 G.GARDEY: change bibtexParse name. 321 /** 322 * This set of includes is for the OSBib public release and should be uncommented for that and 323 * the WIKINDX-specific includes below commented out! 324 */ 325 include_once($this->bibtexParsePath . "/PARSECREATORS.php"); 326 $parseCreator = new PARSECREATORS(); 327 include_once($this->bibtexParsePath . "/PARSEMONTH.php"); 328 $parseDate = new PARSEMONTH(); 329 include_once($this->bibtexParsePath . "/PARSEPAGE.php"); 330 $parsePages = new PARSEPAGE(); 331 332 // WIKINDX naming of above files 333 /* 334 include_once($this->bibtexParsePath . "/BIBTEXCREATORPARSE.php"); 335 $parseCreator = new BIBTEXCREATORPARSE(); 336 include_once($this->bibtexParsePath . "/BIBTEXMONTHPARSE.php"); 337 $parseDate = new BIBTEXMONTHPARSE(); 338 include_once($this->bibtexParsePath . "/BIBTEXPAGEPARSE.php"); 339 $parsePages = new BIBTEXPAGEPARSE(); 340 341 342 343 */ 344 // Added by Christophe Ambroise: convert the bibtex entry to utf8 (for storage or printing) 345 if ($this->cleanEntry) {$row=$this->convertEntry($row);} 346 // 347 348 349 /** 350 * Bibtex-specific types not defined in STYLEMAPBIBTEX 351 */ 352 353 if(!$this->type) 354 { 355 if($type == 'mastersthesis') 356 { 357 $type = 'thesis'; 358 $row['type'] = "Master's Dissertation"; 359 } 360 if($type == 'phdthesis') 361 { 362 $type = 'thesis'; 363 $row['type'] = "PhD Thesis"; 364 } 365 else if($type == 'booklet') 366 $type = 'miscellaneous'; 367 else if($type == 'conference') 368 $type = 'proceedings_article'; 369 else if($type == 'incollection') 370 $type = 'book_article'; 371 else if($type == 'manual') 372 $type = 'report'; 373 } 374 /** 375 * 'article' could be journal, newspaper or magazine article 376 */ 377 else if($type == 'journal_article') 378 { 379 if(array_key_exists('month', $row) && array_key_exists('date', $this->styleMap->$type)) 380 { 381 list($startMonth, $startDay, $endMonth, $endDay) = $parseDate->init($row['month']); 382 if($startDay) 383 $type = 'newspaper_article'; 384 else if($startMonth) 385 $type = 'magazine_article'; 386 $this->formatDate($startDay, $startMonth, $endDay, $endMonth); 387 } 388 else 389 $type = 'journal_article'; 390 } 391 /** 392 * Is this a web article? 393 */ 394 else if(($type == 'miscellaneous') && array_key_exists('howpublished', $row)) 395 { 396 if(preg_match("#^\\\url{(.*://.*)}#", $row['howpublished'], $match)) 397 { 398 $row['URL'] = $match[1]; 399 $type = 'web_article'; 400 } 401 } 402 $this->type = $type; 403 if(array_key_exists('creator1', $row) && $row['creator1'] && 404 array_key_exists('creator1', $this->styleMap->$type)) 405 { 406 $creators = $parseCreator->parse($row['creator1']); 407 foreach($creators as $cArray) 408 { 409 $temp[] = array( 410 'surname' => trim($cArray[2]), 411 'firstname' => trim($cArray[0]), 412 'initials' => trim($cArray[1]), 413 'prefix' => trim($cArray[3]), 414 ); 415 } 416 $this->formatNames($temp, 'creator1'); 417 unset($temp); 418 } 419 if(array_key_exists('creator2', $row) && $row['creator2'] && 420 array_key_exists('creator2', $this->styleMap->$type)) 421 { 422 $creators = $parseCreator->parse($row['creator2']); 423 foreach($creators as $cArray) 424 { 425 $temp[] = array( 426 'surname' => trim($cArray[2]), 427 'firstname' => trim($cArray[0]), 428 'initials' => trim($cArray[1]), 429 'prefix' => trim($cArray[3]), 430 ); 431 } 432 $this->formatNames($temp, 'creator2'); 433 } 434 if(array_key_exists('pages', $row) && array_key_exists('pages', $this->styleMap->$type)) 435 { 436 list($start, $end) = $parsePages->init($row['pages']); 437 $this->formatPages(trim($start), trim($end)); 438 } 439 $this->formatTitle($row['title'], "{", "}"); 440 return array($type, $row); 441 } 442 /** 443 * Map the $item array against the style array ($this->$type) for this resource type and produce a string ready to be 444 * formatted for bold, italics etc. 445 * 446 * @author Mark Grimshaw 447 * @version 1 448 * 449 * @param $template If called from CITEFORMAT, this is the array of template elements. 450 * @return string ready for printing to the output medium. 451 */ 452 function map($template = FALSE) 453 { 454 /** 455 * Output medium: 456 * 'html', 'rtf', or 'plain' 457 */ 458 include_once($this->dir . "format/EXPORTFILTER.php"); 459 $this->export = new EXPORTFILTER($this, $this->output); 460 if($template) 461 { 462 $this->citation = $template; 463 $this->type = 'citation'; 464 } 465 $type = $this->type; 466 $ultimate = ''; 467 $index = 0; 468 $previousFieldExists = $nextFieldExists = TRUE; 469 if(array_key_exists('independent', $this->$type)) 470 $independent = $this->{$type}['independent']; 471 /** 472 * For dependency on next field, we must grab array keys of $this->$type, shift the first element then, in the loop, 473 * check each element exists in $item. If it doesn't, $nextFieldExists is set to FALSE 474 */ 475 $checkPost = array_keys($this->$type); 476 array_shift($checkPost); 477 foreach($this->$type as $key => $value) 478 { 479 if($key == 'ultimate') 480 { 481 $ultimate = $value; 482 continue; 483 } 484 if(!array_key_exists($key, $this->item) || !$this->item[$key]) 485 { 486 $keyNotExists[] = $index; 487 $index++; 488 array_shift($checkPost); 489 $previousFieldExists = FALSE; 490 continue; 491 } 492 $checkPostShift = array_shift($checkPost); 493 if(!array_key_exists($checkPostShift, $this->item) || !$this->item[$checkPostShift]) 494 $nextFieldExists = FALSE; 495 $pre = array_key_exists('pre', $value) ? $value['pre'] : ''; 496 $post = array_key_exists('post', $value) ? $value['post'] : ''; 497 /** 498 * Deal with __DEPENDENT_ON_PREVIOUS_FIELD__ for characters dependent on previous field's existence and 499 * __DEPENDENT_ON_NEXT_FIELD__ for characters dependent on the next field's existence 500 */ 501 if($previousFieldExists && array_key_exists('dependentPre', $value)) 502 $pre = preg_replace("/__DEPENDENT_ON_PREVIOUS_FIELD__/", 503 $value['dependentPre'], $pre); 504 else if(array_key_exists('dependentPreAlternative', $value)) 505 $pre = preg_replace("/__DEPENDENT_ON_PREVIOUS_FIELD__/", 506 $value['dependentPreAlternative'], $pre); 507 else 508 $pre = preg_replace("/__DEPENDENT_ON_PREVIOUS_FIELD__/", '', $pre); 509 if($nextFieldExists && array_key_exists('dependentPost', $value)) 510 $post = str_replace("__DEPENDENT_ON_NEXT_FIELD__", 511 $value['dependentPost'], $post); 512 else if(array_key_exists('dependentPostAlternative', $value)) 513 $post = preg_replace("/__DEPENDENT_ON_NEXT_FIELD__/", 514 $value['dependentPostAlternative'], $post); 515 else 516 $post = preg_replace("/__DEPENDENT_ON_NEXT_FIELD__/", '', $post); 517 /** 518 * Deal with __SINGULAR_PLURAL__ for creator lists and pages 519 */ if($styleKey = array_search($key, $this->styleMap->$type)) 520 $pluralKey = $styleKey . "_plural"; 521 if(isset($this->$pluralKey) && $this->$pluralKey) // plural alternative for this key 522 { 523 $pre = array_key_exists('plural', $value) ? 524 preg_replace("/__SINGULAR_PLURAL__/", $value['plural'], $pre) : $pre; 525 $post = array_key_exists('plural', $value) ? 526 preg_replace("/__SINGULAR_PLURAL__/", $value['plural'], $post) : $post; 527 } 528 else if(isset($this->$pluralKey)) // singular alternative for this key 529 { 530 $pre = array_key_exists('singular', $value) ? 531 preg_replace("/__SINGULAR_PLURAL__/", $value['singular'], $pre) : $pre; 532 $post = array_key_exists('singular', $value) ? 533 preg_replace("/__SINGULAR_PLURAL__/", $value['singular'], $post) : $post; 534 } 535 /** 536 * Make sure we don't have duplicate punctuation characters 537 */ $lastPre = substr($post, -1); 538 $firstItem = substr($this->item[$key], 0, 1); 539 if($firstItem === $lastPre) 540 $this->item[$key] = substr($this->item[$key], 1); 541 $firstPost = substr($post, 0, 1); 542 $lastItem = substr($this->item[$key], -1); 543 // if(preg_match("/\.|,|;|:\?!/", $lastItem) && preg_match("/\.|,|;|:|\?|!/", $firstPost)) 544 if(preg_match("/\.|,|;|:\?!/", $lastItem) && ($firstPost == $lastItem)) 545 $post = substr($post, 1); // take a guess at removing first character of $post 546 /** 547 * Strip backticks used in template 548 */ 549 $pre = str_replace("`", '', $pre); 550 $post = str_replace("`", '', $post); 551 $pre = ($this->output == 'html') ? $this->utf8->utf8_htmlspecialchars($pre) : $pre; 552 $post = ($this->output == 'html') ? $this->utf8->utf8_htmlspecialchars($post) : $post; 553 if($this->item[$key]) 554 $itemArray[$index] = $pre . $this->item[$key] . $post; 555 $previousFieldExists = $nextFieldExists = TRUE; 556 $index++; 557 } 558 /** 559 * Check for independent characters. These (should) come in pairs. 560 */ if(isset($independent)) 561 { 562 $independentKeys = array_keys($independent); 563 while($independent) 564 { 565 $preAlternative = $postAlternative = FALSE; 566 $startFound = $endFound = FALSE; 567 $pre = array_shift($independent); 568 $post = array_shift($independent); 569 if(preg_match("/%(.*)%(.*)%|%(.*)%/U", $pre, $dependent)) 570 { 571 if(sizeof($dependent) == 4) 572 $pre = $dependent[3]; 573 else 574 { 575 $pre = $dependent[1]; 576 $preAlternative = $dependent[2]; 577 } 578 } 579 if(preg_match("/%(.*)%(.*)%|%(.*)%/U", $post, $dependent)) 580 { 581 if(sizeof($dependent) == 4) 582 $post = $dependent[3]; 583 else 584 { 585 $post = $dependent[1]; 586 $postAlternative = $dependent[2]; 587 } 588 } 589 /** 590 * Strip backticks used in template 591 */ 592 $preAlternative = str_replace("`", '', $preAlternative); 593 $postAlternative = str_replace("`", '', $postAlternative); 594 $firstKey = array_shift($independentKeys); 595 $secondKey = array_shift($independentKeys); 596 for($index = $firstKey; $index <= $secondKey; $index++) 597 { 598 if(array_key_exists($index, $itemArray)) 599 { 600 $startFound = $index; 601 break; 602 } 603 } 604 for($index = $secondKey; $index >= $firstKey; $index--) 605 { 606 if(array_key_exists($index, $itemArray)) 607 { 608 $endFound = $index; 609 break; 610 } 611 } 612 if(($startFound !== FALSE) && ($endFound !== FALSE)) // intervening fields found 613 { 614 $itemArray[$startFound] = $pre . $itemArray[$startFound]; 615 $itemArray[$endFound] = $itemArray[$endFound] . $post; 616 } 617 else // intervening fields not found - do we have an alternative? 618 { 619 if(array_key_exists($firstKey - 1, $itemArray) && $preAlternative) 620 $itemArray[$firstKey - 1] .= $preAlternative; 621 if(array_key_exists($secondKey + 1, $itemArray) && $postAlternative) 622 $itemArray[$secondKey + 1] = $postAlternative . 623 $itemArray[$secondKey + 1]; 624 } 625 } 626 } 627 $pString = join('', $itemArray); 628 /** 629 * if last character is punctuation (which it may be with missing fields etc.), and $ultimate is also 630 * punctuation, remove last character. 631 */ if(isset($ultimate) && $ultimate) 632 { 633 $last = substr(trim($pString), -1); 634 /** 635 * Don't do ';' in case last element is URL with > ...! 636 */ 637 if(preg_match("/^\.|^,||^:^\?^\!/", $ultimate) && preg_match("/\.|,|:|\?|!/", $last)) 638 $pString = substr(trim($pString), 0, -1); 639 } 640 // If $this->editorSwitch, we have altered $this->$bibformat->$type so need to reload styles 641 if($this->editorSwitch) 642 { 643 $this->restoreTypes(); 644 $this->editorSwitch = FALSE; 645 } 646 return $this->export->format(trim($pString) . $ultimate); 647 } 648 /** 649 * Format creator name lists (authors, editors, etc.) 650 * 651 * @author Mark Grimshaw 652 * @version 1 653 * 654 * @param $creators Multi-associative array of creator names e.g. this array might be of 655 * the primary authors: 656 * <pre> 657 * array([0] => array(['surname'] => 'Grimshaw', ['firstname'] => Mark, ['initials'] => 'N', ['prefix'] => ), 658 * [1] => array(['surname'] => 'Witt', ['firstname'] => Jan, ['initials'] => , ['prefix'] => 'de')) 659 * </pre> 660 * @param $nameType 'creator1', 'creator2' etc. If $nameType == 'citation', this method is called 661 * from CITEFORMAT for formatting citation creators in which case we expect the 3rd parameter $citation. 662 * @param $citation If called from CITEFORMAT, this is the array of citation stylings. 663 * @return Optional if $nameType == 'citation': formatted string of all creator names in the input array. 664 */ 665 function formatNames($creators, $nameType, $citation = FALSE) 666 { 667 $style = $citation ? $citation : $this->style; 668 $first = TRUE; 669 /** 670 * Set default plural behaviour for creator lists 671 */ 672 $pluralKey = $nameType . "_plural"; 673 $this->$pluralKey = FALSE; 674 // $this->creator1_plural = $this->creator2_plural = 675 // $this->creator3_plural = $this->creator4_plural = $this->creator5_plural = FALSE; 676 /** 677 * Citation creators 678 */ 679 if($nameType == 'citation') 680 { 681 $limit = 'creatorListLimit'; 682 $moreThan = 'creatorListMore'; 683 $abbreviation = 'creatorListAbbreviation'; 684 $initialsStyle = 'creatorInitials'; 685 $firstNameInitial = 'creatorFirstName'; 686 $delimitTwo = 'twoCreatorsSep'; 687 $delimitFirstBetween = 'creatorSepFirstBetween'; 688 $delimitNextBetween = 'creatorSepNextBetween'; 689 $delimitLast = 'creatorSepNextLast'; 690 $uppercase = 'creatorUppercase'; 691 $italics = 'creatorListAbbreviationItalic'; 692 if($first) 693 $nameStyle = 'creatorStyle'; 694 else 695 $nameStyle = 'creatorOtherStyle'; 696 } 697 /** 698 * Primary creator 699 */ 700 else if($nameType == 'creator1') 701 { 702 $limit = 'primaryCreatorListLimit'; 703 $moreThan = 'primaryCreatorListMore'; 704 $abbreviation = 'primaryCreatorListAbbreviation'; 705 $initialsStyle = 'primaryCreatorInitials'; 706 $firstNameInitial = 'primaryCreatorFirstName'; 707 $delimitTwo = 'primaryTwoCreatorsSep'; 708 $delimitFirstBetween = 'primaryCreatorSepFirstBetween'; 709 $delimitNextBetween = 'primaryCreatorSepNextBetween'; 710 $delimitLast = 'primaryCreatorSepNextLast'; 711 $uppercase = 'primaryCreatorUppercase'; 712 $italics = 'primaryCreatorListAbbreviationItalic'; 713 if($first) 714 $nameStyle = 'primaryCreatorFirstStyle'; 715 else 716 $nameStyle = 'primaryCreatorOtherStyle'; 717 } 718 else 719 { 720 $limit = 'otherCreatorListLimit'; 721 $moreThan = 'otherCreatorListMore'; 722 $abbreviation = 'otherCreatorListAbbreviation'; 723 $initialsStyle = 'otherCreatorInitials'; 724 $firstNameInitial = 'otherCreatorFirstName'; 725 $delimitTwo = 'otherTwoCreatorsSep'; 726 $delimitFirstBetween = 'otherCreatorSepFirstBetween'; 727 $delimitNextBetween = 'otherCreatorSepNextBetween'; 728 $delimitLast = 'otherCreatorSepNextLast'; 729 $uppercase = 'otherCreatorUppercase'; 730 $italics = 'otherCreatorListAbbreviationItalic'; 731 if($first) 732 $nameStyle = 'otherCreatorFirstStyle'; 733 else 734 $nameStyle = 'otherCreatorOtherStyle'; 735 } 736 $type = $this->type; 737 foreach($creators as $creator) 738 { 739 $firstName = trim($this->checkInitials($creator, $style[$initialsStyle], 740 $style[$firstNameInitial])); 741 $prefix = $creator['prefix'] ? trim(stripslashes($creator['prefix'])) . ' ' : ''; 742 if($style[$nameStyle] == 0) // Joe Bloggs 743 { 744 $nameString = $firstName . ' ' . 745 $prefix . 746 stripslashes($creator['surname']); 747 } 748 else if($style[$nameStyle] == 1) // Bloggs, Joe 749 { 750 $prefixDelimit = $firstName ? ', ' : ''; 751 $nameString = 752 stripslashes($creator['prefix']) . ' ' . 753 stripslashes($creator['surname']) . $prefixDelimit . 754 $firstName; 755 } 756 else if($style[$nameStyle] == 2) // Bloggs Joe 757 { 758 $nameString = 759 stripslashes($creator['prefix']) . ' ' . 760 stripslashes($creator['surname']) . ' ' . 761 $firstName; 762 } 763 else // Last name only 764 { 765 $nameString = 766 stripslashes($creator['prefix']) . ' ' . 767 stripslashes($creator['surname']); 768 } 769 if(isset($style[$uppercase])) 770 $nameString = $this->utf8->utf8_strtoupper($nameString); 771 $cArray[] = trim($nameString); 772 $first = FALSE; 773 } 774 /** 775 * Keep only some elements in array if we've exceeded $moreThan 776 */ 777 $etAl = FALSE; 778 if($style[$limit] && (sizeof($cArray) > $style[$moreThan])) 779 { 780 array_splice($cArray, $style[$limit]); 781 if(isset($style[$italics])) 782 $etAl = "[i]" . $style[$abbreviation] . "[/i]"; 783 else 784 $etAl = $style[$abbreviation]; 785 } 786 /** 787 * add delimiters 788 */ 789 if(sizeof($cArray) > 1) 790 { 791 if(sizeof($cArray) == 2) 792 $cArray[0] .= $style[$delimitTwo]; 793 else 794 { 795 for($index = 0; $index < (sizeof($cArray) - 2); $index++) 796 { 797 if(!$index) 798 $cArray[$index] .= $style[$delimitFirstBetween]; 799 else 800 $cArray[$index] .= $style[$delimitNextBetween]; 801 } 802 $cArray[sizeof($cArray) - 2] .= $style[$delimitLast]; 803 } 804 } 805 /** 806 * If sizeof of $cArray > 1 or $etAl != FALSE, set this $nameType_plural to TRUE 807 */ 808 if((sizeof($cArray) > 1) || $etAl) 809 { 810 $pluralKey = $nameType . "_plural"; 811 $this->$pluralKey = TRUE; 812 } 813 /** 814 * Finally flatten array 815 */ 816 if($etAl) 817 $pString = implode('', $cArray) . $etAl; 818 else 819 $pString = implode('', $cArray); 820 /** 821 * Check for repeating primary creator list in subsequent bibliographic item. 822 */ 823 if($nameType == 'creator1') 824 { 825 $tempString = $pString; 826 if(($style['primaryCreatorRepeat'] == 2) && ($this->previousCreator == $pString)) 827 $pString = $style['primaryCreatorRepeatString']; 828 else if(($style['primaryCreatorRepeat'] == 1) && 829 ($this->previousCreator == $pString)) 830 $pString = ''; // don't print creator list 831 $this->previousCreator = $tempString; 832 } 833 else if($nameType == 'citation') 834 return $pString; 835 $this->item[$this->styleMap->{$type}[$nameType]] = $pString; 836 } 837 /** 838 * Handle initials. 839 * @see formatNames() 840 * 841 * @author Mark Grimshaw 842 * @version 1 843 * 844 * @param $creator Associative array of creator name e.g. 845 * <pre> 846 * array(['surname'] => 'Grimshaw', ['firstname'] => Mark, ['initials'] => 'M N G', ['prefix'] => )) 847 * </pre> 848 * Initials must be space-delimited. 849 * 850 * @param $initialsStyle 851 * @param $firstNameInitial 852 * @return Formatted string of initials. 853 */ 854 function checkInitials(&$creator, $initialsStyle, $firstNameInitial) 855 { 856 /** 857 * Format firstname 858 */ 859 if($creator['firstname'] && !$firstNameInitial) // Full name 860 $firstName = stripslashes($creator['firstname']); 861 else if($creator['firstname']) // Initial only of first name. 'firstname' field may actually have several 'firstnames' 862 { 863 $fn = split(" ", stripslashes($creator['firstname'])); 864 $firstTime = TRUE; 865 foreach($fn as $name) 866 { 867 if($firstTime) 868 { 869 // May be the first name is a hyphenated name 870 // We separate each part of the name separated by a - 871 $fn2 = split("-", trim($name)); 872 $firstNameInitialMake = ""; 873 foreach($fn2 as $nameparts) 874 { 875 if ($firstNameInitialMake != "") 876 { 877 $firstNameInitialMake .= "-"; 878 } 879 $firstNameInitialMake .= $this->utf8->utf8_strtoupper($this->utf8->utf8_substr($nameparts, 0, 1)); 880 $firstTime = FALSE; 881 } 882 } 883 else 884 $initials[] = $this->utf8->utf8_strtoupper($this->utf8->utf8_substr(trim($name), 0, 1)); 885 } 886 if(isset($initials)) 887 { 888 if($creator['initials']) 889 $creator['initials'] = join(" " , $initials) . ' ' . $creator['initials']; 890 else 891 $creator['initials'] = join(" " , $initials); 892 } 893 } 894 /** 895 * Initials are stored as space-delimited characters. 896 * If no initials, return just the firstname or its initial in the correct format. 897 */ 898 if(!$creator['initials']) 899 { 900 if(isset($firstName)) // full first name only 901 return $firstName; 902 if(isset($firstNameInitialMake) && $initialsStyle > 1) // First name initial with no '.' 903 return $firstNameInitialMake; 904 if(isset($firstNameInitialMake)) // First name initial with '.' 905 { 906 // If the name is hyphaned, we have to add a . after each initial. 907 $fn2 = split("-", $firstNameInitialMake); 908 $firstNameInitialMakeResult = ""; 909 foreach($fn2 as $initial) 910 { 911 if ($firstNameInitialMakeResult != "") 912 { 913 $firstNameInitialMakeResult .= "-"; 914 } 915 $firstNameInitialMakeResult .= $initial . "."; 916 } 917 return $firstNameInitialMakeResult; 918 } 919 return ''; // nothing here 920 } 921 $initialsArray = explode(' ', $creator['initials']); 922 /** 923 * If firstname is initial only, prepend to array 924 */ 925 if(isset($firstNameInitialMake)) 926 array_unshift($initialsArray, $firstNameInitialMake); 927 if($initialsStyle == 0) // 'T. U. ' 928 $initials = implode('. ', $initialsArray) . '.'; 929 else if($initialsStyle == 1) // 'T.U.' 930 $initials = implode('.', $initialsArray) . '.'; 931 else if($initialsStyle == 2) // 'T U ' 932 $initials = implode(' ', $initialsArray); 933 else // 'TU ' 934 $initials = implode('', $initialsArray); 935 /** 936 * If we have a full first name, prepend it to $initials. 937 */ 938 if(isset($firstName)) 939 return ($firstName . ' ' . $initials); 940 return $initials; 941 } 942 /** 943 * Add an item to $this->item array 944 * 945 * @author Mark Grimshaw 946 * @version 1 947 * 948 * @param $item The item to be added. 949 * @param $fieldName The database fieldName of the item to be added 950 */ 951 function addItem($item, $fieldName) 952 { 953 $type = $this->type; 954 if($item === FALSE) 955 return; 956 /** 957 * This item may already exist (e.g. edition field for WIKINDX) 958 */ 959 if(isset($this->item) && array_key_exists($this->styleMap->{$type}[$fieldName], $this->item)) 960 return FALSE; 961 $this->item[$this->styleMap->{$type}[$fieldName]] = $item; 962 } 963 /** 964 * Add all remaining items to $this->item array 965 * 966 * @author Mark Grimshaw 967 * @version 1 968 * 969 * @param $row The items to be added. 970 */ 971 function addAllOtherItems($row) 972 { 973 $type = $this->type; 974 foreach($row as $field => $value) 975 { 976 if(array_key_exists($field, $this->styleMap->$type) && 977 !array_key_exists($this->styleMap->{$type}[$field], $this->item)) 978 $this->addItem($row[$field], $field); 979 } 980 } 981 /** 982 * Format a title. Anything enclosed in $delimitLeft...$delimitRight is to be left unchanged 983 * 984 * @author Mark Grimshaw 985 * @version 1 986 * 987 * @param $pString Raw title string. 988 * @param $delimitLeft 989 * @param $delimitRight 990 * @return Formatted title string. 991 */ 992 function formatTitle($pString, $delimitLeft = FALSE, $delimitRight = FALSE) 993 { 994 if(!$delimitLeft) 995 $delimitLeft = '{'; 996 if(!$delimitRight) 997 $delimitRight = '}'; 998 $delimitLeft = preg_quote($delimitLeft); 999 $delimitRight = preg_quote($delimitRight); 1000 $match = "/" . $delimitLeft . "/"; 1001 $type = $this->type; 1002 if(!array_key_exists('title', $this->styleMap->$type)) 1003 $this->item[$this->styleMap->{$type}['title']] = ''; 1004 /** 1005 * '0' == 'Osbib Bibliographic Formatting' 1006 * '1' == 'Osbib bibliographic formatting' 1007 */ 1008 if($this->style['titleCapitalization']) 1009 { 1010 // Something here (preg_split probably) interferes with UTF-8 encoding (data is stored in 1011 // the database as UTF-8 as long as web browser charset == UTF-8). 1012 // So first decode then encode back to UTF-8 at end. 1013 // There is a 'u' UTF-8 parameter for preg_xxx but it doesn't work. 1014 $pString = $this->utf8->decodeUtf8($pString); 1015 $newString = ''; 1016 while(preg_match($match, $pString)) 1017 { 1018 $array = preg_split("/(.*)$delimitLeft(.*)$delimitRight(.*)/U", 1019 $pString, 2, PREG_SPLIT_DELIM_CAPTURE); 1020 /** 1021 * in case user has input {..} incorrectly 1022 */ 1023 if(sizeof($array) == 1) 1024 break; 1025 $newString .= $this->utf8->utf8_strtolower($this->utf8->encodeUtf8($array[1])) . $array[2]; 1026 $pString = $array[4]; 1027 } 1028 $newString .= $this->utf8->utf8_strtolower($this->utf8->encodeUtf8($pString)); 1029 } 1030 $pString = isset($newString) ? $newString : $pString; 1031 $title = $this->utf8->encodeUtf8($this->utf8->utf8_ucfirst(trim($pString))); 1032 $this->item[$this->styleMap->{$type}['title']] = 1033 ($this->output == 'html') ? $this->utf8->utf8_htmlspecialchars($title) : $title; 1034 } 1035 /** 1036 * Format pages. 1037 * $this->style['pageFormat']: 1038 * 0 == 132-9 1039 * 1 == 132-39 1040 * 2 == 132-139 1041 * 1042 * @author Mark Grimshaw 1043 * @version 1 1044 * 1045 * @param $start Page start. 1046 * @param $end Page end. 1047 * @param $citation If called from CITEFORMAT, this is the array of citation stylings. 1048 * @return string of pages. 1049 */ 1050 function formatPages($start, $end = FALSE, $citation = FALSE) 1051 { 1052 $type = $this->type; 1053 $style = $citation ? $citation : $this->style; 1054 /** 1055 * Set default plural behaviour for pages 1056 */ 1057 $this->pages_plural = FALSE; 1058 /** 1059 * If no page end, return just $start; 1060 */ 1061 if(!$end) 1062 { 1063 $this->item[$this->styleMap->{$type}['pages']] = $start; 1064 return; 1065 } 1066 /** 1067 * Pages may be in roman numeral format etc. Return unchanged 1068 */ 1069 if(!is_numeric($start)) 1070 { 1071 $this->item[$this->styleMap->{$type}['pages']] = $start . '-' . $end; 1072 return; 1073 } 1074 /** 1075 * We have multiple pages... 1076 */ 1077 $this->pages_plural = TRUE; 1078 /** 1079 * They've done something wrong so give them back exactly what they entered 1080 */ 1081 if(($end <= $start) || (strlen($end) < strlen($start))) 1082 { 1083 $this->item[$this->styleMap->{$type}['pages']] = $start . '-' . $end; 1084 return; 1085 } 1086 else if($style['pageFormat'] == 2) 1087 { 1088 $this->item[$this->styleMap->{$type}['pages']] = $start . '-' . $end; 1089 return; 1090 } 1091 else 1092 { 1093 /** 1094 * We assume page numbers are not into the 10,000 range - if so, return the complete pages 1095 */ 1096 if(strlen($start) <= 4) 1097 { 1098 $startArray = preg_split('//', $start); 1099 array_shift($startArray); // always an empty element at start? 1100 array_pop($startArray); // always an empty array element at end? 1101 if($style['pageFormat'] == 0) 1102 { 1103 array_pop($startArray); 1104 $endPage = substr($end, -1); 1105 $index = -2; 1106 } 1107 else 1108 { 1109 array_pop($startArray); 1110 array_pop($startArray); 1111 $endPage = substr($end, -2); 1112 $index = -3; 1113 } 1114 while(!empty($startArray)) 1115 { 1116 $startPop = array_pop($startArray); 1117 $endSub = substr($end, $index--, 1); 1118 if($endSub == $startPop) 1119 { 1120 $this->item[$this->styleMap->{$type}['pages']] 1121 = $start . '-' . $endPage; 1122 return; 1123 } 1124 if($endSub > $startPop) 1125 $endPage = $endSub . $endPage; 1126 } 1127 } 1128 else 1129 { 1130 $this->item[$this->styleMap->{$type}['pages']] = $start . '-' . $end; 1131 return; 1132 } 1133 } 1134 /** 1135 * We should never reach here - in case we do, give back complete range so that something at least is printed 1136 */ 1137 $this->item[$this->styleMap->{$type}['pages']] = $start . '-' . $end; 1138 } 1139 /** 1140 * Format runningTime for film/broadcast 1141 * 1142 * @author Mark Grimshaw 1143 * @version 1 1144 * 1145 * @param $minutes 1146 * @param $hours 1147 */ 1148 function formatRunningTime($minutes, $hours) 1149 { 1150 $type = $this->type; 1151 if($this->style['runningTimeFormat'] == 0) // 3'45" 1152 { 1153 if(isset($minutes) && $minutes) 1154 { 1155 if($minutes < 10) 1156 $minutes = '0' . $minutes; 1157 $runningTime = $hours . "'" . $minutes . "\""; 1158 } 1159 else 1160 $runningTime = $hours . "'00\""; 1161 } 1162 else if($this->style['runningTimeFormat'] == 1) // 3:45 1163 { 1164 if(isset($minutes) && $minutes) 1165 { 1166 if($minutes < 10) 1167 $minutes = '0' . $minutes; 1168 $runningTime = $hours . ":" . $minutes; 1169 } 1170 else 1171 $runningTime = $hours . ":00"; 1172 } 1173 else if($this->style['runningTimeFormat'] == 1) // 3,45 1174 { 1175 if(isset($minutes) && $minutes) 1176 { 1177 if($minutes < 10) 1178 $minutes = '0' . $minutes; 1179 $runningTime = $hours . "," . $minutes; 1180 } 1181 else 1182 $runningTime = $hours . ",00"; 1183 } 1184 else if($this->style['runningTimeFormat'] == 3) // 3 hours, 45 minutes 1185 { 1186 $hours = ($hours == 1) ? $hours . " hour" : $hours . " hours"; 1187 if(isset($minutes) && $minutes) 1188 { 1189 $minutes = ($minutes == 1) ? $minutes . " minute" : $minutes . " minutes"; 1190 $runningTime = $hours . ", " . $minutes; 1191 } 1192 else 1193 $runningTime = $hours; 1194 } 1195 else if($this->style['runningTimeFormat'] == 4) // 3 hours and 45 minutes 1196 { 1197 $hours = ($hours == 1) ? $hours . " hour" : $hours . " hours"; 1198 if(isset($minutes) && $minutes) 1199 { 1200 $minutes = ($minutes == 1) ? $minutes . " minute" : $minutes . " minutes"; 1201 $runningTime = $hours . " and " . $minutes; 1202 } 1203 else 1204 $runningTime = $hours; 1205 } 1206 $this->item[$this->styleMap->{$type}['runningTime']] = $runningTime; 1207 } 1208 /** 1209 * Format date 1210 * 1211 * @author Mark Grimshaw 1212 * @version 2 1213 * 1214 * @param INT $startDay 1215 * @param INT $startMonth 1216 * @param INT $endDay 1217 * @param INT $sendMonth 1218 */ 1219 function formatDate($startDay, $startMonth, $endDay, $endMonth) 1220 { 1221 $type = $this->type; 1222 if($startDay !== FALSE) 1223 { 1224 if($this->style['dayFormat']) // e.g. 10th 1225 $startDay = $this->cardinalToOrdinal($startDay); 1226 else if($startDay < 10) 1227 $startDay = '0' . $startDay; 1228 } 1229 if($endDay !== FALSE) 1230 { 1231 if($this->style['dayFormat']) // e.g. 10th 1232 $endDay = $this->cardinalToOrdinal($endDay); 1233 else if($endDay < 10) 1234 $endDay = '0' . $endDay; 1235 } 1236 if($this->style['monthFormat'] == 1) // Full month name 1237 $monthArray = $this->longMonth; 1238 else if($this->style['monthFormat'] == 2) // User-defined 1239 { 1240 for($i = 1; $i <= 12; $i++) 1241 $monthArray[$i] = $this->style["userMonth_$i"]; 1242 } 1243 else // Short month name 1244 $monthArray = $this->shortMonth; 1245 if($startMonth !== FALSE) 1246 $startMonth = $monthArray[$startMonth]; 1247 if($endMonth !== FALSE) 1248 $endMonth = $monthArray[$endMonth]; 1249 if(!$endMonth) 1250 { 1251 if($this->style['dateFormat']) // Order == Month Day 1252 { 1253 $startDay = ($startDay === FALSE) ? '' : ' ' . $startDay; 1254 $date = $startMonth . $startDay; 1255 } 1256 else // Order == Day Month 1257 { 1258 $startDay = ($startDay === FALSE) ? '' : $startDay . ' '; 1259 $date = $startDay . $startMonth; 1260 } 1261 } 1262 else // date range 1263 { 1264 if(!$startDay) 1265 $delimit = $this->style['dateRangeDelimit2']; 1266 else 1267 $delimit = $this->style['dateRangeDelimit1']; 1268 if(($endMonth !== FALSE) && ($startMonth == $endMonth) && ($this->style['dateRangeSameMonth'] == 1)) 1269 { 1270 $endMonth = FALSE; 1271 if(!$endDay) 1272 $delimit = FALSE; 1273 } 1274 if($this->style['dateFormat']) // Order == Month Day 1275 { 1276 $startDay = ($startDay === FALSE) ? '' : ' ' . $startDay; 1277 $startDate = $startMonth . $startDay; 1278 if($endMonth) 1279 $endDate = $endMonth . $endDay = ($endDay === FALSE) ? '' : ' ' . $endDay; 1280 else 1281 $endDate = $endDay; 1282 } 1283 else // Order == Day Month 1284 { 1285 if($endMonth) 1286 { 1287 $startDate = $startDay . ' ' . $startMonth; 1288 $endDate = $endDay = ($endDay === FALSE) ? '' : $endDay . ' '; 1289 $endDate .= $endMonth; 1290 } 1291 else 1292 { 1293 $startDate = $startDay; 1294 $endDate = ($endDay === FALSE) ? ' ' : $endDay . ' '; 1295 $endDate .= $startMonth; 1296 } 1297 } 1298 $date = $startDate . $delimit . $endDate; 1299 } 1300 $this->item[$this->styleMap->{$type}['date']] = $date; 1301 } 1302 /** 1303 * Format edition 1304 * 1305 * @author Mark Grimshaw 1306 * @version 1 1307 * 1308 * @param INT $edition 1309 * @return string of edition. 1310 */ 1311 function formatEdition($edition) 1312 { 1313 $type = $this->type; 1314 if(!is_numeric($edition)) 1315 $edition = ($this->output == 'html') ? $this->utf8->utf8_htmlspecialchars($edition) : $edition; 1316 else if($this->style['editionFormat']) // 10th 1317 $edition = ($this->output == 'html') ? $this->utf8->utf8_htmlspecialchars($this->cardinalToOrdinal($edition)) 1318 : $this->cardinalToOrdinal($edition); 1319 $this->item[$this->styleMap->{$type}[array_search('edition', $this->styleMap->$type)]] = $edition; 1320 } 1321 /** 1322 * Create ordinal number from cardinal 1323 * 1324 * @author Mark Grimshaw 1325 * @version 1 1326 * 1327 * @param $cardinal 1328 * @return $ordinal 1329 */ 1330 function cardinalToOrdinal($cardinal) 1331 { 1332 $modulo = $cardinal % 100; 1333 if(($modulo == 11) || ($modulo == 12) || ($modulo == 13)) 1334 return $cardinal . 'th'; 1335 $modulo = $cardinal % 10; 1336 if(($modulo >= 4) || !$modulo) 1337 return $cardinal . 'th'; 1338 if($modulo == 1) 1339 return $cardinal . 'st'; 1340 if($modulo == 2) 1341 return $cardinal . 'nd'; 1342 if($modulo == 3) 1343 return $cardinal . 'rd'; 1344 } 1345 /** 1346 * Month arrays 1347 * @author Mark Grimshaw 1348 * @version 1 1349 */ 1350 function loadArrays() 1351 { 1352 $this->longMonth = array( 1353 1 => 'January', 1354 2 => 'February', 1355 3 => 'March', 1356 4 => 'April', 1357 5 => 'May', 1358 6 => 'June', 1359 7 => 'July', 1360 8 => 'August', 1361 9 => 'September', 1362 10 => 'October', 1363 11 => 'November', 1364 12 => 'December', 1365 ); 1366 $this->shortMonth = array( 1367 1 => 'Jan', 1368 2 => 'Feb', 1369 3 => 'Mar', 1370 4 => 'Apr', 1371 5 => 'May', 1372 6 => 'Jun', 1373 7 => 'Jul', 1374 8 => 'Aug', 1375 9 => 'Sep', 1376 10 => 'Oct', 1377 11 => 'Nov', 1378 12 => 'Dec', 1379 ); 1380 } 1381 1382 1383 1384/* 1385 * convertEntry - convert any laTeX code and convert to UTF-8 ready 1386 for storing in the database 1387 * 1388 * @author Mark Grimshaw, modified by Christophe Ambroise 26/10/2003 1389 * @param array $entry - a bibtex entry 1390 * @return $entry converted to utf8 1391 1392 */ 1393function convertEntry($entry) 1394{ 1395 $this->config = new BIBTEXCONFIG(); 1396 $this->config->bibtex(); 1397 1398 // Construction of the transformation filter 1399 foreach($this->config->bibtexSpCh as $key => $value) 1400 { 1401 $replaceBibtex[] = chr($key); 1402 $matchBibtex[] = preg_quote("/$value/"); 1403 } 1404 foreach($this->config->bibtexSpChOld as $key => $value) 1405 { 1406 $replaceBibtex[] = chr($key); 1407 $matchBibtex[] = preg_quote("/$value/"); 1408 } 1409 foreach($this->config->bibtexSpChOld2 as $key => $value) 1410 { 1411 $replaceBibtex[] = chr($key); 1412 $matchBibtex[] = preg_quote("/$value/"); 1413 } 1414 foreach($this->config->bibtexSpChLatex as $key => $value) 1415 { 1416 $replaceBibtex[] = chr($key); 1417 $matchBibtex[] = preg_quote("/$value/"); 1418 } 1419 1420 // Processing of the entry 1421 foreach($entry as $key => $value){ 1422 // The transformation filter has returned latin1 code 1423 // We thus need to work with latin1. 1424 $value= $this->utf8->smartUtf8_decode($value); 1425 $entry[$key] = utf8_encode(preg_replace($matchBibtex, $replaceBibtex, $value)); 1426 } 1427 return $entry; 1428} 1429 1430 1431 1432 1433} 1434 1435 1436/***** 1437 * BIBTEXCONFIG: BibTeX Configuration class 1438 *****/ 1439class BIBTEXCONFIG 1440{ 1441 // Constructor 1442 function BIBTEXCONFIG() 1443 { 1444 } 1445 // BibTeX arrays 1446 function bibtex() 1447 { 1448 $this->bibtexSpCh = array( 1449 // Deal with '{' and '}' first! 1450 0x007B => "\\textbraceleft", 1451 0x007D => "\\textbraceright", 1452 0x0022 => "{\"}", 1453 0x0023 => "{\#}", 1454 0x0025 => "{\%}", 1455 0x0026 => "{\&}", 1456 0x003C => "\\textless", 1457 0x003E => "\\textgreater", 1458 0x005F => "{\_}", 1459 0x00A3 => "\\textsterling", 1460 0x00C0 => "{\`A}", 1461 0x00C1 => "{\'A}", 1462 0x00C2 => "{\^A}", 1463 0x00C3 => "{\~A}", 1464 0x00C4 => '{\"A}', 1465 0x00C5 => "{\AA}", 1466 0x00C6 => "{\AE}", 1467 0x00C7 => "{\c{C}}", 1468 0x00C8 => "{\`E}", 1469 0x00C9 => "{\'E}", 1470 0x00CA => "{\^E}", 1471 0x00CB => '{\"E}', 1472 0x00CC => "{\`I}", 1473 0x00CD => "{\'I}", 1474 0x00CE => "{\^I}", 1475 0x00CF => '{\"I}', 1476 0x00D1 => "{\~N}", 1477 0x00D2 => "{\`O}", 1478 0x00D3 => "{\'O}", 1479 0x00D4 => "{\^O}", 1480 0x00D5 => "{\~O}", 1481 0x00D6 => '{\"O}', 1482 0x00D8 => "{\O}", 1483 0x00D9 => "{\`U}", 1484 0x00DA => "{\'U}", 1485 0x00DB => "{\^U}", 1486 0x00DC => '{\"U}', 1487 0x00DD => "{\'Y}", 1488 0x00DF => "{\ss}", 1489 0x00E0 => "{\`a}", 1490 0x00E1 => "{\'a}", 1491 0x00E2 => "{\^a}", 1492 0x00E3 => "{\~a}", 1493 0x00E4 => '{\"a}', 1494 0x00E5 => "{\aa}", 1495 0x00E6 => "{\ae}", 1496 0x00E7 => "{\c{c}}", 1497 0x00E8 => "{\`e}", 1498 0x00E9 => "{\'e}", 1499 0x00EA => "{\^e}", 1500 0x00EB => '{\"e}', 1501 0x00EC => "{\`\i}", 1502 0x00ED => "{\'\i}", 1503 0x00EE => "{\^\i}", 1504 0x00EF => '{\"\i}', 1505 0x00F1 => "{\~n}", 1506 0x00F2 => "{\`o}", 1507 0x00F3 => "{\'o}", 1508 0x00F4 => "{\^o}", 1509 0x00F5 => "{\~o}", 1510 0x00F6 => '{\"o}', 1511 0x00F8 => "{\o}", 1512 0x00F9 => "{\`u}", 1513 0x00FA => "{\'u}", 1514 0x00FB => "{\^u}", 1515 0x00FC => '{\"u}', 1516 0x00FD => "{\'y}", 1517 0x00FF => '{\"y}', 1518 0x00A1 => "{\!}", 1519 0x00BF => "{\?}", 1520 ); 1521 //Old style with extra {} - usually array_flipped 1522 $this->bibtexSpChOld = array( 1523 0x00C0 => "{\`{A}}", 1524 0x00C1 => "{\'{A}}", 1525 0x00C2 => "{\^{A}}", 1526 0x00C3 => "{\~{A}}", 1527 0x00C4 => '{\"{A}}', 1528 0x00C5 => "{\A{A}}", 1529 0x00C6 => "{\A{E}}", 1530 0x00C7 => "{\c{C}}", 1531 0x00C8 => "{\`{E}}", 1532 0x00C9 => "{\'{E}}", 1533 0x00CA => "{\^{E}}", 1534 0x00CB => '{\"{E}}', 1535 0x00CC => "{\`{I}}", 1536 0x00CD => "{\'{I}}", 1537 0x00CE => "{\^{I}}", 1538 0x00CF => '{\"{I}}', 1539 0x00D1 => "{\~{N}}", 1540 0x00D2 => "{\`{O}}", 1541 0x00D3 => "{\'{O}}", 1542 0x00D4 => "{\^{O}}", 1543 0x00D5 => "{\~{O}}", 1544 0x00D6 => '{\"{O}}', 1545 0x00D8 => "{\{O}}", 1546 0x00D9 => "{\`{U}}", 1547 0x00DA => "{\'{U}}", 1548 0x00DB => "{\^{U}}", 1549 0x00DC => '{\"{U}}', 1550 0x00DD => "{\'{Y}}", 1551 0x00DF => "{\s{s}}", 1552 0x00E0 => "{\`{a}}", 1553 0x00E1 => "{\'{a}}", 1554 0x00E2 => "{\^{a}}", 1555 0x00E3 => "{\~{a}}", 1556 0x00E4 => '{\"{a}}', 1557 0x00E5 => "{\a{a}}", 1558 0x00E6 => "{\a{e}}", 1559 0x00E7 => "{\c{c}}", 1560 0x00E8 => "{\`{e}}", 1561 0x00E9 => "{\'{e}}", 1562 0x00EA => "{\^{e}}", 1563 0x00EB => '{\"{e}}', 1564 0x00EC => "{\`\i}", 1565 0x00ED => "{\'\i}", 1566 0x00EE => "{\^\i}", 1567 0x00EF => '{\"\i}', 1568 0x00F1 => "{\~{n}}", 1569 0x00F2 => "{\`{o}}", 1570 0x00F3 => "{\'{o}}", 1571 0x00F4 => "{\^{o}}", 1572 0x00F5 => "{\~{o}}", 1573 0x00F6 => '{\"{o}}', 1574 0x00F8 => "{\{o}}", 1575 0x00F9 => "{\`{u}}", 1576 0x00FA => "{\'{u}}", 1577 0x00FB => "{\^{u}}", 1578 0x00FC => '{\"{u}}', 1579 0x00FD => "{\'{y}}", 1580 0x00FF => '{\"{y}}', 1581 0x00A1 => "{\{!}}", 1582 0x00BF => "{\{?}}", 1583 ); 1584 // And there's more?!?!?!?!? (This is not strict bibtex.....) 1585 $this->bibtexSpChOld2 = array( 1586 0x00C0 => "\`{A}", 1587 0x00C1 => "\'{A}", 1588 0x00C2 => "\^{A}", 1589 0x00C3 => "\~{A}", 1590 0x00C4 => '\"{A}', 1591 0x00C5 => "\A{A}", 1592 0x00C6 => "\A{E}", 1593 0x00C7 => "\c{C}", 1594 0x00C8 => "\`{E}", 1595 0x00C9 => "\'{E}", 1596 0x00CA => "\^{E}", 1597 0x00CB => '\"{E}', 1598 0x00CC => "\`{I}", 1599 0x00CD => "\'{I}", 1600 0x00CE => "\^{I}", 1601 0x00CF => '\"{I}', 1602 0x00D1 => "\~{N}", 1603 0x00D2 => "\`{O}", 1604 0x00D3 => "\'{O}", 1605 0x00D4 => "\^{O}", 1606 0x00D5 => "\~{O}", 1607 0x00D6 => '\"{O}', 1608 0x00D8 => "\{O}", 1609 0x00D9 => "\`{U}", 1610 0x00DA => "\'{U}", 1611 0x00DB => "\^{U}", 1612 0x00DC => '\"{U}', 1613 0x00DD => "\'{Y}", 1614 0x00DF => "\s{s}", 1615 0x00E0 => "\`{a}", 1616 0x00E1 => "\'{a}", 1617 0x00E2 => "\^{a}", 1618 0x00E3 => "\~{a}", 1619 0x00E4 => '\"{a}', 1620 0x00E5 => "\a{a}", 1621 0x00E6 => "\a{e}", 1622 0x00E7 => "\c{c}", 1623 0x00E8 => "\`{e}", 1624 0x00E9 => "\'{e}", 1625 0x00EA => "\^{e}", 1626 0x00EB => '\"{e}', 1627 0x00EC => "\`{i}", 1628 0x00ED => "\'{i}", 1629 0x00EE => "\^{i}", 1630 0x00EF => '\"{i}', 1631 0x00F1 => "\~{n}", 1632 0x00F2 => "\`{o}", 1633 0x00F3 => "\'{o}", 1634 0x00F4 => "\^{o}", 1635 0x00F5 => "\~{o}", 1636 0x00F6 => '\"{o}', 1637 0x00F8 => "\{o}", 1638 0x00F9 => "\`{u}", 1639 0x00FA => "\'{u}", 1640 0x00FB => "\^{u}", 1641 0x00FC => '\"{u}', 1642 0x00FD => "\'{y}", 1643 0x00FF => '\"{y}', 1644 0x00A1 => "\{!}", 1645 0x00BF => "\{?}", 1646 ); 1647 // Latex code that some bibtex users may be using 1648 $this->bibtexSpChLatex = array( 1649 0x00C0 => "\`A", 1650 0x00C1 => "\'A", 1651 0x00C2 => "\^A", 1652 0x00C3 => "\~A", 1653 0x00C4 => '\"A', 1654 0x00C5 => "\AA", 1655 0x00C6 => "\AE", 1656 0x00C7 => "\cC", 1657 0x00C8 => "\`E", 1658 0x00C9 => "\'E", 1659 0x00CA => "\^E", 1660 0x00CB => '\"E', 1661 0x00CC => "\`I", 1662 0x00CD => "\'I", 1663 0x00CE => "\^I", 1664 0x00CF => '\"I', 1665 0x00D1 => "\~N", 1666 0x00D2 => "\`O", 1667 0x00D3 => "\'O", 1668 0x00D4 => "\^O", 1669 0x00D5 => "\~O", 1670 0x00D6 => '\"O', 1671 0x00D8 => "\O", 1672 0x00D9 => "\`U", 1673 0x00DA => "\'U", 1674 0x00DB => "\^U", 1675 0x00DC => '\"U', 1676 0x00DD => "\'Y", 1677 0x00DF => "\ss", 1678 0x00E0 => "\`a", 1679 0x00E1 => "\'a", 1680 0x00E2 => "\^a", 1681 0x00E3 => "\~a", 1682 0x00E4 => '\"a', 1683 0x00E5 => "\aa", 1684 0x00E6 => "\ae", 1685 0x00E7 => "\cc", 1686 0x00E8 => "\`e", 1687 0x00E9 => "\'e", 1688 0x00EA => "\^e", 1689 0x00EB => '\"e', 1690 0x00EC => "\`i", 1691 0x00ED => "\'i", 1692 0x00EE => "\^i", 1693 0x00EF => '\"i', 1694 0x00F1 => "\~n", 1695 0x00F2 => "\`o", 1696 0x00F3 => "\'o", 1697 0x00F4 => "\^o", 1698 0x00F5 => "\~o", 1699 0x00F6 => '\"o', 1700 0x00F8 => "\o", 1701 0x00F9 => "\`u", 1702 0x00FA => "\'u", 1703 0x00FB => "\^u", 1704 0x00FC => '\"u', 1705 0x00FD => "\'y", 1706 0x00FF => '\"y', 1707 0x00A1 => "\!", 1708 0x00BF => "\?", 1709 ); 1710 $this->bibtexSpChPlain = array( 1711 0x00C0 => "A", 1712 0x00C1 => "A", 1713 0x00C2 => "A", 1714 0x00C3 => "A", 1715 0x00C4 => 'A', 1716 0x00C5 => "A", 1717 0x00C6 => "AE", 1718 0x00C7 => "C", 1719 0x00C8 => "E", 1720 0x00C9 => "E", 1721 0x00CA => "E", 1722 0x00CB => 'E', 1723 0x00CC => "I", 1724 0x00CD => "I", 1725 0x00CE => "I", 1726 0x00CF => 'I', 1727 0x00D1 => "N", 1728 0x00D2 => "O", 1729 0x00D3 => "O", 1730 0x00D4 => "O", 1731 0x00D5 => "O", 1732 0x00D6 => 'O', 1733 0x00D8 => "O", 1734 0x00D9 => "U", 1735 0x00DA => "U", 1736 0x00DB => "U", 1737 0x00DC => 'U', 1738 0x00DD => "Y", 1739 0x00DF => "ss", 1740 0x00E0 => "a", 1741 0x00E1 => "a", 1742 0x00E2 => "a", 1743 0x00E3 => "a", 1744 0x00E4 => 'a', 1745 0x00E5 => "aa", 1746 0x00E6 => "ae", 1747 0x00E7 => "c", 1748 0x00E8 => "e", 1749 0x00E9 => "e", 1750 0x00EA => "e", 1751 0x00EB => 'e', 1752 0x00EC => "i", 1753 0x00ED => "i", 1754 0x00EE => "i", 1755 0x00EF => 'i', 1756 0x00F1 => "n", 1757 0x00F2 => "o", 1758 0x00F3 => "o", 1759 0x00F4 => "o", 1760 0x00F5 => "o", 1761 0x00F6 => 'o', 1762 0x00F8 => "o", 1763 0x00F9 => "u", 1764 0x00FA => "u", 1765 0x00FB => "u", 1766 0x00FC => 'u', 1767 0x00FD => "u", 1768 0x00FF => 'u', 1769 0x00A1 => "u", 1770 0x00BF => "u", 1771 ); 1772 } 1773} 1774 1775 1776?> 1777