PageRenderTime 36ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/bibtexbrowser.php

https://github.com/emir-munoz/bibtexbrowser
PHP | 3496 lines | 2991 code | 182 blank | 323 comment | 150 complexity | 4f9f18f4e3f0b0f17ae103fa5235259f MD5 | raw file
  1. <?php /* bibtexbrowser: publication lists with bibtex and PHP
  2. <!--this is version v20120703 -->
  3. URL: http://www.monperrus.net/martin/bibtexbrowser/
  4. Feedback & Bug Reports: martin.monperrus@gmail.com
  5. (C) 2006-2012 Martin Monperrus
  6. (C) 2005-2006 The University of Texas at El Paso / Joel Garcia, Leonardo Ruiz, and Yoonsik Cheon
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License as
  9. published by the Free Software Foundation; either version 2 of the
  10. License, or (at your option) any later version.
  11. */
  12. // it is be possible to include( 'bibtexbrowser.php' ); several times in the same script
  13. // added on Wednesday, June 01 2011, bug found by Carlos Bras
  14. if (!defined('BIBTEXBROWSER')) {
  15. // this if block ends at the very end of this file, after all class and function declarations.
  16. define('BIBTEXBROWSER','v20120703');
  17. // *************** CONFIGURATION
  18. // I recommend to put your changes in bibtexbrowser.local.php
  19. // it will help you to upgrade the script with a new version
  20. @include(dirname(__FILE__).'/bibtexbrowser.local.php');
  21. // there is no encoding transformation from the bibtex file to the html file
  22. // if your bibtex file contains 8 bits characters in utf-8
  23. // change the following parameter
  24. @define('ENCODING','UTF-8');//@define('ENCODING','iso-8859-1');//define('ENCODING','windows-1252');
  25. // number of bib items per page
  26. // we use the same parameter 'num' as Google
  27. @define('PAGE_SIZE',isset($_GET['num'])?(preg_match('/^\d+$/',$_GET['num'])?$_GET['num']:10000):14);
  28. // bibtexbrowser uses a small piece of Javascript to improve the user experience
  29. // see http://en.wikipedia.org/wiki/Progressive_enhancement
  30. // if you don't like it, you can be disable it by adding in bibtexbrowser.local.php
  31. // @define('BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT',false);
  32. @define('BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT',true);
  33. // if you disable the Javascript progressive enhancement,
  34. // you may want the links to be open in a new window/tab
  35. // if yes, add in bibtexbrowser.local.php define('BIBTEXBROWSER_BIB_IN_NEW_WINDOW',true);
  36. @define('BIBTEXBROWSER_BIB_IN_NEW_WINDOW',false);
  37. @define('BIBLIOGRAPHYSTYLE','DefaultBibliographyStyle');// this is the name of a function
  38. @define('BIBLIOGRAPHYSECTIONS','DefaultBibliographySections');// this is the name of a function
  39. // can we load bibtex files on external servers?
  40. @define('BIBTEXBROWSER_LOCAL_BIB_ONLY', true);
  41. // the default view in {SimpleDisplay,AcademicDisplay,RSSDisplay,BibtexDisplay}
  42. @define('BIBTEXBROWSER_DEFAULT_DISPLAY','SimpleDisplay');
  43. // the target frame of menu links
  44. @define('BIBTEXBROWSER_MENU_TARGET','main'); // might be define('BIBTEXBROWSER_MENU_TARGET','_self'); in bibtexbrowser.local.php
  45. @define('ABBRV_TYPE','index');// may be year/x-abbrv/key/none/index
  46. // Wrapper to use when we are included by another script
  47. @define('BIBTEXBROWSER_EMBEDDED_WRAPPER', 'NoWrapper');
  48. // default order functions
  49. @define('ORDER_FUNCTION','compare_bib_entry_by_year_and_month');
  50. // can be @define('ORDER_FUNCTION','compare_bib_entry_by_title');
  51. // only displaying the n newest entries
  52. @define('BIBTEXBROWSER_NEWEST',5);
  53. @define('BIBTEXBROWSER_NO_DEFAULT', false);
  54. // do we add [bibtex] links ?
  55. // suggested by Sascha Schnepp
  56. @define('BIBTEXBROWSER_BIBTEX_LINKS',true);
  57. @define('BIBTEXBROWSER_DEBUG',false);
  58. @define('COMMA_NAMES',false);// do have authors in a comma separated form?
  59. @define('TYPES_SIZE',10); // number of entry types per table
  60. @define('YEAR_SIZE',20); // number of years per table
  61. @define('AUTHORS_SIZE',30); // number of authors per table
  62. @define('TAGS_SIZE',30); // number of keywords per table
  63. @define('READLINE_LIMIT',1024);
  64. @define('Q_YEAR', 'year');
  65. @define('Q_YEAR_PAGE', 'year_page');
  66. @define('Q_FILE', 'bib');
  67. @define('Q_AUTHOR', 'author');
  68. @define('Q_AUTHOR_PAGE', 'author_page');
  69. @define('Q_TAG', 'keywords');
  70. @define('Q_TAG_PAGE', 'keywords_page');
  71. @define('Q_TYPE', 'type');
  72. @define('Q_TYPE_PAGE', 'type_page');
  73. @define('Q_ALL', 'all');
  74. @define('Q_ENTRY', 'entry');
  75. @define('Q_KEY', 'key');
  76. @define('Q_SEARCH', 'search');
  77. @define('Q_EXCLUDE', 'exclude');
  78. @define('Q_RESULT', 'result');
  79. @define('Q_ACADEMIC', 'academic');
  80. @define('Q_DB', 'bibdb');
  81. @define('Q_LATEST', 'latest');
  82. @define('AUTHOR', 'author');
  83. @define('EDITOR', 'editor');
  84. @define('SCHOOL', 'school');
  85. @define('TITLE', 'title');
  86. @define('BOOKTITLE', 'booktitle');
  87. @define('YEAR', 'year');
  88. @define('BUFFERSIZE',100000);
  89. @define('MULTIPLE_BIB_SEPARATOR',';');
  90. @define('METADATA_GS',true);
  91. @define('METADATA_DC',true);
  92. @define('METADATA_EPRINTS',false);
  93. // in embedded mode, we still need a URL for displaying bibtex entries alone
  94. // this is usually resolved to bibtexbrowser.php
  95. // but can be overridden in bibtexbrowser.local.php
  96. // for instance with @define('BIBTEXBROWSER_URL',''); // links to the current page with ?
  97. @define('BIBTEXBROWSER_URL',basename(__FILE__));
  98. // *************** END CONFIGURATION
  99. // for clean search engine links
  100. // we disable url rewriting
  101. // ... and hope that your php configuration will accept one of these
  102. @ini_set("session.use_only_cookies",1);
  103. @ini_set("session.use_trans_sid",0);
  104. @ini_set("url_rewriter.tags","");
  105. // we ensure that the pages won't get polluted
  106. // if future versions of PHP change warning mechanisms...
  107. @error_reporting(E_ERROR);
  108. /** parses $_GET[Q_FILE] and puts the result (an object of type BibDataBase) in $_GET[Q_DB].
  109. See also zetDB().
  110. */
  111. function setDB() {
  112. list($db, $parsed, $updated, $saved) = _zetDB(@$_GET[Q_FILE]);
  113. $_GET[Q_DB] = $db;
  114. return $updated;
  115. }
  116. /** parses the $bibtex_filenames (usually semi-column separated) and returns an object of type BibDataBase.
  117. See also setDB()
  118. */
  119. function zetDB($bibtex_filenames) {
  120. list($db, $parsed, $updated, $saved) = _zetDB($bibtex_filenames);
  121. return $db;
  122. }
  123. /** @nodoc */
  124. function default_message() {
  125. if (BIBTEXBROWSER_NO_DEFAULT) { return; }
  126. ?>
  127. <div id="bibtexbrowser_message">
  128. Congratulations! bibtexbrowser is correctly installed!<br/>
  129. Now you have to pass the name of the bibtex file as parameter (e.g. bibtexbrowser.php?bib=mybib.php)<br/>
  130. You may browse:<br/>
  131. <?php
  132. foreach (glob("*.bib") as $bibfile) {
  133. $url="?bib=".$bibfile; echo '<a href="'.$url.'" rel="nofollow">'.$bibfile.'</a><br/>';
  134. }
  135. echo "</div>";
  136. }
  137. /** @nodoc */
  138. function _zetDB($bibtex_filenames) {
  139. $db = null;
  140. // Check if magic_quotes_runtime is active
  141. if(get_magic_quotes_runtime())
  142. {
  143. // Deactivate
  144. // otherwise it does not work
  145. set_magic_quotes_runtime(false);
  146. }
  147. // default bib file, if no file is specified in the query string.
  148. if (!isset($bibtex_filenames) || $bibtex_filenames == "") {
  149. default_message();
  150. exit;
  151. }
  152. // first does the bibfiles exist:
  153. // $bibtex_filenames can be urlencoded for instance if they contain slashes
  154. // so we decode it
  155. $bibtex_filenames = urldecode($bibtex_filenames);
  156. // ---------------------------- HANDLING unexistent files
  157. foreach(explode(MULTIPLE_BIB_SEPARATOR, $bibtex_filenames) as $bib) {
  158. // this is a security protection
  159. if (BIBTEXBROWSER_LOCAL_BIB_ONLY && !file_exists($bib)) {
  160. // to automate dectection of faulty links with tools such as webcheck
  161. header('HTTP/1.1 404 Not found');
  162. die('<b>the bib file '.$bib.' does not exist !</b>');
  163. }
  164. } // end for each
  165. // ---------------------------- HANDLING HTTP If-modified-since
  166. // testing with $ curl -v --header "If-Modified-Since: Fri, 23 Oct 2010 19:22:47 GMT" "... bibtexbrowser.php?key=wasylkowski07&bib=..%252Fstrings.bib%253B..%252Fentries.bib"
  167. // and $ curl -v --header "If-Modified-Since: Fri, 23 Oct 2000 19:22:47 GMT" "... bibtexbrowser.php?key=wasylkowski07&bib=..%252Fstrings.bib%253B..%252Fentries.bib"
  168. // save bandwidth and server cpu
  169. // (imagine the number of requests from search engine bots...)
  170. $bib_is_unmodified = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ;
  171. foreach(explode(MULTIPLE_BIB_SEPARATOR, $bibtex_filenames) as $bib) {
  172. $bib_is_unmodified =
  173. $bib_is_unmodified
  174. && (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])>filemtime($bib));
  175. } // end for each
  176. if ( $bib_is_unmodified && !headers_sent()) {
  177. header("HTTP/1.1 304 Not Modified");
  178. exit;
  179. }
  180. // ---------------------------- HANDLING caching of compiled bibtex files
  181. // for sake of performance, once the bibtex file is parsed
  182. // we try to save a "compiled" in a txt file
  183. $compiledbib = 'bibtexbrowser_'.md5($bibtex_filenames).'.dat';
  184. $parse=false;
  185. foreach(explode(MULTIPLE_BIB_SEPARATOR, $bibtex_filenames) as $bib) {
  186. // do we have a compiled version ?
  187. if (is_file($compiledbib)
  188. && is_readable($compiledbib)
  189. && filesize($compiledbib)>0
  190. ) {
  191. $f = fopen($compiledbib,'r');
  192. //we use a lock to avoid that a call to bibbtexbrowser made while we write the object loads an incorrect object
  193. if (flock($f,LOCK_EX)) {
  194. $s = filesize($compiledbib);
  195. $ser = fread($f,$s);
  196. $db = @unserialize($ser);
  197. flock($f,LOCK_UN);
  198. } else { die('could not get the lock'); }
  199. fclose($f);
  200. // basic test
  201. // do we have an correct version of the file
  202. if (!is_a($db,'BibDataBase')) {
  203. unlink($compiledbib);
  204. if (BIBTEXBROWSER_DEBUG) { die('$db not a BibDataBase. please reload.'); }
  205. $parse=true;
  206. }
  207. } else {$parse=true;}
  208. } // end for each
  209. // we don't have a compiled version
  210. if ($parse) {
  211. //echo '<!-- parsing -->';
  212. // then parsing the file
  213. $db = createBibDataBase();
  214. foreach(explode(MULTIPLE_BIB_SEPARATOR, $bibtex_filenames) as $bib) {
  215. $db->load($bib);
  216. }
  217. }
  218. $updated = false;
  219. // now we may update the database
  220. if (!file_exists($compiledbib)) {
  221. @touch($compiledbib);
  222. $updated = true; // limit case
  223. } else foreach(explode(MULTIPLE_BIB_SEPARATOR, $bibtex_filenames) as $bib) {
  224. // is it up to date ? wrt to the bib file and the script
  225. // then upgrading with a new version of bibtexbrowser triggers a new compilation of the bib file
  226. if (filemtime($bib)>filemtime($compiledbib) || filemtime(__FILE__)>filemtime($compiledbib)) {
  227. //echo "updating...";
  228. $db->update($bib);
  229. $updated = true;
  230. }
  231. }
  232. //echo var_export($parse);
  233. //echo var_export($updated);
  234. $saved = false;
  235. // are we able to save the compiled version ?
  236. // note that the compiled version is saved in the current working directory
  237. if ( ($parse || $updated ) && is_writable($compiledbib)) {
  238. // we use 'a' because the file is not locked between fopen and flock
  239. $f = fopen($compiledbib,'a');
  240. //we use a lock to avoid that a call to bibbtexbrowser made while we write the object loads an incorrect object
  241. if (flock($f,LOCK_EX)) {
  242. // echo '<!-- saving -->';
  243. ftruncate($f,0);
  244. fwrite($f,serialize($db));
  245. flock($f,LOCK_UN);
  246. $saved = true;
  247. } else { die('could not get the lock'); }
  248. fclose($f);
  249. } // end saving the cached verions
  250. //else echo '<!-- please chmod the directory containing the bibtex file to be able to keep a compiled version (much faster requests for large bibtex files) -->';
  251. return array(&$db, $parse, $updated, $saved);
  252. } // end function setDB
  253. // factories
  254. // may be overridden in bibtexbrowser.local.php
  255. if (!function_exists('createBibDataBase')) {
  256. /** factory method for openness @nodoc */
  257. function createBibDataBase() { $x = new BibDataBase(); return $x;}
  258. }
  259. if (!function_exists('createBibEntry')) {
  260. /** factory method for openness @nodoc */
  261. function createBibEntry() { $x = new BibEntry(); return $x;}
  262. }
  263. if (!function_exists('createBibDBBuilder')) {
  264. /** factory method for openness @nodoc */
  265. function createBibDBBuilder() { $x = new BibDBBuilder(); return $x;}
  266. }
  267. if (!function_exists('createBasicDisplay')) {
  268. /** factory method for openness @nodoc */
  269. function createBasicDisplay() { $x = new SimpleDisplay(); return $x;}
  270. }
  271. if (!function_exists('createBibEntryDisplay')) {
  272. /** factory method for openness @nodoc */
  273. function createBibEntryDisplay() { $x = new BibEntryDisplay(); return $x;}
  274. }
  275. if (!function_exists('createMenuManager')) {
  276. /** factory method for openness @nodoc */
  277. function createMenuManager() { $x = new MenuManager(); return $x;}
  278. }
  279. ////////////////////////////////////////////////////////
  280. /** is a generic parser of bibtex files.
  281. usage:
  282. <pre>
  283. $delegate = new XMLPrettyPrinter();// or another delegate such as BibDBBuilder
  284. $parser = new StateBasedBibtexParser($delegate);
  285. $parser->parse('foo.bib');
  286. </pre>
  287. notes:
  288. - It has no dependencies, it can be used outside of bibtexbrowser
  289. - The delegate is expected to have some methods, see classes BibDBBuilder and XMLPrettyPrinter
  290. */
  291. class StateBasedBibtexParser {
  292. var $delegate;
  293. function StateBasedBibtexParser(&$delegate) {
  294. $this->delegate = &$delegate;
  295. }
  296. function parse($bibfilename) {
  297. $delegate = &$this->delegate;
  298. // STATE DEFINITIONS
  299. @define('NOTHING',1);
  300. @define('GETTYPE',2);
  301. @define('GETKEY',3);
  302. @define('GETVALUE',4);
  303. @define('GETVALUEDELIMITEDBYQUOTES',5);
  304. @define('GETVALUEDELIMITEDBYQUOTES_ESCAPED',6);
  305. @define('GETVALUEDELIMITEDBYCURLYBRACKETS',7);
  306. @define('GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED',8);
  307. @define('GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL',9);
  308. @define('GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED',10);
  309. @define('GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL',11);
  310. @define('GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED',12);
  311. @define('GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL',13);
  312. @define('GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED',14);
  313. $state=NOTHING;
  314. $entrytype='';
  315. $entrykey='';
  316. $entryvalue='';
  317. $finalkey='';
  318. $entrysource='';
  319. // metastate
  320. $isinentry = false;
  321. $delegate->beginFile();
  322. $handle = fopen($bibfilename, "r");
  323. if (!$handle) die ('cannot open '.$bibfilename);
  324. // if you encounter this error "Allowed memory size of xxxxx bytes exhausted"
  325. // then decrease the size of the temp buffer below
  326. $bufsize=BUFFERSIZE;
  327. while (!feof($handle)) {
  328. $sread=fread($handle,$bufsize);
  329. //foreach(str_split($sread) as $s) {
  330. for ( $i=0; $i < strlen( $sread ); $i++) { $s=$sread[$i];
  331. if ($isinentry) $entrysource.=$s;
  332. if ($state==NOTHING) {
  333. // this is the beginning of an entry
  334. if ($s=='@') {
  335. $delegate->beginEntry();
  336. $state = GETTYPE;
  337. $isinentry = true;
  338. $entrysource='@';
  339. }
  340. }
  341. else if ($state==GETTYPE) {
  342. // this is the beginning of a key
  343. if ($s=='{') {
  344. $state = GETKEY;
  345. $delegate->setEntryType($entrytype);
  346. $entrytype='';
  347. }
  348. else $entrytype=$entrytype.$s;
  349. }
  350. else if ($state==GETKEY) {
  351. // now we get the value
  352. if ($s=='=') {
  353. $state = GETVALUE;
  354. $finalkey=$entrykey;
  355. $entrykey='';}
  356. // oups we only have the key :-) anyway
  357. else if ($s=='}') {
  358. $state = NOTHING;$isinentry = false;$delegate->endEntry($entrysource);
  359. $entrykey='';
  360. }
  361. // OK now we look for values
  362. else if ($s==',') {
  363. $state=GETKEY;
  364. $delegate->setEntryKey($entrykey);
  365. $entrykey='';}
  366. else { $entrykey=$entrykey.$s; }
  367. }
  368. // we just got a =, we can now receive the value, but we don't now whether the value
  369. // is delimited by curly brackets, double quotes or nothing
  370. else if ($state==GETVALUE) {
  371. // the value is delimited by double quotes
  372. if ($s=='"') {
  373. $state = GETVALUEDELIMITEDBYQUOTES;
  374. }
  375. // the value is delimited by curly brackets
  376. else if ($s=='{') {
  377. $state = GETVALUEDELIMITEDBYCURLYBRACKETS;
  378. }
  379. // the end of the key and no value found: it is the bibtex key e.g. \cite{Descartes1637}
  380. else if ($s==',') {
  381. $state = GETKEY;
  382. $delegate->setEntryField(trim($finalkey),$entryvalue);
  383. $entryvalue=''; // resetting the value buffer
  384. }
  385. // this is the end of the value AND of the entry
  386. else if ($s=='}') {
  387. $state = NOTHING;
  388. $delegate->setEntryField(trim($finalkey),$entryvalue);
  389. $isinentry = false;$delegate->endEntry($entrysource);
  390. $entryvalue=''; // resetting the value buffer
  391. }
  392. else if ($s==' ' || $s=="\t" || $s=="\n" || $s=="\r" ) {
  393. // blank characters are not taken into account when values are not in quotes or curly brackets
  394. }
  395. else { $entryvalue=$entryvalue.$s;}
  396. }
  397. /* GETVALUEDELIMITEDBYCURLYBRACKETS* handle entries delimited by curly brackets and the possible nested curly brackets */
  398. else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS) {
  399. if ($s=='\\') {
  400. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED;
  401. $entryvalue=$entryvalue.$s;}
  402. else if ($s=='{') {
  403. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
  404. else if ($s=='}') {
  405. $state = GETVALUE;}
  406. else { $entryvalue=$entryvalue.$s;}
  407. }
  408. // handle anti-slashed brackets
  409. else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_ESCAPED) {
  410. $state = GETVALUEDELIMITEDBYCURLYBRACKETS;
  411. $entryvalue=$entryvalue.$s;
  412. }
  413. // in first level of curly bracket
  414. else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL) {
  415. if ($s=='\\') {
  416. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED;
  417. $entryvalue=$entryvalue.$s;}
  418. else if ($s=='{') {
  419. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
  420. else if ($s=='}') {
  421. $state = GETVALUEDELIMITEDBYCURLYBRACKETS;$entryvalue=$entryvalue.$s;}
  422. else { $entryvalue=$entryvalue.$s;}
  423. }
  424. // handle anti-slashed brackets
  425. else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL_ESCAPED) {
  426. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;
  427. $entryvalue=$entryvalue.$s;
  428. }
  429. // in second level of curly bracket
  430. else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL) {
  431. if ($s=='\\') {
  432. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED;
  433. $entryvalue=$entryvalue.$s;}
  434. else if ($s=='{') {
  435. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
  436. else if ($s=='}') {
  437. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_1NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
  438. else { $entryvalue=$entryvalue.$s;}
  439. }
  440. // handle anti-slashed brackets
  441. else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL_ESCAPED) {
  442. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;
  443. $entryvalue=$entryvalue.$s;
  444. }
  445. // in third level of curly bracket
  446. else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL) {
  447. if ($s=='\\') {
  448. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED;
  449. $entryvalue=$entryvalue.$s;}
  450. else if ($s=='}') {
  451. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_2NESTEDLEVEL;$entryvalue=$entryvalue.$s;}
  452. else { $entryvalue=$entryvalue.$s;}
  453. }
  454. // handle anti-slashed brackets
  455. else if ($state==GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL_ESCAPED) {
  456. $state = GETVALUEDELIMITEDBYCURLYBRACKETS_3NESTEDLEVEL;
  457. $entryvalue=$entryvalue.$s;
  458. }
  459. /* handles entries delimited by double quotes */
  460. else if ($state==GETVALUEDELIMITEDBYQUOTES) {
  461. if ($s=='\\') {
  462. $state = GETVALUEDELIMITEDBYQUOTES_ESCAPED;
  463. $entryvalue=$entryvalue.$s;}
  464. else if ($s=='"') {
  465. $state = GETVALUE;
  466. }
  467. else { $entryvalue=$entryvalue.$s;}
  468. }
  469. // handle anti-double quotes
  470. else if ($state==GETVALUEDELIMITEDBYQUOTES_ESCAPED) {
  471. $state = GETVALUEDELIMITEDBYQUOTES;
  472. $entryvalue=$entryvalue.$s;
  473. }
  474. } // end for
  475. } // end while
  476. $delegate->endFile();
  477. fclose($handle);
  478. //$d = &$this->delegate;print_r($d);
  479. } // end function
  480. } // end class
  481. /** is a delegate for StateBasedBibParser.
  482. usage:
  483. see snippet of [[#StateBasedBibParser]]
  484. */
  485. class XMLPrettyPrinter {
  486. function beginFile() {
  487. header('Content-type: text/xml;');
  488. print '<?xml version="1.0" encoding="'.ENCODING.'"?>';
  489. print '<bibfile>';
  490. }
  491. function endFile() {
  492. print '</bibfile>';
  493. }
  494. function setEntryField($finalkey,$entryvalue) {
  495. print "<data>\n<key>".$finalkey."</key>\n<value>".$entryvalue."</value>\n</data>\n";
  496. }
  497. function setEntryType($entrytype) {
  498. print '<type>'.$entrytype.'</type>';
  499. }
  500. function setEntryKey($entrykey) {
  501. print '<keyonly>'.$entrykey.'</keyonly>';
  502. }
  503. function beginEntry() {
  504. print "<entry>\n";
  505. }
  506. function endEntry($entrysource) {
  507. print "</entry>\n";
  508. }
  509. } // end class XMLPrettyPrinter
  510. /** builds arrays of BibEntry objects from a bibtex file.
  511. usage:
  512. <pre>
  513. $empty_array = array();
  514. $db = new BibDBBuilder(); // see also factory method createBibDBBuilder
  515. $db->build('foo.bib'); // parses foo.bib
  516. print_r($db->builtdb);// an associated array key -> BibEntry objects
  517. print_r($db->stringdb);// an associated array key -> strings representing @string
  518. </pre>
  519. notes:
  520. method build can be used several times, bibtex entries are accumulated in the builder
  521. */
  522. class BibDBBuilder {
  523. /** A hashtable from keys to bib entries (BibEntry). */
  524. var $builtdb = array();
  525. /** A hashtable of constant strings */
  526. var $stringdb = array();
  527. var $filename;
  528. var $currentEntry;
  529. function setData(&$builtdb, &$stringdb) {
  530. $this->builtdb = $builtdb;
  531. $this->stringdb = $stringdb;
  532. return $this;
  533. }
  534. function build($filename) {
  535. $this->filename = $filename;
  536. $parser = new StateBasedBibtexParser($this);
  537. $parser->parse($filename);
  538. //print_r(array_keys(&$this->builtdb));
  539. //print_r(&$this->builtdb);
  540. }
  541. function getBuiltDb() {
  542. //print_r($this->builtdb);
  543. return $this->builtdb;
  544. }
  545. function beginFile() {
  546. }
  547. function endFile() {
  548. // resolving crossrefs
  549. // we are careful with PHP 4 semantics
  550. foreach (array_keys($this->builtdb) as $key) {
  551. $bib = &$this->builtdb[$key];
  552. if ($bib->hasField('crossref')) {
  553. if (isset($this->builtdb[$bib->getField('crossref')])) {
  554. $crossrefEntry = $this->builtdb[$bib->getField('crossref')];
  555. $bib->crossref = $crossrefEntry;
  556. foreach($crossrefEntry->getFields() as $k => $v) {
  557. // copying the fields of the cross ref
  558. // only if they don't exist yet
  559. if (!$bib->hasField($k)) {
  560. $bib->setField($k,$v);
  561. }
  562. }
  563. }
  564. }
  565. }
  566. //print_r($this->builtdb);
  567. }
  568. function setEntryField($finalkey,$entryvalue) {
  569. // is it a constant? then we replace the value
  570. // we support advanced features of bibtexbrowser
  571. // see http://newton.ex.ac.uk/tex/pack/bibtex/btxdoc/node3.html
  572. $entryvalue_array=explode('#',$entryvalue);
  573. foreach ($entryvalue_array as $k=>$v) {
  574. // spaces are allowed when using #, they are not taken into account
  575. // however # is not istself replaced by a space
  576. // warning: @strings are not case sensitive
  577. // see http://newton.ex.ac.uk/tex/pack/bibtex/btxdoc/node3.html
  578. $stringKey=strtolower(trim($v));
  579. if (isset($this->stringdb[$stringKey]))
  580. {
  581. // this field will be formated later by xtrim and latex2html
  582. $entryvalue_array[$k]=$this->stringdb[$stringKey];
  583. // we keep a trace of this replacement
  584. // so as to produce correct bibtex snippets
  585. $this->currentEntry->constants[$stringKey]=$this->stringdb[$stringKey];
  586. }
  587. }
  588. $entryvalue=implode('',$entryvalue_array);
  589. $this->currentEntry->setField($finalkey,$entryvalue);
  590. }
  591. function setEntryType($entrytype) {
  592. $this->currentEntry->setType($entrytype);
  593. }
  594. function setEntryKey($entrykey) {
  595. //echo "new entry:".$entrykey."\n";
  596. $this->currentEntry->setKey($entrykey);
  597. }
  598. function beginEntry() {
  599. $this->currentEntry = createBibEntry();
  600. $this->currentEntry->setFile($this->filename);
  601. }
  602. function endEntry($entrysource) {
  603. // we add a timestamp
  604. $this->currentEntry->setTimestamp();
  605. // we set the fulltext
  606. $this->currentEntry->text = $entrysource;
  607. // we format the author names in a special field
  608. // to enable search
  609. if ($this->currentEntry->hasField('author')) {
  610. $this->currentEntry->setField('_author',$this->currentEntry->getFormattedAuthorsImproved());
  611. }
  612. // ignoring jabref comments
  613. if (($this->currentEntry->getType()=='comment')) {
  614. /* do nothing for jabref comments */
  615. }
  616. // we add it to the string database
  617. else if ($this->currentEntry->getType()=='string') {
  618. foreach($this->currentEntry->fields as $k => $v) {
  619. $k!='type' and $this->stringdb[$k]=$v;
  620. }
  621. }
  622. // we add it to the database
  623. else {
  624. $this->builtdb[$this->currentEntry->getKey()] = $this->currentEntry;
  625. }
  626. }
  627. } // end class BibDBBuilder
  628. /** is an extended version of the trim function, removes linebreaks, tabs, etc.
  629. */
  630. function xtrim($line) {
  631. $line = trim($line);
  632. // we remove the unneeded line breaks
  633. // this is *required* to correctly split author lists into names
  634. // 2010-06-30
  635. // bug found by Thomas
  636. // windows new line is **\r\n"** and not the other way around!!
  637. $line = str_replace("\r\n",' ', $line);//windows like
  638. $line = str_replace("\n",' ', $line);//unix-like
  639. // we also replace tabs
  640. $line = str_replace("\t",' ', $line);
  641. // remove superfluous spaces e.g. John+++Bar
  642. $line = preg_replace('/ {2,}/',' ', $line);
  643. return $line;
  644. }
  645. /** encapsulates the conversion of a single latex chars to the corresponding HTML entity.
  646. It expects a **lower-case** char.
  647. */
  648. function char2html($line,$latexmodifier,$char,$entitiyfragment) {
  649. $line = str_replace('\\'.$latexmodifier.$char,'&'.$char.''.$entitiyfragment.';', $line);
  650. $line = str_replace('\\'.$latexmodifier.'{'.$char.'}','&'.$char.''.$entitiyfragment.';', $line);
  651. $line = str_replace('\\'.$latexmodifier.strtoupper($char),'&'.strtoupper($char).''.$entitiyfragment.';', $line);
  652. $line = str_replace('\\'.$latexmodifier.'{'.strtoupper($char).'}','&'.strtoupper($char).''.$entitiyfragment.';', $line);
  653. return $line;
  654. }
  655. /** converts latex chars to HTML entities.
  656. (I still look for a comprehensive translation table from late chars to html, better than [[http://isdc.unige.ch/Newsletter/help.html]])
  657. */
  658. function latex2html($line) {
  659. $line = preg_replace('/([^\\\\])~/','\\1&nbsp;', $line);
  660. // performance increases with this test
  661. // bug found by Serge Barral: what happens if we have curly braces only (typically to ensure case in Latex)
  662. // added && strpos($line,'{')===false
  663. if (strpos($line,'\\')===false && strpos($line,'{')===false) return $line;
  664. // we should better replace this before the others
  665. // in order not to mix with the HTML entities coming after (just in case)
  666. $line = str_replace('\\&','&amp;', $line);
  667. // handling \url{....}
  668. // often used in howpublished for @misc
  669. $line = preg_replace('/\\\\url\{(.*)\}/U','<a href="\\1">\\1</a>', $line);
  670. // Friday, April 01 2011
  671. // added support for accented i
  672. // for instance \`\i
  673. // see http://en.wikibooks.org/wiki/LaTeX/Accents
  674. // " the letters "i" and "j" require special treatment when they are given accents because it is often desirable to replace the dot with the accent. For this purpose, the commands \i and \j can be used to produce dotless letters."
  675. $line = preg_replace('/\\\\([ij])/i','\\1', $line);
  676. $line = char2html($line,"'",'a',"acute");
  677. $line = char2html($line,"'",'e',"acute");
  678. $line = char2html($line,"'",'i',"acute");
  679. $line = char2html($line,"'",'o',"acute");
  680. $line = char2html($line,"'",'u',"acute");
  681. $line = char2html($line,"'",'y',"acute");
  682. $line = char2html($line,"'",'n',"acute");
  683. $line = char2html($line,'`','a',"grave");
  684. $line = char2html($line,'`','e',"grave");
  685. $line = char2html($line,'`','i',"grave");
  686. $line = char2html($line,'`','o',"grave");
  687. $line = char2html($line,'`','u',"grave");
  688. $line = char2html($line,'~','a',"tilde");
  689. $line = char2html($line,'~','n',"tilde");
  690. $line = char2html($line,'~','o',"tilde");
  691. $line = char2html($line,'"','a',"uml");
  692. $line = char2html($line,'"','e',"uml");
  693. $line = char2html($line,'"','i',"uml");
  694. $line = char2html($line,'"','o',"uml");
  695. $line = char2html($line,'"','u',"uml");
  696. $line = char2html($line,'"','y',"uml");
  697. $line = char2html($line,'^','a',"circ");
  698. $line = char2html($line,'^','e',"circ");
  699. $line = char2html($line,'^','i',"circ");
  700. $line = char2html($line,'^','o',"circ");
  701. $line = char2html($line,'^','u',"circ");
  702. $line = char2html($line,'.','a',"ring");
  703. $line = char2html($line,'c','c',"cedil");
  704. $line = str_replace('\\ae','&aelig;', $line);
  705. $line = str_replace('\\ss','&szlig;', $line);
  706. $line = str_replace('\\o','&oslash;', $line);
  707. $line = str_replace('\\O','&Oslash;', $line);
  708. $line = str_replace('\\aa','&aring;', $line);
  709. $line = str_replace('\\AA','&Aring;', $line);
  710. // clean out extra tex curly brackets, usually used for preserving capitals
  711. $line = str_replace('}','', $line);
  712. $line = str_replace('{','', $line);
  713. return $line;
  714. }
  715. /** encodes strings for Z3988 URLs. Note that & are encoded as %26 and not as &amp. */
  716. function s3988($s) {return urlencode(utf8_encode($s));}
  717. /**
  718. see BibEntry->formatAuthor($author)
  719. @deprecated
  720. @nodoc
  721. */
  722. function formatAuthor() {
  723. die('Sorry, this function does not exist anymore, however, you can simply use $bibentry->formatAuthor($author) instead.');
  724. }
  725. // ----------------------------------------------------------------------
  726. // BIB ENTRIES
  727. // ----------------------------------------------------------------------
  728. /** represents a bibliographic entry.
  729. usage:
  730. <pre>
  731. $db = zetDB('metrics.bib');
  732. $entry = $db->getEntryByKey('Schmietendorf2000');
  733. echo bib2html($entry);
  734. </pre>
  735. notes:
  736. - BibEntry are usually obtained with getEntryByKey or multisearch
  737. */
  738. class BibEntry {
  739. /** The fields (fieldName -> value) of this bib entry. */
  740. var $fields;
  741. /** The constants @STRINGS referred to by this entry */
  742. var $constants;
  743. /** The crossref entry if there is one */
  744. var $crossref;
  745. /** The verbatim copy (i.e., whole text) of this bib entry. */
  746. var $text;
  747. /** A timestamp to trace when entries have been created */
  748. var $timestamp;
  749. /** The name of the file containing this entry */
  750. var $filename;
  751. /** The short name of the entry (parameterized by ABBRV_TYPE) */
  752. var $abbrv;
  753. /** The index in a list of publications (e.g. [1] Foo */
  754. var $index = '';
  755. /** Creates an empty new bib entry. Each bib entry is assigned a unique
  756. * identification number. */
  757. function BibEntry() {
  758. $this->fields = array();
  759. $this->constants = array();
  760. $this->text ='';
  761. }
  762. /** Sets the name of the file containing this entry */
  763. function setFile($filename) {
  764. $this->filename = $filename;
  765. return $this;
  766. }
  767. /** Adds timestamp to this object */
  768. function setTimestamp() {
  769. $this->timestamp = time();
  770. }
  771. /** Returns the timestamp of this object */
  772. function getTimestamp() {
  773. return $this->timestamp;
  774. }
  775. /** Returns the type of this bib entry. */
  776. function getType() {
  777. // strtolower is important to be case-insensitive
  778. return strtolower($this->getField(Q_TYPE));
  779. }
  780. /** Sets the key of this bib entry. */
  781. function setKey($value) {
  782. $this->setField('key',$value);
  783. }
  784. /** Sets a field of this bib entry. */
  785. function setField($name, $value) {
  786. $name = strtolower($name);
  787. // fields that should not be transformed
  788. // we assume that "comment" is never latex code
  789. // but instead could contain HTML code (with links using the character "~" for example)
  790. // so "comment" is not transformed too
  791. if ($name!='url' && $name!='comment') {
  792. $value = xtrim($value);
  793. $value = latex2html($value);
  794. } else {
  795. //echo "xx".$value."xx\n";
  796. }
  797. $this->fields[$name] = $value;
  798. }
  799. /** Sets a type of this bib entry. */
  800. function setType($value) {
  801. // 2009-10-25 added trim
  802. // to support space e.g. "@article {"
  803. // as generated by ams.org
  804. // thanks to Jacob Kellner
  805. $this->fields[Q_TYPE] =trim($value);
  806. }
  807. function setIndex($index) { $this->index = $index; }
  808. /** Tries to build a good URL for this entry */
  809. function getURL() {
  810. if (defined('BIBTEXBROWSER_URL_BUILDER')) {
  811. $f = BIBTEXBROWSER_URL_BUILDER;
  812. return $f($this);
  813. }
  814. // echo $this->filename;
  815. // echo $this->getKey();
  816. return BIBTEXBROWSER_URL.'?'.createQueryString(array('key'=>$this->getKey(), Q_FILE=>$this->filename));
  817. }
  818. /** Tries to build a good absolute URL for this entry */
  819. function getAbsoluteURL() {
  820. if (defined('BIBTEXBROWSER_URL_BUILDER')) {
  821. $f = BIBTEXBROWSER_URL_BUILDER;
  822. return $f($this);
  823. }
  824. return "http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME']).'/'.$this->getURL();
  825. }
  826. /** returns a "[pdf]" link if relevant */
  827. function getUrlLink() {
  828. if ($this->hasField('url')) return ' <a'.(BIBTEXBROWSER_BIB_IN_NEW_WINDOW?' target="_blank" ':'').' href="'.$this->getField('url').'">[pdf]</a>';
  829. return '';
  830. }
  831. /** Reruns the abstract */
  832. function getAbstract() {
  833. if ($this->hasField('abstract')) return $this->getField('abstract');
  834. else return '';
  835. }
  836. /**
  837. * Returns the last name of an author name.
  838. */
  839. function getLastName($author){
  840. list($firstname, $lastname) = splitFullName($author);
  841. return $lastname;
  842. }
  843. /** Has this entry the given field? */
  844. function hasField($name) {
  845. return isset($this->fields[strtolower($name)]);
  846. }
  847. /** Returns the authors of this entry. If "author" is not given,
  848. * return a string 'Unknown'. */
  849. function getAuthor() {
  850. if (array_key_exists(AUTHOR, $this->fields)) {
  851. return $this->fields[AUTHOR];
  852. }
  853. // 2010-03-02: commented the following, it results in misleading author lists
  854. // issue found by Alan P. Sexton
  855. //if (array_key_exists(EDITOR, $this->fields)) {
  856. // return $this->fields[EDITOR];
  857. //}
  858. return 'Unknown';
  859. }
  860. /** Returns the key of this entry */
  861. function getKey() {
  862. return $this->getField('key');
  863. }
  864. /** Returns the title of this entry? */
  865. function getTitle() {
  866. return $this->getField('title');
  867. }
  868. /** Returns the publisher of this entry
  869. * It encodes a specific logic
  870. * */
  871. function getPublisher() {
  872. // citation_publisher
  873. if ($this->hasField("publisher")) {
  874. return $this->getField("publisher");
  875. }
  876. if ($this->getType()=="phdthesis") {
  877. return $this->getField(SCHOOL);
  878. }
  879. if ($this->getType()=="mastersthesis") {
  880. return $this->getField(SCHOOL);
  881. }
  882. if ($this->getType()=="bachelorsthesis") {
  883. return $this->getField(SCHOOL);
  884. }
  885. if ($this->getType()=="techreport") {
  886. return $this->getField("institution");
  887. }
  888. // then we don't know
  889. return '';
  890. }
  891. /** Returns the authors of this entry as an array */
  892. function getRawAuthors() {
  893. $authors = array();
  894. foreach (preg_split('/ and /i', $this->getAuthor()) as $author) {
  895. $authors[]=$author;
  896. }
  897. return $authors;
  898. }
  899. /**
  900. * Returns the formated author name w.r.t to the user preference encoded in COMMA_NAMES
  901. */
  902. function formatAuthor($author){
  903. if (COMMA_NAMES) {
  904. return $this->formatAuthorCommaSeparated($author);
  905. }
  906. else return $this->formatAuthorCanonical($author);
  907. }
  908. /**
  909. * Returns the formated author name as "FirstName LastName".
  910. */
  911. function formatAuthorCanonical($author){
  912. list($firstname, $lastname) = splitFullName($author);
  913. if ($firstname!='') return $firstname.' '.$lastname;
  914. else return $lastname;
  915. }
  916. /**
  917. * Returns the formated author name as "LastName, FirstName".
  918. */
  919. function formatAuthorCommaSeparated($author){
  920. list($firstname, $lastname) = splitFullName($author);
  921. if ($firstname!='') return $lastname.', '.$firstname;
  922. else return $lastname;
  923. }
  924. /** Returns the authors as a string depending on the configuration parameter COMMA_NAMES */
  925. function getFormattedAuthors() {
  926. $authors = array();
  927. foreach ($this->getRawAuthors() as $author) {
  928. $authors[]=$this->formatAuthor($author);
  929. }
  930. return $authors;
  931. }
  932. /** @deprecated
  933. * @see getFormattedAuthorsImproved()
  934. */
  935. function formattedAuthors() { return $this->getFormattedAuthorsImproved(); }
  936. /** Adds to getFormattedAuthors() the home page links and returns a string (not an array)
  937. */
  938. function getFormattedAuthorsImproved() {
  939. $array_authors = $this->getFormattedAuthors();
  940. foreach ($array_authors as $k => $author) {
  941. $array_authors[$k]=$this->addHomepageLink($author);
  942. }
  943. if (COMMA_NAMES) {$sep = '; ';} else {$sep = ', ';}
  944. return implode($sep ,$array_authors);
  945. }
  946. /** Returns the authors of this entry as an array in a canonical form */
  947. function getCanonicalAuthors() {
  948. $authors = array();
  949. foreach ($this->getRawAuthors() as $author) {
  950. $authors[]=$this->formatAuthorCanonical($author);
  951. }
  952. return $authors;
  953. }
  954. /** Returns the authors of this entry as an array in a comma-separated form */
  955. function getArrayOfCommaSeparatedAuthors() {
  956. $authors = array();
  957. foreach ($this->getRawAuthors() as $author) {
  958. $authors[]=$this->formatAuthorCommaSeparated($author);
  959. }
  960. return $authors;
  961. }
  962. /**
  963. * Returns a compacted string form of author names by throwing away
  964. * all author names except for the first one and appending ", et al."
  965. */
  966. function getCompactedAuthors($author){
  967. $authors = $this->getAuthors();
  968. $etal = count($authors) > 1 ? ', et al.' : '';
  969. return $this->formatAuthor($authors[0]) . $etal;
  970. }
  971. /** add the link to the homepage if it is defined in a string
  972. * e.g. @string{hp_MartinMonperrus="http://www.monperrus.net/martin"}
  973. * The string is a concatenation of firstname, lastname, prefixed by hp_
  974. * Warning: by convention @string are case sensitive so please be keep the same case as author names
  975. * @thanks Eric Bodden for the idea
  976. */
  977. function addHomepageLink($author) {
  978. // hp as home page
  979. // accents are handled normally
  980. // e.g. @STRING{hp_Jean-MarcJĂŠzĂŠquel="http://www.irisa.fr/prive/jezequel/"}
  981. $homepage = strtolower('hp_'.preg_replace('/ /', '', $author));
  982. if (isset($_GET[Q_DB]->stringdb[$homepage]))
  983. $author='<a href="'.$_GET[Q_DB]->stringdb[$homepage].'">'.$author.'</a>';
  984. return $author;
  985. }
  986. /** Returns the editors of this entry as an arry */
  987. function getEditors() {
  988. $editors = array();
  989. foreach (preg_split('/ and /i', $this->getField(EDITOR)) as $editor) {
  990. $editors[]=$editor;
  991. }
  992. return $editors;
  993. }
  994. /** Returns the editors of this entry as an arry */
  995. function getFormattedEditors() {
  996. $editors = array();
  997. foreach ($this->getEditors() as $editor) {
  998. $editors[]=$this->addHomepageLink($this->formatAuthor($editor));
  999. }
  1000. if (COMMA_NAMES) {$sep = '; ';} else {$sep = ', ';}
  1001. return implode($sep, $editors).', '.(count($editors)>1?'eds.':'ed.');
  1002. }
  1003. /** Returns the year of this entry? */
  1004. function getYear() {
  1005. return $this->getField('year');
  1006. }
  1007. /** Returns the value of the given field? */
  1008. function getField($name) {
  1009. // 2010-06-07: profiling showed that this is very costly
  1010. // hence returning the value directly
  1011. //if ($this->hasField($name))
  1012. // {return $this->fields[strtolower($name)];}
  1013. //else return 'missing '.$name;
  1014. return @$this->fields[strtolower($name)];
  1015. }
  1016. /** Returns the fields */
  1017. function getFields() {
  1018. return $this->fields;
  1019. }
  1020. /** Returns the abbreviation. */
  1021. function getAbbrv() {
  1022. if (ABBRV_TYPE == 'index') return $this->index;
  1023. if (ABBRV_TYPE == 'none') return '';
  1024. if (ABBRV_TYPE == 'key') return '['.$this->getKey().']';
  1025. if (ABBRV_TYPE == 'year') return '['.$this->getYear().']';
  1026. if (ABBRV_TYPE == 'x-abbrv') {
  1027. if ($this->hasField('x-abbrv')) {return $this->getField('x-abbrv');}
  1028. return $this->abbrv;
  1029. }
  1030. // otherwise it is a user-defined function in bibtexbrowser.local.php
  1031. $f = ABBRV_TYPE;
  1032. return $f($this);
  1033. }
  1034. /** Sets the abbreviation (e.g. [OOPSLA] or [1]) */
  1035. function setAbbrv($abbrv) {
  1036. //if (!is_string($abbrv)) { throw new Exception('Illegal argument'); }
  1037. $this->abbrv = $abbrv;
  1038. return $this;
  1039. }
  1040. function getText() {
  1041. /** Returns the verbatim text of this bib entry. */
  1042. return $this->text;
  1043. }
  1044. /** Returns true if this bib entry contains the given phrase
  1045. * in the given field. if $field is null, all fields are considered.
  1046. * Note that this method is NOT case sensitive */
  1047. function hasPhrase($phrase, $field = null) {
  1048. // 2010-01-25
  1049. // bug found by jacob kellner
  1050. // we have to search in the formatted fileds and not in the raw entry
  1051. // i.e. all latex markups are not considered for searches
  1052. // i.e. added join(" ",$this->getFields())
  1053. // and html_entity_decode
  1054. if (!$field) {
  1055. // warning html_entity_decode supports encoding since PHP5
  1056. return preg_match('/'.$phrase.'/i',$this->getConstants().' '.@html_entity_decode(join(" ",$this->getFields()),ENT_NOQUOTES,ENCODING));
  1057. //return stripos($this->getText(), $phrase) !== false;
  1058. }
  1059. if ($this->hasField($field) && (preg_match('/'.$phrase.'/i',$this->getField($field)) ) ) {
  1060. //if ($this->hasField($field) && (stripos($this->getField($field), $phrase) !== false) ) {
  1061. return true;
  1062. }
  1063. return false;
  1064. }
  1065. /** Outputs an HTML line (<tr>)with two TDS inside
  1066. */
  1067. function toTR() {
  1068. echo '<tr class="bibline">';
  1069. echo '<td class="bibref">';
  1070. //echo '<a name="'.$this->getId().'"></a>';
  1071. echo $this->getAbbrv().'</td> ';
  1072. echo '<td class="bibitem">';
  1073. echo bib2html($this);
  1074. $href = 'href="'.$this->getURL().'"';
  1075. if (BIBTEXBROWSER_BIBTEX_LINKS) {
  1076. // we add biburl and title to be able to retrieve this important information
  1077. // using Xpath expressions on the XHTML source
  1078. echo " <a".(BIBTEXBROWSER_BIB_IN_NEW_WINDOW?' target="_blank" ':'')." class=\"biburl\" title=\"".$this->getKey()."\" {$href}>[bibtex]</a>";
  1079. }
  1080. // returns an empty string if no url present
  1081. echo $this->getUrlLink();
  1082. if ($this->hasField('doi')) {
  1083. echo ' <a href="http://dx.doi.org/'.$this->getField("doi").'">[doi]</a>';
  1084. }
  1085. // Google Scholar ID
  1086. if ($this->hasField('gsid')) {
  1087. echo ' <a href="http://scholar.google.com/scholar?cites='.$this->getField("gsid").'">[cites]</a>';
  1088. }
  1089. echo "</td></tr>\n";
  1090. }
  1091. /** Outputs an coins URL: see http://ocoins.info/cobg.html
  1092. * Used by Zotero, mendeley, etc.
  1093. */
  1094. function toCoins() {
  1095. $url_parts=array();
  1096. $url_parts[]='ctx_ver=Z39.88-2004';
  1097. $type = $this->getType();
  1098. if ($type=="book") {
  1099. $url_parts[]='rft_val_fmt='.s3988('info:ofi/fmt:kev:mtx:book');
  1100. $url_parts[]='rft.btitle='.s3988($this->getTitle());
  1101. $url_parts[]='rft.genre=book';
  1102. } else if ($type=="inproceedings") {
  1103. $url_parts[]='rft_val_fmt='.s3988('info:ofi/fmt:kev:mtx:book');
  1104. $url_parts[]='rft.atitle='.s3988($this->getTitle());
  1105. $url_parts[]='rft.btitle='.s3988($this->getField(BOOKTITLE));
  1106. // zotero does not support with this proceeding and conference
  1107. // they give the wrong title
  1108. //$url_parts[]='rft.genre=proceeding';
  1109. //$url_parts[]='rft.genre=conference';
  1110. $url_parts[]='rft.genre=bookitem';
  1111. } else if ($type=="incollection" ) {
  1112. $url_parts[]='rft_val_fmt='.s3988('info:ofi/fmt:kev:mtx:book');
  1113. $url_parts[]='rft.btitle='.s3988($this->getField(BOOKTITLE));
  1114. $url_parts[]='rft.atitle='.s3988($this->getTitle());
  1115. $url_parts[]='rft.genre=bookitem';
  1116. } else if ($type=="article") {
  1117. $url_parts[]='rft_val_fmt='.s3988('info:ofi/fmt:kev:mtx:journal');
  1118. $url_parts[]='rft.atitle='.s3988($this->getTitle());
  1119. $url_parts[]='rft.jtitle='.s3988($this->getField("journal"));
  1120. $url_parts[]='rft.volume='.s3988($this->getField("volume"));
  1121. $url_parts[]='rft.issue='.s3988($this->getField("issue"));
  1122. } else { // techreport, phdthesis
  1123. $url_parts[]='rft_val_fmt='.s3988('info:ofi/fmt:kev:mtx:book');
  1124. $url_parts[]='rft.btitle='.s3988($this->getTitle());
  1125. $url_parts[]='rft.genre=report';
  1126. }
  1127. $url_parts[]='rft.pub='.s3988($this->getPublisher());
  1128. // referent
  1129. if ($this->hasField('url')) {
  1130. $url_parts[]='rft_id='.s3988($this->getField("url"));
  1131. } else if ($this->hasField('doi')) {
  1132. $url_parts[]='rft_id='.s3988('info:doi/'.$this->getField("doi"));
  1133. }
  1134. // referrer, the id pf a collection of objects
  1135. // see also http://www.openurl.info/registry/docs/pdf/info-sid.pdf
  1136. $url_parts[]='rfr_id='.s3988('info:sid/'.$_SERVER['HTTP_HOST'].':'.@$_GET[Q_FILE]);
  1137. $url_parts[]='rft.date='.s3988($this->getYear());
  1138. foreach ($this->getFormattedAuthors() as $au) $url_parts[]='rft.au='.s3988($au);
  1139. return '<span class="Z3988" title="'.implode('&amp;',$url_parts).'"></span>';
  1140. }
  1141. /**
  1142. * rebuild the set of constants used if any as a string
  1143. */
  1144. function getConstants() {
  1145. $result='';
  1146. foreach ($this->constants as $k=>$v) {
  1147. $result.='@string{'.$k.'="'.$v."\"}\n";
  1148. }
  1149. return $result;
  1150. }
  1151. /**
  1152. * Displays a <pre> text of the given bib entry.
  1153. * URLs are replaced by HTML links.
  1154. */
  1155. function toEntryUnformatted() {
  1156. $result = "";
  1157. $result .= '<pre class="purebibtex">'; // pre is nice when it is embedded with no CSS available
  1158. $entry = str_replace('<','&lt;',$this->getFullText());
  1159. if ($this->hasField('url')) {
  1160. $url = $this->getField('url');
  1161. // this is not a parsing but a simple replacement
  1162. $entry = str_replace($url,'<a href="'.$url.'">'.$url.'</a>', $entry);
  1163. }
  1164. $result .= $entry;
  1165. $result .= '</pre>';
  1166. return $result;
  1167. }
  1168. /**
  1169. * Gets the raw text of the entry (crossref + strings + entry)
  1170. */
  1171. function getFullText() {
  1172. $s = '';
  1173. // adding the crossref if necessary
  1174. if ($this->crossref!=null) { $s .= $this->crossref->getFullText()."\n";}
  1175. $s.=$this->getConstants();
  1176. $s.=$this->getText();
  1177. return $s;
  1178. }
  1179. }
  1180. /** this function encapsulates the user-defined name for bib to HTML*/
  1181. function bib2html(&$bibentry) {
  1182. $function = BIBLIOGRAPHYSTYLE;
  1183. return $function($bibentry);
  1184. }
  1185. /** encapsulates the user-defined sections. @nodoc */
  1186. function _DefaultBibliographySections() {
  1187. $function = BIBLIOGRAPHYSECTIONS;
  1188. return $function();
  1189. }
  1190. /** compares two instances of BibEntry by modification time
  1191. */
  1192. function compare_bib_entry_by_mtime($a, $b)
  1193. {
  1194. return -($a->getTimestamp()-$b->getTimestamp());
  1195. }
  1196. /** compares two instances of BibEntry by year
  1197. */
  1198. function compare_bib_entry_by_year_and_month($a, $b)
  1199. {
  1200. $year_cmp = -strcmp($a->getYear(),$b->getYear());
  1201. if ($year_cmp==0) { return compare_bib_entry_by_month($a, $b);}
  1202. return $year_cmp;
  1203. }
  1204. /** compares two instances of BibEntry by title
  1205. */
  1206. function compare_bib_entry_by_title($a, $b)
  1207. {
  1208. return strcmp($a->getTitle(),$b->getTitle());
  1209. }
  1210. /** compares two instances of BibEntry by month
  1211. * @author Jan Geldmacher
  1212. */
  1213. function compare_bib_entry_by_month($a, $b)
  1214. {
  1215. // this was the old behavior
  1216. // return strcmp($a->getKey(),$b->getKey());
  1217. //bibkey which is used for sorting
  1218. $sort_key = 'month';
  1219. //desired order of values
  1220. $sort_order_values = array('jan','january','feb','february','mar','march','apr','april','may','jun','june','jul','july','aug','august','sep','september','oct','october','nov','november','dec','december');
  1221. //order: 1=as specified in $sort_order_values or -1=reversed
  1222. $order = -1;
  1223. //first check if the search key exists
  1224. if (!array_key_exists($sort_key,$a->fields) && !array_key_exists($sort_key,$b->fields)) {
  1225. //neither a nor b have the key -> we compare the keys
  1226. $retval=strcmp($a->getKey(),$b->getKey());
  1227. }
  1228. elseif (!array_key_exists($sort_key,$a->fields)) {
  1229. //only b has the field -> b is greater
  1230. $retval=-1;
  1231. }
  1232. elseif (!array_key_exists($sort_key,$b->fields)) {
  1233. //only a has the key -> a is greater
  1234. $retval=1;
  1235. }
  1236. else {
  1237. //both have the key, sort using the order given in $sort_order_values
  1238. $val_a = array_search(strtolower($a->fields[$sort_key]), $sort_order_values);
  1239. $val_b = array_search(strtolower($b->fields[$sort_key]), $sort_order_values);
  1240. if (($val_a === FALSE && $val_b === FALSE) || ($val_a === $val_b)) {
  1241. //neither a nor b are in the search array or a=b -> both are equal
  1242. $retval=0;
  1243. }
  1244. elseif (($val_a === FALSE) || ($val_a < $val_b)) {
  1245. //a is not in the search array or a<b -> b is greater
  1246. $retval=-1;
  1247. }
  1248. elseif (($val_b === FALSE) || (($val_a > $val_b))){
  1249. //b is not in the search array or a>b -> a is greater
  1250. $retval=1;
  1251. }
  1252. }
  1253. return $order*$retval;
  1254. }
  1255. /** is the default sectioning for AcademicDisplay (books, articles, proceedings, etc. ) */
  1256. function DefaultBibliographySections() {
  1257. return
  1258. array(
  1259. // Books
  1260. array(
  1261. 'query' => array(Q_TYPE=>'book'),
  1262. 'title' => 'Books'
  1263. ),
  1264. // Journal / Bookchapters
  1265. array(
  1266. 'query' => array(Q_TYPE=>'article|incollection'),
  1267. 'title' => 'Refereed Articles and Book Chapters'
  1268. ),
  1269. // conference papers
  1270. array(
  1271. 'query' => array(Q_TYPE=>'inproceedings|conference',Q_EXCLUDE=>'workshop'),
  1272. 'title' => 'Refereed Conference Papers'
  1273. ),
  1274. // workshop papers
  1275. array(
  1276. 'query' => array(Q_TYPE=>'inproceedings',Q_SEARCH=>'workshop'),
  1277. 'title' => 'Refereed Workshop Papers'
  1278. ),
  1279. // misc and thesis
  1280. array(
  1281. 'query' => array(Q_TYPE=>'misc|phdthesis|mastersthesis|bachelorsthesis|techreport'),
  1282. 'title' => 'Other Publications'
  1283. )
  1284. );
  1285. }
  1286. /** transforms a $bibentry into an HTML string.
  1287. It is called by function bib2html if the user did not choose a specific style
  1288. the default usable CSS styles are
  1289. .bibtitle { font-weight:bold; }
  1290. .bibbooktitle { font-style:italic; }
  1291. .bibauthor { }
  1292. .bibpublisher { }
  1293. */
  1294. function DefaultBibliographyStyle(&$bibentry) {
  1295. $title = $bibentry->getTitle();
  1296. $type = $bibentry->getType();
  1297. // later on, all values of $entry will be joined by a comma
  1298. $entry=array();
  1299. // title
  1300. // usually in bold: .bibtitle { font-weight:bold; }
  1301. $title = '<span class="bibtitle">'.$title.'</span>';
  1302. if ($bibentry->hasField('url')) $title = ' <a'.(BIBTEXBROWSER_BIB_IN_NEW_WINDOW?' target="_blank" ':'').' href="'.$bibentry->getField("url").'">'.$title.'</a>';
  1303. // author
  1304. if ($bibentry->hasField('author')) {
  1305. $coreInfo = $title . ' <span class="bibauthor">('.$bibentry->getFormattedAuthorsImproved().')</span>';}
  1306. else $coreInfo = $title;
  1307. // core info usually contains title + author
  1308. $entry[] = $coreInfo;
  1309. // now the book title
  1310. $booktitle = '';
  1311. if ($type=="inproceedings") {
  1312. $booktitle = 'In '.$bibentry->getField(BOOKTITLE); }
  1313. if ($type=="incollection") {
  1314. $booktitle = 'Chapter in '.$bibentry->getField(BOOKTITLE);}
  1315. if ($type=="inbook") {
  1316. $booktitle = 'Chapter in '.$bibentry->getField('chapter');}
  1317. if ($type=="article") {
  1318. $booktitle = 'In '.$bibentry->getField("journal");}
  1319. //// we may add the editor names to the booktitle
  1320. $editor='';
  1321. if ($bibentry->hasField(EDITOR)) {
  1322. $editor = $bibentry->getFormattedEditors();
  1323. }
  1324. if ($editor!='') $booktitle .=' ('.$editor.')';
  1325. // end editor section
  1326. // is the booktitle available
  1327. if ($booktitle!='') {
  1328. $entry[] = '<span class="bibbooktitle">'.$booktitle.'</span>';
  1329. }
  1330. $publisher='';
  1331. if ($type=="phdthesis") {
  1332. $publisher = 'PhD thesis, '.$bibentry->getField(SCHOOL);
  1333. }
  1334. if ($type=="mastersthesis") {
  1335. $publisher = 'Master\'s thesis, '.$bibentry->getField(SCHOOL);
  1336. }
  1337. if ($type=="bachelorsthesis") {
  1338. $publisher = 'Bachelor\'s thesis, '.$bibentry->getField(SCHOOL);
  1339. }
  1340. if ($type=="techreport") {
  1341. $publisher = 'Technical report, '.$bibentry->getField("institution");
  1342. }
  1343. if ($type=="misc") {
  1344. $publisher = $bibentry->getField('howpublished');
  1345. }
  1346. if ($bibentry->hasField("publisher")) {
  1347. $publisher = $bibentry->getField("publisher");
  1348. }
  1349. if ($publisher!='') $entry[] = '<span class="bibpublisher">'.$publisher.'</span>';
  1350. if ($bibentry->hasField('volume')) $entry[] = "volume ".$bibentry->getField("volume");
  1351. if ($bibentry->hasField(YEAR)) $entry[] = $bibentry->getYear();
  1352. $result = implode(", ",$entry).'.';
  1353. // some comments (e.g. acceptance rate)?
  1354. if ($bibentry->hasField('comment')) {
  1355. $result .= " (".$bibentry->getField("comment").")";
  1356. }
  1357. if ($bibentry->hasField('note')) {
  1358. $result .= " (".$bibentry->getField("note").")";
  1359. }
  1360. // add the Coin URL
  1361. $result .= "\n".$bibentry->toCoins();
  1362. return $result;
  1363. }
  1364. /** is the Bibtexbrowser style contributed by Janos Tapolcai. It looks like the IEEE transaction style.
  1365. usage:
  1366. Add the following line in "bibtexbrowser.local.php"
  1367. <pre>
  1368. include( 'bibtexbrowser-style-janos.php' );
  1369. define('BIBLIOGRAPHYSTYLE','JanosBibliographyStyle');
  1370. </pre>
  1371. */
  1372. function JanosBibliographyStyle(&$bibentry) {
  1373. $title = $bibentry->getTitle();
  1374. $type = $bibentry->getType();
  1375. $entry=array();
  1376. // author
  1377. if ($bibentry->hasField('author')) {
  1378. $entry[] = $bibentry->formattedAuthors();
  1379. }
  1380. // title
  1381. $title = '"'.$title.'"';
  1382. if ($bibentry->hasField('url')) $title = ' <a'.(BIBTEXBROWSER_BIB_IN_NEW_WINDOW?' target="_blank" ':'').' href="'.$bibentry->getField("url").'">'.$title.'</a>';
  1383. $entry[] = $title;
  1384. // now the origin of the publication is in italic
  1385. $booktitle = '';
  1386. if (($type=="misc") && $bibentry->hasField("note")) {
  1387. $booktitle = $bibentry->getField("note");
  1388. }
  1389. if ($type=="inproceedings") {
  1390. $booktitle = 'In '.$bibentry->getField(BOOKTITLE);
  1391. }
  1392. if ($type=="incollection") {
  1393. $booktitle = 'Chapter in '.$bibentry->getField(BOOKTITLE);
  1394. }
  1395. if ($type=="article") {
  1396. $booktitle = 'In '.$bibentry->getField("journal");
  1397. }
  1398. //// ******* EDITOR
  1399. $editor='';
  1400. if ($bibentry->hasField(EDITOR)) {
  1401. $editor = $bibentry->getFormattedEditors();
  1402. }
  1403. if ($booktitle!='') {
  1404. if ($editor!='') $booktitle .=' ('.$editor.')';
  1405. $entry[] = '<i>'.$booktitle.'</i>';
  1406. }
  1407. $publisher='';
  1408. if ($type=="phdthesis") {
  1409. $publisher = 'PhD thesis, '.$bibentry->getField(SCHOOL);
  1410. }
  1411. if ($type=="mastersthesis") {
  1412. $publisher = 'Master\'s thesis, '.$bibentry->getField(SCHOOL);
  1413. }
  1414. if ($type=="techreport") {
  1415. $publisher = 'Technical report, '.$bibentry->getField("institution");
  1416. }
  1417. if ($bibentry->hasField("publisher")) {
  1418. $publisher = $bibentry->getField("publisher");
  1419. }
  1420. if ($publisher!='') $entry[] = $publisher;
  1421. if ($bibentry->hasField('volume')) $entry[] = "vol. ".$bibentry->getField("volume");
  1422. if ($bibentry->hasField('number')) $entry[] = 'no. '.$bibentry->getField("number");
  1423. if ($bibentry->hasField('address')) $entry[] = $bibentry->getField("address");
  1424. if ($bibentry->hasField('pages')) $entry[] = str_replace("--", "-", "pp. ".$bibentry->getField("pages"));
  1425. if ($bibentry->hasField(YEAR)) $entry[] = $bibentry->getYear();
  1426. $result = implode(", ",$entry).'.';
  1427. // some comments (e.g. acceptance rate)?
  1428. if ($bibentry->hasField('comment')) {
  1429. $result .= " (".$bibentry->getField("comment").")";
  1430. }
  1431. // add the Coin URL
  1432. $result .= "\n".$bibentry->toCoins();
  1433. return $result;
  1434. }
  1435. // ----------------------------------------------------------------------
  1436. // DISPLAY MANAGEMENT
  1437. // ----------------------------------------------------------------------
  1438. /** creates a query string given an array of parameter, with all specifities of bibtexbrowser_ (such as adding the bibtex file name &bib=foo.bib
  1439. */
  1440. function createQueryString($array_param) {
  1441. if (isset($_GET[Q_FILE]) && !isset($array_param[Q_FILE])) {
  1442. // first we add the name of the bib file
  1443. $array_param[Q_FILE] = urlencode($_GET[Q_FILE]);
  1444. }
  1445. // then a simple transformation and implode
  1446. foreach ($array_param as $key => $val) {
  1447. if($key == '_author') { $key = 'author'; }
  1448. $array_param[$key]=$key .'='. urlencode($val);
  1449. }
  1450. return implode("&amp;",$array_param);
  1451. }
  1452. /** returns a href string of the form: href="?bib=testing.bib&search=JML.
  1453. Based on createQueryString.
  1454. @nodoc
  1455. */
  1456. function makeHref($query = NULL) {
  1457. return 'href="?'. createQueryString($query) .'"';
  1458. }
  1459. /** returns the splitted name of an author name as an array. The argument is assumed to be
  1460. "FirstName LastName" or "LastName, FirstName".
  1461. */
  1462. function splitFullName($author){
  1463. $author = trim($author);
  1464. // the author format is "Joe Dupont"
  1465. if (strpos($author,',')===false) {
  1466. $parts=explode(' ', $author);
  1467. // get the last name
  1468. $lastname = array_pop($parts);
  1469. $firstname = implode(" ", $parts);
  1470. }
  1471. // the author format is "Dupont, J."
  1472. else {
  1473. $parts=explode(',', $author);
  1474. // get the last name
  1475. $lastname = str_replace(',','',array_shift($parts));
  1476. $firstname = implode(" ", $parts);
  1477. }
  1478. return array(trim($firstname), trim($lastname));
  1479. }
  1480. /** outputs an horizontal year-based menu
  1481. usage:
  1482. <pre>
  1483. $_GET['library']=1;
  1484. $_GET['bib']='metrics.bib';
  1485. $_GET['all']=1;
  1486. include( 'bibtexbrowser.php' );
  1487. setDB();
  1488. new IndependentYearMenu();
  1489. </pre>
  1490. */
  1491. class IndependentYearMenu {
  1492. function IndependentYearMenu() {
  1493. if (!isset($_GET[Q_DB])) {die('Did you forget to call setDB() before instantiating this class?');}
  1494. $yearIndex = $_GET[Q_DB]->yearIndex();
  1495. echo '<div id="yearmenu">Year: ';
  1496. $formatedYearIndex = array();
  1497. $formatedYearIndex[] = '<a '.makeHref(array(Q_YEAR=>'.*')).'>All</a>';
  1498. foreach($yearIndex as $year) {
  1499. $formatedYearIndex[] = '<a '.makeHref(array(Q_YEAR=>$year)).'>'.$year.'</a>';
  1500. }
  1501. // by default the separator is a |
  1502. echo implode('|',$formatedYearIndex);
  1503. echo '</div>';
  1504. }
  1505. }
  1506. /** Returns the powered by part. @nodoc */
  1507. function poweredby() {
  1508. $poweredby = "\n".'<div style="text-align:right;font-size: xx-small;opacity: 0.6;" class="poweredby">';
  1509. $poweredby .= '<!-- If you like bibtexbrowser, thanks to keep the link :-) -->';
  1510. $poweredby .= 'Powered by <a href="http://www.monperrus.net/martin/bibtexbrowser/">bibtexbrowser</a><!--v20120703-->';
  1511. $poweredby .= '</div>'."\n";
  1512. return $poweredby;
  1513. }
  1514. /** ^^adds a touch of AJAX in bibtexbrowser to display bibtex entries inline.
  1515. It uses the HIJAX design pattern: the Javascript code fetches the normal bibtex HTML page
  1516. and extracts the bibtex.
  1517. In other terms, URLs and content are left perfectly optimized for crawlers
  1518. Note how beautiful is this piece of code thanks to JQuery.^^
  1519. */
  1520. function javascript() {
  1521. // we use jquery with the official content delivery URLs
  1522. // Microsoft and Google also provide jquery with their content delivery networks
  1523. ?><script type="text/javascript" src="http://code.jquery.com/jquery-1.5.1.min.js"></script>
  1524. <script type="text/javascript" ><!--
  1525. // Javascript progressive enhancement for bibtexbrowser
  1526. $('a.biburl').each(function() { // for each url "[bibtex]"
  1527. var biburl = $(this);
  1528. if (biburl.attr('bibtexbrowser') === undefined)
  1529. {
  1530. biburl.click(function(ev) { // we change the click semantics
  1531. ev.preventDefault(); // no open url
  1532. if (biburl.nextAll('pre').length == 0) { // we don't have yet the bibtex data
  1533. var bibtexEntryUrl = $(this).attr('href');
  1534. $.ajax({url: bibtexEntryUrl, dataType: 'xml', success: function (data) { // we download it
  1535. // elem is the element containing bibtex entry, creating a new element is required for Chrome and IE
  1536. var elem = $('<pre class="purebibtex"/>');
  1537. elem.text($('.purebibtex', data).text()); // both text() are required for IE
  1538. // we add a link so that users clearly see that even with AJAX
  1539. // there is still one URL per paper (which is important for crawlers and metadata)
  1540. elem.append(
  1541. $('<div>%% Bibtex entry URL: <a href="'+bibtexEntryUrl+'">'+bibtexEntryUrl+'</a></div>')
  1542. ).appendTo(biburl.parent());
  1543. }, error: function() {window.location.href = biburl.attr('href');}});
  1544. } else {biburl.nextAll('pre').toggle();} // we toggle the view
  1545. });
  1546. biburl.attr('bibtexbrowser','done');
  1547. } // end if biburl.bibtexbrowser;
  1548. });
  1549. --></script><?php
  1550. } // end function javascript
  1551. /** is used for creating menus (by type, by year, by author, etc.).
  1552. usage:
  1553. <pre>
  1554. $db = zetDB('metrics.bib');
  1555. $menu = new MenuManager();
  1556. $menu->setDB($db);
  1557. $menu->year_size=100;// should display all years :)
  1558. $menu->display();
  1559. </pre>
  1560. */
  1561. class MenuManager {
  1562. /** The bibliographic database, an instance of class BibDataBase. */
  1563. var $db;
  1564. var $type_size = TYPES_SIZE;
  1565. var $year_size = YEAR_SIZE;
  1566. var $author_size = AUTHORS_SIZE;
  1567. var $tag_size = TAGS_SIZE;
  1568. function MenuManager() {
  1569. }
  1570. /** sets the database that is used to create the menu */
  1571. function setDB(&$db) {
  1572. $this->db =$db;
  1573. return $this;
  1574. }
  1575. function getTitle() {
  1576. return '';
  1577. }
  1578. /** function called back by HTMLWrapper */
  1579. function display() {
  1580. echo $this->searchView().'<br/>';
  1581. echo $this->typeVC().'<br/>';
  1582. echo $this->yearVC().'<br/>';
  1583. echo $this->authorVC().'<br/>';
  1584. echo $this->tagVC().'<br/>';
  1585. }
  1586. /** Displays the title in a table. */
  1587. function titleView() {
  1588. ?>
  1589. <table>
  1590. <tr>
  1591. <td class="title">Generated from <?php echo $_GET[Q_FILE]; ?></td>
  1592. </tr>
  1593. </table>
  1594. <?php
  1595. }
  1596. /** Displays the search view in a form. */
  1597. function searchView() {
  1598. ?>
  1599. <form action="?" method="get" target="<?php echo BIBTEXBROWSER_MENU_TARGET;?>">
  1600. <input type="text" name="<?php echo Q_SEARCH; ?>" class="input_box" size="18"/>
  1601. <input type="hidden" name="<?php echo Q_FILE; ?>" value="<?php echo $_GET[Q_FILE]; ?>"/>
  1602. <br/>
  1603. <input type="submit" value="search" class="input_box"/>
  1604. </form>
  1605. <?php
  1606. }
  1607. /** Displays and controls the types menu in a table. */
  1608. function typeVC() {
  1609. $types = array();
  1610. foreach ($this->db->getTypes() as $type) {
  1611. $types[$type] = $type;
  1612. }
  1613. $types[''] = 'all types';
  1614. // retreive or calculate page number to display
  1615. if (isset($_GET[Q_TYPE_PAGE])) {
  1616. $page = $_GET[Q_TYPE_PAGE];
  1617. }
  1618. else $page = 1;
  1619. $this->displayMenu('Types', $types, $page, $this->type_size, Q_TYPE_PAGE, Q_TYPE);
  1620. }
  1621. /** Displays and controls the authors menu in a table. */
  1622. function authorVC() {
  1623. // retrieve authors list to display
  1624. $authors = $this->db->authorIndex();
  1625. // determine the authors page to display
  1626. if (isset($_GET[Q_AUTHOR_PAGE])) {
  1627. $page = $_GET[Q_AUTHOR_PAGE];
  1628. }
  1629. else $page = 1;
  1630. $this->displayMenu('Authors', $authors, $page, $this->author_size, Q_AUTHOR_PAGE,
  1631. Q_AUTHOR);
  1632. }
  1633. /** Displays and controls the tag menu in a table. */
  1634. function tagVC() {
  1635. // retrieve authors list to display
  1636. $tags = $this->db->tagIndex();
  1637. // determine the authors page to display
  1638. if (isset($_GET[Q_TAG_PAGE])) {
  1639. $page = $_GET[Q_TAG_PAGE];
  1640. } else $page = 1;
  1641. if (count($tags)>0) $this->displayMenu('Keywords', $tags, $page, $this->tag_size, Q_TAG_PAGE,
  1642. Q_TAG);
  1643. }
  1644. /** Displays and controls the tag menu in a table. */
  1645. function yearVC() {
  1646. // retrieve authors list to display
  1647. $years = $this->db->yearIndex();
  1648. // determine the authors page to display
  1649. if (isset($_GET[Q_YEAR_PAGE])) {
  1650. $page = $_GET[Q_YEAR_PAGE];
  1651. }
  1652. else $page = 1;
  1653. $this->displayMenu('Years', $years, $page, $this->year_size, Q_YEAR_PAGE,
  1654. Q_YEAR);
  1655. }
  1656. /** Displays the main contents . */
  1657. function mainVC() {
  1658. $this->display->display();
  1659. }
  1660. /** Displays a list menu in a table.
  1661. *
  1662. * $title: title of the menu (string)
  1663. * $list: list of menu items (string)
  1664. * $page: page number to display (number)
  1665. * $pageSize: size of each page
  1666. * $pageKey: URL query name to send the page number to the server
  1667. * $targetKey: URL query name to send the target of the menu item
  1668. */
  1669. function displayMenu($title, $list, $page, $pageSize, $pageKey,
  1670. $targetKey) {
  1671. $numEntries = count($list);
  1672. $startIndex = ($page - 1) * $pageSize;
  1673. $endIndex = $startIndex + $pageSize;
  1674. ?>
  1675. <table style="width:100%" class="menu">
  1676. <tr>
  1677. <td>
  1678. <!-- this table is used to have the label on the left
  1679. and the navigation links on the right -->
  1680. <table style="width:100%" border="0" cellspacing="0" cellpadding="0">
  1681. <tr class="btb-nav-title">
  1682. <td><b><?php echo $title; ?></b></td>
  1683. <td class="btb-nav"><b>
  1684. <?php echo $this->menuPageBar($pageKey, $numEntries, $page,
  1685. $pageSize, $startIndex, $endIndex);?></b></td>
  1686. </tr>
  1687. </table>
  1688. </td>
  1689. </tr>
  1690. <tr>
  1691. <td class="btb-menu-items">
  1692. <?php $this->displayMenuItems($list, $startIndex, $endIndex,
  1693. $targetKey); ?>
  1694. </td>
  1695. </tr>
  1696. </table>
  1697. <?php
  1698. }
  1699. /** Returns a string to displays forward and reverse page controls.
  1700. *
  1701. * $queryKey: key to send the page number as a URL query string
  1702. * $page: current page number to display
  1703. * $numEntries: number of menu items
  1704. * $start: start index of the current page
  1705. * $end: end index of the current page
  1706. */
  1707. function menuPageBar($queryKey, $numEntries, $page, $pageSize,
  1708. $start, $end) {
  1709. $result = '';
  1710. // (1 page) reverse (<)
  1711. if ($start > 0) {
  1712. $href = makeHref(array($queryKey => $page - 1,'menu'=>''));//menuPageBar
  1713. $result .= '<a '. $href ."><b>[prev]</b></a>\n";
  1714. }
  1715. // (1 page) forward (>)
  1716. if ($end < $numEntries) {
  1717. $href = makeHref(array($queryKey => $page + 1,'menu'=>''));//menuPageBar
  1718. $result .= '<a '. $href ."><b>[next]</b></a>\n";
  1719. }
  1720. return $result;
  1721. }
  1722. /**
  1723. * Displays menu items (anchors) from the start index (inclusive) to
  1724. * the end index (exclusive). For each menu, the following form of
  1725. * string is printed:
  1726. *
  1727. * <a href="...?bib=cheon.bib&search_author=Yoonsik+Cheon">
  1728. * Cheon, Yoonsik</a>
  1729. * <div class="mini_se"></div>
  1730. */
  1731. function displayMenuItems($items, $startIndex, $endIndex, $queryKey) {
  1732. $index = 0;
  1733. foreach ($items as $key => $item) {
  1734. if ($index >= $startIndex && $index < $endIndex) {
  1735. $href = makeHref(array($queryKey => $key));
  1736. echo '<a '. $href .' target="'.BIBTEXBROWSER_MENU_TARGET.'">'. $item ."</a>\n";
  1737. echo "<div class=\"mini_se\"></div>\n";
  1738. }
  1739. $index++;
  1740. }
  1741. }
  1742. }
  1743. /** transforms an array representing a query into a formatted string */
  1744. function query2title(&$query) {
  1745. $headers = array();
  1746. foreach($query as $k=>$v) {
  1747. if($k == '_author') { $k = 'author'; }
  1748. if($k == 'type') { $v = substr($v,1,strlen($v)-2); }
  1749. $headers[$k] = ucwords($k).': '.ucwords($v);
  1750. }
  1751. // special cases
  1752. if (isset($headers[Q_ALL])) $headers[Q_ALL] = 'Publications in '.$_GET[Q_FILE];
  1753. if (isset($headers[Q_AUTHOR])) $headers[Q_AUTHOR] = 'Publications of '.$_GET[Q_AUTHOR];
  1754. return join(' &amp; ',$headers);
  1755. }
  1756. /** displays the latest modified bibtex entries.
  1757. usage:
  1758. <pre>
  1759. $db = zetDB('metrics.bib');
  1760. $d = new NewEntriesDisplay();
  1761. $d->setDB($db);
  1762. $d->setN(7);// optional
  1763. $d->display();
  1764. </pre>
  1765. */
  1766. class NewEntriesDisplay {
  1767. var $n=5;
  1768. var $db;
  1769. function setDB(&$bibdatabase) {
  1770. $this->db = $bibdatabase;
  1771. }
  1772. function setN($n) {$this->n = $n;return $this;}
  1773. /** sets the entries to be shown */
  1774. function setEntries(&$entries) {
  1775. $this->db = createBibDataBase();
  1776. $this->db->bibdb = $entries;
  1777. }
  1778. /** Displays a set of bibtex entries in an HTML table */
  1779. function display() {
  1780. $array = $this->db->getLatestEntries($this->n);
  1781. $delegate = createBasicDisplay();
  1782. $delegate->setEntries($array);
  1783. $delegate->display();
  1784. }
  1785. }
  1786. /** displays the entries by year in reverse chronological order.
  1787. usage:
  1788. <pre>
  1789. $db = zetDB('metrics.bib');
  1790. $d = new YearDisplay();
  1791. $d->setDB($db);
  1792. $d->display();
  1793. </pre>
  1794. */
  1795. class YearDisplay {
  1796. /** is an array of strings representing years */
  1797. var $yearIndex;
  1798. function setDB(&$bibdatabase) {
  1799. $this->setEntries($bibdatabase->bibdb);
  1800. }
  1801. /** creates a YearDisplay */
  1802. function setOptions(&$options) {}
  1803. function getTitle() {return '';}
  1804. /** sets the entries to be shown */
  1805. function setEntries(&$entries) {
  1806. $this->entries = $entries;
  1807. $db= createBibDataBase();
  1808. $db->bibdb = $entries;
  1809. $this->yearIndex = $db->yearIndex();
  1810. }
  1811. /** Displays a set of bibtex entries in an HTML table */
  1812. function display() {
  1813. $delegate = createBasicDisplay();
  1814. $delegate->setEntries($this->entries);
  1815. $index = count($this->entries);
  1816. foreach($this->yearIndex as $year) {
  1817. $x = array();
  1818. uasort($x,'compare_bib_entry_by_month');
  1819. foreach($this->entries as $e) {
  1820. if ($e->getYear() == $year) {
  1821. $x[] = $e;
  1822. }
  1823. }
  1824. if (count($x)>0) {
  1825. echo '<div class="btb-header">'.$year.'</div>';
  1826. $delegate->setEntries($x);
  1827. $delegate->display();
  1828. }
  1829. $index = $index - count($x);
  1830. }
  1831. }
  1832. }
  1833. /** displays the summary information of all bib entries.
  1834. usage:
  1835. <pre>
  1836. $db = zetDB('metrics.bib');
  1837. $d = new SimpleDisplay();
  1838. $d->setDB($db);
  1839. $d->display();
  1840. </pre>
  1841. */
  1842. class SimpleDisplay {
  1843. var $options = array();
  1844. function setDB(&$bibdatabase) {
  1845. $this->setEntries($bibdatabase->bibdb);
  1846. }
  1847. /** sets the entries to be shown */
  1848. function setEntries(&$entries) {
  1849. $this->entries = $entries;
  1850. }
  1851. function indexUp() {
  1852. $index=1;
  1853. foreach ($this->entries as $bib) {
  1854. $bib->setAbbrv((string)$index++);
  1855. } // end foreach
  1856. return $this->entries;
  1857. }
  1858. function newest(&$entries) {
  1859. return array_slice($entries,0,BIBTEXBROWSER_NEWEST);
  1860. }
  1861. function indexDown() {
  1862. $index=count($this->entries);
  1863. foreach ($this->entries as $bib) {
  1864. $bib->setAbbrv((string)$index--);
  1865. } // end foreach
  1866. return $this->entries;
  1867. }
  1868. function setTitle($title) { $this->title = $title; return $this; }
  1869. function getTitle() { return @$this->title ; }
  1870. /** Displays a set of bibtex entries in an HTML table */
  1871. function display() {
  1872. uasort($this->entries, ORDER_FUNCTION);
  1873. if ($this->options) {
  1874. foreach($this->options as $fname=>$opt) {
  1875. $this->$fname($opt,$entries);
  1876. }
  1877. }
  1878. if (BIBTEXBROWSER_DEBUG) {
  1879. echo 'Style: '.BIBLIOGRAPHYSTYLE.'<br/>';
  1880. echo 'Order: '.ORDER_FUNCTION.'<br/>';
  1881. echo 'Abbrv: '.ABBRV_TYPE.'<br/>';
  1882. echo 'Options: '.@implode(',',$this->options).'<br/>';
  1883. }
  1884. ?>
  1885. <table class="result" >
  1886. <?php
  1887. $count = count($this->entries);
  1888. $i=0;
  1889. foreach ($this->entries as $bib) {
  1890. // by default, index are in decrasing order
  1891. // so that when you add a publicaton recent , the indices of preceding publications don't change
  1892. $bib->setIndex('['.($count-($i++)).']');
  1893. $bib->toTR();
  1894. } // end foreach
  1895. ?>
  1896. </table>
  1897. <?php
  1898. } // end function
  1899. } // end class
  1900. /** returns an HTTP 404 and displays en error message. */
  1901. function nonExistentBibEntryError() {
  1902. header('HTTP/1.1 404 Not found');
  1903. ?>
  1904. <b>Sorry, this bib entry does not exist.</b>
  1905. <a href="?">Back to bibtexbrowser</a>
  1906. <?php
  1907. exit;
  1908. }
  1909. /** displays the publication records sorted by publication types (as configured by constant BIBLIOGRAPHYSECTIONS).
  1910. usage:
  1911. <pre>
  1912. $db = zetDB('metrics.bib');
  1913. $d = new AcademicDisplay();
  1914. $d->setDB($db);
  1915. $d->display();
  1916. </pre>
  1917. */
  1918. class AcademicDisplay {
  1919. function getTitle() { return $this->title; }
  1920. function setTitle($title) { $this->title = $title; return $this; }
  1921. function setDB(&$bibdatabase) {
  1922. $this->setEntries($bibdatabase->bibdb);
  1923. }
  1924. /** sets the entries to be shown */
  1925. function setEntries(&$entries) {
  1926. $this->entries = $entries;
  1927. }
  1928. /** transforms a query to HTML
  1929. * $ query is an array (e.g. array(Q_TYPE=>'book'))
  1930. * $title is a string, the title of the section
  1931. */
  1932. function search2html($query, $title) {
  1933. $entries = $this->db->multisearch($query);
  1934. uasort($entries, ORDER_FUNCTION);
  1935. if (count($entries)>0) {
  1936. echo "\n".'<div class="btb-header">'.$title.'</div>'."\n";
  1937. echo '<table class="result">'."\n";
  1938. // by default the abbreviation is incermented over all
  1939. // searches
  1940. // since we don't know before hand all section, we can not index in decreasing order
  1941. static $count;
  1942. if ($count == NULL) { $count = 1; } // init
  1943. $id = $count;
  1944. foreach ($entries as $bib) {
  1945. $bib->setIndex('['.($id++).']');
  1946. $bib->toTR();
  1947. } // end foreach
  1948. $count = @$count + count($entries);
  1949. echo '</table>';
  1950. }
  1951. }
  1952. function display() {
  1953. $this->db = createBibDataBase();
  1954. $this->db->bibdb = $this->entries;
  1955. foreach (_DefaultBibliographySections() as $section) {
  1956. $this->search2html($section['query'],$section['title']);
  1957. }
  1958. echo poweredby();
  1959. }
  1960. }
  1961. /** displays a single bib entry.
  1962. usage:
  1963. <pre>
  1964. $db = zetDB('metrics.bib');
  1965. $dis = new BibEntryDisplay($db->getEntryByKey('Schmietendorf2000'));
  1966. $dis->display();
  1967. </pre>
  1968. notes:
  1969. - the top-level header (usually &lt;H1>) must be done by the caller.
  1970. - this view is optimized for Google Scholar
  1971. */
  1972. class BibEntryDisplay {
  1973. /** the bib entry to display */
  1974. var $bib;
  1975. function BibEntryDisplay($bib=null) {
  1976. $this->bib = $bib;
  1977. }
  1978. function setEntries(&$entries) {
  1979. $this->bib = $entries[0];
  1980. //$this->title = $this->bib->getTitle().' (bibtex)'.$this->bib->getUrlLink();
  1981. }
  1982. /** returns the title */
  1983. function getTitle() {
  1984. return $this->bib->getTitle().' (bibtex)';
  1985. }
  1986. /** 2011/10/02: new display, inspired from Tom Zimmermann's home page */
  1987. function displayOnSteroids() {
  1988. $subtitle = '<div class="bibentry-by">by '.$this->bib->getFormattedAuthorsImproved().'</div>';
  1989. $abstract = '';
  1990. if ($this->bib->hasField('abstract')) {
  1991. $abstract = '<div class="bibentry-label">Abstract:</div><div class="bibentry-abstract">'.$this->bib->getAbstract().'</div>';
  1992. }
  1993. $download = '';
  1994. if ($this->bib->hasField('url')) {
  1995. $download = '<div class="bibentry-document-link"><a href="'.$this->bib->getField('url').'">View PDF</a></div>';
  1996. }
  1997. $reference= '<div class="bibentry-label">Reference:</div><div class="bibentry-reference">'.strip_tags(bib2html($this->bib)).'</div>';
  1998. $bibtex = '<div class="bibentry-label">Bibtex Entry:</div>'.$this->bib->toEntryUnformatted().'';
  1999. return $subtitle.$abstract.$download.$reference.$bibtex.$this->bib->toCoins();
  2000. }
  2001. function display() {
  2002. // we encapsulate everything so that the output of display() is still valid XHTML
  2003. echo '<div>';
  2004. //echo $this->display_old();
  2005. echo $this->displayOnSteroids();
  2006. echo poweredby();
  2007. echo '</div>';
  2008. }
  2009. // old display
  2010. function display_old() {
  2011. return $this->bib->toCoins().$this->bib->toEntryUnformatted();
  2012. }
  2013. /** Creates metadata for Google Scholar
  2014. * + a description
  2015. * @see http://scholar.google.com/intl/en/scholar/inclusion.html
  2016. * @see http://www.monperrus.net/martin/accurate+bibliographic+metadata+and+google+scholar
  2017. * */
  2018. function metadata() {
  2019. $result=array();
  2020. if (METADATA_GS) {
  2021. // the description may mix with the Google Scholar tags
  2022. // we remove it
  2023. // $result[] = array('description',trim(strip_tags(str_replace('"','',bib2html($this->bib)))));
  2024. $result[] = array('citation_title',$this->bib->getTitle());
  2025. $authors = $this->bib->getArrayOfCommaSeparatedAuthors();
  2026. $result[] = array('citation_authors',implode("; ",$authors));
  2027. foreach($authors as $author) {
  2028. $result[] = array('citation_author',$author);
  2029. }
  2030. $result[] = array('citation_publication_date',$this->bib->getYear());
  2031. // this page
  2032. $result[] = array('citation_abstract_html_url','http://'.$_SERVER['HTTP_HOST'].($_SERVER['SERVER_PORT']=='80'?'':$_SERVER['SERVER_PORT']).str_replace('&','&amp;',$_SERVER['REQUEST_URI']));
  2033. if ($this->bib->hasField("publisher")) {
  2034. $result[] = array('citation_publisher',$this->bib->getPublisher());
  2035. }
  2036. // BOOKTITLE: JOURNAL NAME OR PROCEEDINGS
  2037. if ($this->bib->getType()=="article") { // journal article
  2038. $result[] = array('citation_journal_title',$this->bib->getField("journal"));
  2039. $result[] = array('citation_volume',$this->bib->getField("volume"));
  2040. if ($this->bib->hasField("issue")) {
  2041. $result[] = array('citation_issue',$this->bib->getField("issue"));
  2042. }
  2043. if ($this->bib->hasField("issn")) {
  2044. $result[] = array('citation_issue',$this->bib->getField("issn"));
  2045. }
  2046. }
  2047. if ($this->bib->getType()=="inproceedings" || $this->bib->getType()=="conference") {
  2048. $result[] = array('citation_conference_title',$this->bib->getField(BOOKTITLE));
  2049. $result[] = array('citation_conference',$this->bib->getField(BOOKTITLE));
  2050. }
  2051. if ($this->bib->getType()=="phdthesis"
  2052. || $this->bib->getType()=="mastersthesis"
  2053. || $this->bib->getType()=="bachelorsthesis"
  2054. )
  2055. {
  2056. $result[] = array('citation_dissertation_institution',$this->bib->getField('school'));
  2057. }
  2058. if ($this->bib->getType()=="techreport"
  2059. && $this->bib->hasField("number")
  2060. )
  2061. {
  2062. $result[] = array('citation_technical_report_number',$this->bib->getField('number'));
  2063. }
  2064. if ($this->bib->getType()=="techreport"
  2065. && $this->bib->hasField("institution")
  2066. )
  2067. {
  2068. $result[] = array('citation_technical_report_institution',$this->bib->getField('institution'));
  2069. }
  2070. // generic
  2071. if ($this->bib->hasField("doi")) {
  2072. $result[] = array('citation_doi',$this->bib->getField("doi"));
  2073. }
  2074. if ($this->bib->hasField("url")) {
  2075. $result[] = array('citation_pdf_url',$this->bib->getField("url"));
  2076. }
  2077. }
  2078. // we don't introduce yet another kind of bibliographic metadata
  2079. // the core bibtex metadata will simply be available as json
  2080. // now adding the pure bibtex with no translation
  2081. //foreach ($this->bib->getFields() as $k => $v) {
  2082. // if (!preg_match("/^_/",$k)) {
  2083. // $result[] = array("bibtex:".$k,$v);
  2084. // }
  2085. //}
  2086. // a fallback to essential dublin core
  2087. // Dublin Core should not be used for bibliographic metadata
  2088. // according to several sources
  2089. // * Google Scholar: "Use Dublin Core tags (e.g., DC.title) as a last resort - they work poorly for journal papers"
  2090. // * http://reprog.wordpress.com/2010/09/03/bibliographic-data-part-2-dublin-cores-dirty-little-secret/
  2091. // however it seems that Google Scholar needs at least DC.Title to trigger referencing
  2092. // reference documentation: http://dublincore.org/documents/dc-citation-guidelines/
  2093. if (METADATA_DC) {
  2094. $result[] = array('DC.Title',$this->bib->getTitle());
  2095. foreach($this->bib->getArrayOfCommaSeparatedAuthors() as $author) {
  2096. $result[] = array('DC.Creator',$author);
  2097. }
  2098. $result[] = array('DC.Issued',$this->bib->getYear());
  2099. }
  2100. // --------------------------------- BEGIN METADATA EPRINTS
  2101. // and now adding eprints metadata
  2102. // why adding eprints metadata?
  2103. // because eprints is a well known bibliographic software and several crawlers/desktop software
  2104. // use their metadata
  2105. // unfortunately, the metadata is even less documented than Google Scholar citation_
  2106. // reference documentation: the eprints source code (./perl_lib/EPrints/Plugin/Export/Simple.pm)
  2107. // examples: conference paper: http://tubiblio.ulb.tu-darmstadt.de/44344/
  2108. // journal paper: http://tubiblio.ulb.tu-darmstadt.de/44344/
  2109. if (METADATA_EPRINTS) {
  2110. $result[] = array('eprints.title',$this->bib->getTitle());
  2111. $authors = $this->bib->getArrayOfCommaSeparatedAuthors();
  2112. foreach($authors as $author) {
  2113. $result[] = array('eprints.creators_name',$author);
  2114. }
  2115. $result[] = array('eprints.date',$this->bib->getYear());
  2116. if ($this->bib->hasField("publisher")) {
  2117. $result[] = array('eprints.publisher',$this->bib->getPublisher());
  2118. }
  2119. if ($this->bib->getType()=="article") { // journal article
  2120. $result[] = array('eprints.type','article');
  2121. $result[] = array('eprints.publication',$this->bib->getField("journal"));
  2122. $result[] = array('eprints.volume',$this->bib->getField("volume"));
  2123. if ($this->bib->hasField("issue")) {
  2124. $result[] = array('eprints.number',$this->bib->getField("issue"));}
  2125. }
  2126. if ($this->bib->getType()=="inproceedings" || $this->bib->getType()=="conference") {
  2127. $result[] = array('eprints.type','proceeding');
  2128. $result[] = array('eprints.book_title',$this->bib->getField(BOOKTITLE));
  2129. }
  2130. if ($this->bib->getType()=="phdthesis"
  2131. || $this->bib->getType()=="mastersthesis"
  2132. || $this->bib->getType()=="bachelorsthesis"
  2133. )
  2134. {
  2135. $result[] = array('eprints.type','thesis');
  2136. $result[] = array('eprints.institution',$this->bib->getField('school'));
  2137. }
  2138. if ($this->bib->getType()=="techreport")
  2139. {
  2140. $result[] = array('eprints.type','monograph');
  2141. if ($this->bib->hasField("number")) {
  2142. $result[] = array('eprints.number',$this->bib->getField('number'));
  2143. }
  2144. if ($this->bib->hasField("institution")) {
  2145. $result[] = array('eprints.institution',$this->bib->getField('institution'));
  2146. }
  2147. }
  2148. // generic
  2149. if ($this->bib->hasField("doi")) {
  2150. $result[] = array('eprints.id_number',$this->bib->getField("doi"));
  2151. }
  2152. if ($this->bib->hasField("url")) {
  2153. $result[] = array('eprints.official_url',$this->bib->getField("url"));
  2154. }
  2155. }
  2156. // --------------------------------- END METADATA EPRINTS
  2157. return $result;
  2158. }
  2159. }
  2160. // ----------------------------------------------------------------------
  2161. // DATABASE MANAGEMENT
  2162. // ----------------------------------------------------------------------
  2163. /** represents a bibliographic database that contains a set of bibliographic entries.
  2164. usage:
  2165. <pre>
  2166. $db = new BibDataBase();
  2167. $db->load('metrics.bib');
  2168. $query = array('author'=>'martin', 'year'=>2008);
  2169. foreach ($db->multisearch($query) as $bibentry) { echo $bibentry->getTitle(); }
  2170. </pre>
  2171. */
  2172. class BibDataBase {
  2173. /** A hash table from keys (e.g. Goody1994) to bib entries (BibEntry instances). */
  2174. var $bibdb;
  2175. /** A hashtable of constant strings */
  2176. var $stringdb;
  2177. /** Creates a new database by parsing bib entries from the given
  2178. * file. (backward compatibility) */
  2179. function load($filename) {
  2180. $this->update($filename);
  2181. }
  2182. /** Updates a database (replaces the new bibtex entries by the most recent ones) */
  2183. function update($filename) {
  2184. $empty_array = array();
  2185. $db = createBibDBBuilder();
  2186. $db->setData($empty_array, $this->stringdb);
  2187. $db->build($filename);
  2188. $this->stringdb = $db->stringdb;
  2189. $result = $db->builtdb;
  2190. foreach ($result as $b) {
  2191. // new entries:
  2192. if (!isset($this->bibdb[$b->getKey()])) {
  2193. //echo 'adding...<br/>';
  2194. $this->bibdb[$b->getKey()] = $b;
  2195. }
  2196. // update entry
  2197. else if (isset($this->bibdb[$b->getKey()]) && ($b->getText() !== $this->bibdb[$b->getKey()]->getText())) {
  2198. //echo 'replacing...<br/>';
  2199. $this->bibdb[$b->getKey()] = $b;
  2200. }
  2201. }
  2202. // some entries have been removed
  2203. foreach ($this->bibdb as $e) {
  2204. if (!isset($result[$e->getKey()])) {
  2205. //echo 'deleting...<br/>';
  2206. unset($this->bibdb[$e->getKey()]);
  2207. }
  2208. }
  2209. }
  2210. /** Creates a new empty database */
  2211. function BibDataBase() {
  2212. $this->bibdb = array();
  2213. $this->stringdb = array();
  2214. }
  2215. /** Returns the $n latest modified bibtex entries/ */
  2216. function getLatestEntries($n) {
  2217. $order='compare_bib_entry_by_mtime';
  2218. $array = $this->bibdb; // array passed by value
  2219. uasort($array, $order);
  2220. $result = array_slice($array,0,$n);
  2221. return $result;
  2222. }
  2223. /** Returns all entries as an array. Each entry is an instance of
  2224. * class BibEntry. */
  2225. function getEntries() {
  2226. return $this->bibdb;
  2227. }
  2228. /** tests wheter the database contains a bib entry with $key */
  2229. function contains($key) {
  2230. return isset($this->bibdb[$key]);
  2231. }
  2232. /** Returns all entries categorized by types. The returned value is
  2233. * a hashtable from types to arrays of bib entries.
  2234. */
  2235. function getEntriesByTypes() {
  2236. $result = array();
  2237. foreach ($this->bibdb as $b) {
  2238. $result[$b->getType()][] = $b;
  2239. }
  2240. return $result;
  2241. }
  2242. /** Returns an array containing all the bib types (strings). */
  2243. function getTypes() {
  2244. $result = array();
  2245. foreach ($this->bibdb as $b) {
  2246. $result[$b->getType()] = 1;
  2247. }
  2248. $result = array_keys($result);
  2249. return $result;
  2250. }
  2251. /** Generates and returns an array consisting of all authors.
  2252. * The returned array is a hash table with keys <FirstName LastName>
  2253. * and values <LastName, FirstName>.
  2254. */
  2255. function authorIndex(){
  2256. $result = array();
  2257. foreach ($this->bibdb as $bib) {
  2258. foreach($bib->getRawAuthors() as $a){
  2259. //we use an array because several authors can have the same lastname
  2260. @$result[$bib->getLastName($a)][$bib->formatAuthor($a)]++;
  2261. }
  2262. }
  2263. ksort($result);
  2264. // now authors are sorted by last name
  2265. // we rebuild a new array for having good keys in author page
  2266. $realresult = array();
  2267. foreach($result as $x) {
  2268. ksort($x);
  2269. foreach($x as $v => $tmp) $realresult[$v] = $v;
  2270. }
  2271. return $realresult;
  2272. }
  2273. /** Generates and returns an array consisting of all tags.
  2274. */
  2275. function tagIndex(){
  2276. $result = array();
  2277. foreach ($this->bibdb as $bib) {
  2278. if (!$bib->hasField("keywords")) continue;
  2279. $tags =preg_split('/[,;]/', $bib->getField("keywords"));
  2280. foreach($tags as $a){
  2281. $ta = trim($a);
  2282. $result[$ta] = $ta;
  2283. }
  2284. }
  2285. asort($result);
  2286. return $result;
  2287. }
  2288. /** Generates and returns an array consisting of all years.
  2289. */
  2290. function yearIndex(){
  2291. $result = array();
  2292. foreach ($this->bibdb as $bib) {
  2293. if (!$bib->hasField("year")) continue;
  2294. $year = $bib->getField("year");
  2295. $result[$year] = $year;
  2296. }
  2297. arsort($result);
  2298. return $result;
  2299. }
  2300. /** Given its key, return the bib entry. */
  2301. function getEntryByKey($key) {
  2302. return $this->bibdb[$key];
  2303. }
  2304. /**
  2305. * Returns an array containing all bib entries matching the given
  2306. * type.
  2307. */
  2308. function searchType($type){
  2309. $result = array();
  2310. foreach($this->bibdb as $bib) {
  2311. if($bib->getType() == $type)
  2312. $result[] = $bib;
  2313. }
  2314. return $result;
  2315. }
  2316. /** Returns an array of bib entries (BibEntry) that satisfy the query
  2317. * $query is an hash with entry type as key and searched fragment as value
  2318. */
  2319. function multisearch($query) {
  2320. if (count($query)<1) {return array();}
  2321. if (isset($query[Q_ALL])) return array_values($this->bibdb);
  2322. $result = array();
  2323. foreach ($this->bibdb as $bib) {
  2324. $entryisselected = true;
  2325. foreach ($query as $field => $fragment) {
  2326. if ($field==Q_SEARCH) {
  2327. // we search in the whole bib entry
  2328. if (!$bib->hasPhrase($fragment)) {
  2329. $entryisselected = false;
  2330. }
  2331. }
  2332. else if ($field==Q_EXCLUDE) {
  2333. if ($bib->hasPhrase($fragment)) {
  2334. $entryisselected = false;
  2335. }
  2336. }
  2337. else {
  2338. if (!$bib->hasPhrase($fragment, $field)) {
  2339. $entryisselected = false;
  2340. }
  2341. }
  2342. }
  2343. if ($entryisselected) {
  2344. $result[] = $bib;
  2345. }
  2346. }
  2347. return $result;
  2348. }
  2349. } // end class
  2350. /** returns the default CSS of bibtexbrowser */
  2351. function bibtexbrowserDefaultCSS() {
  2352. ?>
  2353. /* title */
  2354. .bibtitle { font-weight:bold; }
  2355. /* author */
  2356. .bibauthor { /* nothing by default */ }
  2357. /* booktitle (e.g. proceedings title, journal name, etc )*/
  2358. .bibbooktitle { font-style:italic; }
  2359. /* publisher */
  2360. .bibpublisher { /* nothing by default */ }
  2361. .title {
  2362. color: #003366;
  2363. font-size: large;
  2364. font-weight: bold;
  2365. text-align: right;
  2366. }
  2367. .btb-header {
  2368. background-color: #995124;
  2369. color: #FFFFFF;
  2370. padding: 1px 2px 1px 2px;
  2371. }
  2372. .btb-nav-title {
  2373. background-color: #995124;
  2374. color: #FFFFFF;
  2375. padding: 1px 2px 1px 2px;
  2376. }
  2377. .rheader {
  2378. font-weight: bold;
  2379. background-color: #003366;
  2380. color: #ffffff;
  2381. padding: 2px;
  2382. margin-bottom: 10px;
  2383. border-bottom: #ff6633 2px solid;
  2384. }
  2385. .menu {
  2386. font-size: x-small;
  2387. background-color: #EFDDB4;
  2388. padding: 0px;
  2389. border: 1px solid #000000;
  2390. margin: 0px;
  2391. }
  2392. .menu a {
  2393. text-decoration: none;
  2394. color: #003366;
  2395. }
  2396. .menu a:hover {
  2397. color: #ff6633;
  2398. }
  2399. .bibref {
  2400. padding:7px;
  2401. padding-left:15px;
  2402. vertical-align:text-top;
  2403. }
  2404. .result {
  2405. padding:0px;
  2406. border: 1px solid #000000;
  2407. margin:0px;
  2408. background-color: #ffffff;
  2409. width:100%;
  2410. }
  2411. .result a {
  2412. text-decoration: none;
  2413. color: #469AF8;
  2414. }
  2415. .result a:hover {
  2416. color: #ff6633;
  2417. }
  2418. .input_box{
  2419. margin-bottom : 2px;
  2420. }
  2421. .mini_se {
  2422. border: none 0;
  2423. border-top: 1px dashed #717171;
  2424. height: 1px;
  2425. }
  2426. .a_name a {
  2427. color:#469AF8;
  2428. width:130px;
  2429. }
  2430. .rsslink {
  2431. text-decoration: none;
  2432. color:#F88017;
  2433. /* could be fancy, see : http://www.feedicons.com/ for icons*/
  2434. /*background-image: url("rss.png"); text-indent: -9999px;*/
  2435. }
  2436. .purebibtex {
  2437. font-family: monospace;
  2438. font-size: small;
  2439. border: 1px solid #DDDDDD;
  2440. white-space:pre;
  2441. background: none repeat scroll 0 0 #F5F5F5;
  2442. padding:10px;
  2443. overflow:auto;
  2444. clear:both;
  2445. }
  2446. .bibentry-by { font-style: italic; }
  2447. .bibentry-abstract { margin:15px; }
  2448. .bibentry-label { margin-top:15px; }
  2449. .bibentry-reference { margin-bottom:15px; padding:10px; background: none repeat scroll 0 0 #F5F5F5; border: 1px solid #DDDDDD; }
  2450. .btb-nav { text-align: right; }
  2451. <?php
  2452. } // end function bibtexbrowserDefaultCSS
  2453. /** encapsulates the content of a delegate into full-fledged HTML (&lt;HTML>&lt;BODY> and TITLE)
  2454. usage:
  2455. <pre>
  2456. $db = zetDB('metrics.bib');
  2457. $dis = new BibEntryDisplay($db->getEntryByKey('Schmietendorf2000'));
  2458. new HTMLWrapper($dis);
  2459. </pre>
  2460. */
  2461. class HTMLWrapper {
  2462. /**
  2463. * $content: an object with methods
  2464. display()
  2465. getRSS()
  2466. getTitle()
  2467. * $title: title of the page
  2468. */
  2469. function HTMLWrapper(&$content,$metatags=array()/* an array name=>value*/) {
  2470. // when we load a page with AJAX
  2471. // the HTTP header is taken into account, not the <meta http-equiv>
  2472. header('Content-type: text/html; charset='.ENCODING);
  2473. echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
  2474. ?>
  2475. <html xmlns="http://www.w3.org/1999/xhtml">
  2476. <head>
  2477. <meta http-equiv="Content-Type" content="text/html; charset=<?php echo ENCODING ?>"/>
  2478. <meta name="generator" content="bibtexbrowser v20120703" />
  2479. <?php
  2480. // if ($content->getRSS()!='') echo '<link rel="alternate" type="application/rss+xml" title="RSS" href="'.$content->getRSS().'&amp;rss" />';
  2481. ?>
  2482. <?php
  2483. foreach($metatags as $item) {
  2484. list($name,$value) = $item;
  2485. echo '<meta name="'.$name.'" content="'.$value.'"/>'."\n";
  2486. } // end foreach
  2487. // now the title
  2488. if (method_exists($content, 'getTitle')) {
  2489. echo '<title>'.strip_tags($content->getTitle()).'</title>';
  2490. }
  2491. // now the CSS
  2492. echo '<style type="text/css"><!-- '."\n";
  2493. if (method_exists($content, 'getCSS')) {
  2494. echo $content->getCSS();
  2495. } else if (is_readable(dirname(__FILE__).'/bibtexbrowser.css')) {
  2496. readfile(dirname(__FILE__).'/bibtexbrowser.css');
  2497. }
  2498. else { bibtexbrowserDefaultCSS(); }
  2499. echo "\n".' --></style>';
  2500. ?>
  2501. </head>
  2502. <body>
  2503. <?php
  2504. if (method_exists($content, 'getTitle')) {
  2505. echo "<div class=\"rheader\">" . $content->getTitle() . "</div>";
  2506. }
  2507. ?>
  2508. <?php
  2509. $content->display();
  2510. if (BIBTEXBROWSER_USE_PROGRESSIVE_ENHANCEMENT) {
  2511. javascript();
  2512. }
  2513. ?>
  2514. </body>
  2515. </html>
  2516. <?php
  2517. //exit;
  2518. } // end constructor
  2519. }
  2520. /** does nothing but calls method display() on the content.
  2521. usage:
  2522. <pre>
  2523. $db = zetDB('metrics.bib');
  2524. $dis = new SimpleDisplay($db);
  2525. new NoWrapper($dis);
  2526. </pre>
  2527. */
  2528. class NoWrapper {
  2529. function NoWrapper(&$content) {
  2530. echo $content->display();
  2531. }
  2532. }
  2533. /** is used to create an subset of a bibtex file.
  2534. usage:
  2535. <pre>
  2536. $db = zetDB('metrics.bib');
  2537. $query = array('year'=>2005);
  2538. $dis = new BibtexDisplay()->setEntries($db->multisearch($query));
  2539. $dis->display();
  2540. </pre>
  2541. */
  2542. class BibtexDisplay {
  2543. function BibtexDisplay() {}
  2544. function setTitle($title) { $this->title = $title; return $this; }
  2545. /** sets the entries to be shown */
  2546. function setEntries(&$entries) {
  2547. $this->entries = $entries;
  2548. }
  2549. function setWrapper($x) { $x->wrapper = 'NoWrapper'; }
  2550. function display() {
  2551. header('Content-type: text/plain; charset='.ENCODING);
  2552. echo '% generated by bibtexbrowser <http://www.monperrus.net/martin/bibtexbrowser/>'."\n";
  2553. echo '% '.@$this->title."\n";
  2554. echo '% Encoding: '.ENCODING."\n";
  2555. foreach($this->entries as $bibentry) { echo $bibentry->getText()."\n"; }
  2556. exit;
  2557. }
  2558. }
  2559. /** creates paged output, e.g: [[http://localhost/bibtexbrowser/testPagedDisplay.php?page=1]]
  2560. usage:
  2561. <pre>
  2562. $_GET['library']=1;
  2563. include( 'bibtexbrowser.php' );
  2564. $db = zetDB('metrics.bib');
  2565. $pd = new PagedDisplay();
  2566. $pd->setEntries($db->bibdb);
  2567. $pd->display();
  2568. </pre>
  2569. */
  2570. class PagedDisplay {
  2571. var $query = array();
  2572. function PagedDisplay() {
  2573. $this->setPage();
  2574. }
  2575. /** sets the entries to be shown */
  2576. function setEntries(&$entries) {
  2577. uasort($entries, ORDER_FUNCTION);
  2578. $this->entries = array_values($entries);
  2579. }
  2580. /** sets $this->page from $_GET, defaults to 1 */
  2581. function setPage() {
  2582. $this->page = 1;
  2583. if (isset($_GET['page'])) {
  2584. $this->page = $_GET['page'];
  2585. }
  2586. }
  2587. function setQuery($query = array()) {
  2588. $this->query = $query;
  2589. }
  2590. function getTitle() {
  2591. return query2title($this->query). ' - page '.$this->page;
  2592. }
  2593. function display() {
  2594. $less = false;
  2595. if ($this->page>1) {$less = true;}
  2596. $more = true;
  2597. // computing $more
  2598. $index = ($this->page)*PAGE_SIZE;
  2599. if (!isset($this->entries[$index])) {
  2600. $more = false;
  2601. }
  2602. $this->menu($less, $more);
  2603. echo '<table class="result" >';
  2604. for ($i = 0; $i < PAGE_SIZE; $i++) {
  2605. $index = ($this->page-1)*PAGE_SIZE + $i;
  2606. if (isset($this->entries[$index])) {
  2607. $bib = $this->entries[$index];
  2608. $bib->toTR();
  2609. } else {
  2610. //break;
  2611. }
  2612. } // end foreach
  2613. echo '</table>';
  2614. $this->menu($less, $more);
  2615. }
  2616. function menu($less, $more) {
  2617. echo '<span class="nav-menu">';
  2618. $prev = $this->query;
  2619. $prev['page'] = $this->page-1;
  2620. if ($less == true) { echo '<a '.makeHref($prev).'">Prev Page</a>'; }
  2621. if ($less && $more) { echo '&nbsp;|&nbsp;'; }
  2622. $next = $this->query;
  2623. $next['page'] = $this->page+1;
  2624. if ($more == true) { echo '<a '.makeHref($next).'">Next Page</a>'; }
  2625. echo '</span>';
  2626. }
  2627. }
  2628. /** is used to create an RSS feed.
  2629. usage:
  2630. <pre>
  2631. $db = zetDB('metrics.bib');
  2632. $query = array('year'=>2005);
  2633. $rss = new RSSDisplay();
  2634. $entries = $db->getLatestEntries(10);
  2635. $rss->setEntries($entries);
  2636. $rss->display();
  2637. </pre>
  2638. */
  2639. class RSSDisplay {
  2640. var $title = 'RSS produced by bibtexbrowser';
  2641. function RSSDisplay() {
  2642. // nothing by default
  2643. }
  2644. function setTitle($title) { $this->title = $title; return $this; }
  2645. /** tries to always output a valid XML/RSS string
  2646. * based on ENCODING, HTML tags, and the transformations
  2647. * that happened in latex2html */
  2648. function text2rss($desc) {
  2649. // first strip HTML tags
  2650. $desc = strip_tags($desc);
  2651. // then decode characters encoded by latex2html
  2652. $desc= html_entity_decode($desc);
  2653. // some entities may still be here, we remove them
  2654. // we replace html entities e.g. &eacute; by nothing
  2655. // however XML entities are kept (e.g. &#53;)
  2656. $desc = preg_replace('/&\w+;/','',$desc);
  2657. // bullet proofing ampersand
  2658. $desc = preg_replace('/&([^#])/','&#38;$1',$desc);
  2659. // be careful of <
  2660. $desc = str_replace('<','&#60;',$desc);
  2661. // final test with encoding:
  2662. if (function_exists('mb_check_encoding')) { // (PHP 4 >= 4.4.3, PHP 5 >= 5.1.3)
  2663. if (!mb_check_encoding($desc,ENCODING)) {
  2664. return 'encoding error: please check the content of ENCODING';
  2665. }
  2666. }
  2667. return $desc;
  2668. }
  2669. /** sets the entries to be shown */
  2670. function setEntries(&$entries) {
  2671. $this->entries = $entries;
  2672. }
  2673. function setWrapper($x) { $x->wrapper = 'NoWrapper'; }
  2674. function display() {
  2675. header('Content-type: application/rss+xml');
  2676. echo '<?xml version="1.0" encoding="'.ENCODING.'"?>';
  2677. //
  2678. ?>
  2679. <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  2680. <channel>
  2681. <title><?php echo $this->title;?></title>
  2682. <link>http://<?php echo $_SERVER['HTTP_HOST'].htmlentities($_SERVER['REQUEST_URI']);?></link>
  2683. <atom:link href="http://<?php echo $_SERVER['HTTP_HOST'].htmlentities($_SERVER['REQUEST_URI']);?>" rel="self" type="application/rss+xml" />
  2684. <description></description>
  2685. <generator>bibtexbrowser v20120703</generator>
  2686. <?php
  2687. foreach($this->entries as $bibentry) {
  2688. ?>
  2689. <item>
  2690. <title><?php echo $this->text2rss($bibentry->getTitle());?></title>
  2691. <link><?php echo $bibentry->getAbsoluteURL();?></link>
  2692. <description>
  2693. <?php
  2694. // we are in XML, so we cannot have HTML entitites
  2695. // however the encoding is specified in preamble
  2696. echo $this->text2rss(bib2html($bibentry)."\n".$bibentry->getAbstract());
  2697. ?>
  2698. </description>
  2699. <guid isPermaLink="false"><?php echo urlencode(@$_GET[Q_FILE].'::'.$bibentry->getKey());?></guid>
  2700. </item>
  2701. <?php } /* end foreach */?>
  2702. </channel>
  2703. </rss>
  2704. <?php
  2705. //exit;
  2706. }
  2707. }
  2708. /** is responsible for transforming a query string of $_GET[..] into a publication list.
  2709. usage:
  2710. <pre>
  2711. $_GET['library']=1;
  2712. @require('bibtexbrowser.php');
  2713. // simulating ?bib=metrics.bib&year=2009
  2714. $_GET['bib']='metrics.bib';
  2715. $_GET['year']='2006';
  2716. new Dispatcher();
  2717. </pre>
  2718. */
  2719. class Dispatcher {
  2720. /** this is the query */
  2721. var $query = array();
  2722. /** the displayer of selected entries. The default is set in BIBTEXBROWSER_DEFAULT_DISPLAY.
  2723. * It could also be an RSSDisplay if the rss keyword is present
  2724. */
  2725. var $displayer = '';
  2726. /** the wrapper of selected entries. The default is an HTML wrapper
  2727. * It could also be a NoWrapper when you include your pub list in your home page
  2728. */
  2729. var $wrapper = 'HTMLWrapper';
  2730. function Dispatcher() {
  2731. // are we in test mode, or libray mode
  2732. // then this file is just a library
  2733. if (isset($_GET['test']) || isset($_GET['library'])) {
  2734. // we unset in order to use the dispatcher afterwards
  2735. unset($_GET['test']);
  2736. unset($_GET['library']);
  2737. return;
  2738. }
  2739. // first we set the database (load from disk or parse the bibtex file)
  2740. setDB();
  2741. // is the publication list included in another page?
  2742. // strtr is used for Windows where __FILE__ contains C:\toto and SCRIPT_FILENAME contains C:/toto (bug reported by Marco)
  2743. // realpath is required if the path contains sym-linked directories (bug found by Mark Hereld)
  2744. if (strtr(realpath(__FILE__),"\\","/")!=strtr(realpath($_SERVER['SCRIPT_FILENAME']),"\\","/")) $this->wrapper=BIBTEXBROWSER_EMBEDDED_WRAPPER;
  2745. // first pass, we will exit if we encounter key or menu or academic
  2746. // other wise we just create the $this->query
  2747. foreach($_GET as $keyword=>$value) {
  2748. if (method_exists($this,$keyword)) {
  2749. // if the return value is END_DISPATCH, we finish bibtexbrowser (but not the whole PHP process in case we are embedded)
  2750. if ($this->$keyword()=='END_DISPATCH') return;
  2751. }
  2752. }
  2753. // at this point, we may have a query
  2754. if (count($this->query)>0) {
  2755. // first test for inconsistent queries
  2756. if (isset($this->query[Q_ALL]) && count($this->query)>1) {
  2757. // we discard the Q_ALL, it helps in embedded mode
  2758. unset($this->query[Q_ALL]);
  2759. }
  2760. $selectedEntries = $_GET[Q_DB]->multisearch($this->query);
  2761. // default order
  2762. uasort($selectedEntries, ORDER_FUNCTION);
  2763. $selectedEntries = array_values($selectedEntries);
  2764. //echo '<pre>';print_r($selectedEntries);echo '</pre>';
  2765. if ($this->displayer=='') {
  2766. $this->displayer = BIBTEXBROWSER_DEFAULT_DISPLAY;
  2767. }
  2768. } // otherwise the query is left empty
  2769. // do we have a displayer?
  2770. if ($this->displayer!='') {
  2771. $options = array();
  2772. if (isset($_GET['dopt'])) {
  2773. $options = json_decode($_GET['dopt'],true);
  2774. }
  2775. // required for PHP4 to have this intermediate variable
  2776. $x = new $this->displayer();
  2777. if (method_exists($x,'setEntries')) {
  2778. $x->setEntries($selectedEntries);
  2779. }
  2780. if (method_exists($x,'setTitle')) {
  2781. $x->setTitle(query2title($this->query));
  2782. }
  2783. if (method_exists($x,'setQuery')) {
  2784. $x->setQuery($this->query);
  2785. }
  2786. if (method_exists($x,'setWrapper')) {
  2787. $x->setWrapper($this);
  2788. }
  2789. // should call method display() on $x
  2790. new $this->wrapper($x);
  2791. $this->clearQuery();
  2792. }
  2793. else {
  2794. // we send a redirection for having the frameset
  2795. // if some contents have already been sent, for instance if we are included
  2796. // this means doing nothing
  2797. if ( headers_sent() == false ) { /* to avoid sending an unnecessary frameset */
  2798. header("Location: ".$_SERVER['SCRIPT_NAME']."?frameset&bib=".$_GET[Q_FILE]);
  2799. }
  2800. }
  2801. }
  2802. /** clears the query string in $_GET so that bibtexbrowser can be called multiple times */
  2803. function clearQuery() {
  2804. $params= array(Q_ALL,'rss', 'astext', Q_SEARCH, Q_EXCLUDE, Q_YEAR, EDITOR, Q_TAG, Q_AUTHOR, Q_TYPE, Q_ACADEMIC, Q_KEY);
  2805. foreach($params as $p) { unset($_GET[$p]); }
  2806. }
  2807. function all() {
  2808. $this->query[Q_ALL]=1;
  2809. }
  2810. function display() {
  2811. $this->displayer=$_GET['display'];
  2812. }
  2813. function rss() {
  2814. $this->displayer='RSSDisplay';
  2815. $this->wrapper='NoWrapper';
  2816. }
  2817. function astext() {
  2818. $this->displayer='BibtexDisplay';
  2819. $this->wrapper='NoWrapper';
  2820. }
  2821. function search() {
  2822. if (preg_match('/utf-?8/i',ENCODING)) {
  2823. $_GET[Q_SEARCH] = urldecode($_GET[Q_SEARCH]);
  2824. }
  2825. $this->query[Q_SEARCH]=$_GET[Q_SEARCH];
  2826. }
  2827. function exclude() { $this->query[Q_EXCLUDE]=$_GET[Q_EXCLUDE]; }
  2828. function year() {
  2829. // we may want the latest
  2830. if ($_GET[Q_YEAR]=='latest') {
  2831. $years = $_GET[Q_DB]->yearIndex();
  2832. $_GET[Q_YEAR]=array_shift($years);
  2833. }
  2834. $this->query[Q_YEAR]=$_GET[Q_YEAR];
  2835. }
  2836. function editor() { $this->query[EDITOR]=$_GET[EDITOR]; }
  2837. function keywords() { $this->query[Q_TAG]=$_GET[Q_TAG]; }
  2838. function author() {
  2839. // Friday, October 29 2010
  2840. // changed fomr 'author' to '_author'
  2841. // because '_author' is already formatted
  2842. // doing so we can search at the same time "Joe Dupont" an "Dupont, Joe"
  2843. $this->query['_author']=$_GET[Q_AUTHOR];
  2844. }
  2845. function type() {
  2846. // remarks KEN
  2847. // "book" selects inbook, book, bookchapter
  2848. // so we add the regexp modifiers
  2849. if (strlen($_GET[Q_TYPE])>0 && !preg_match('/^\^.*\$$/',$_GET[Q_TYPE])) { $_GET[Q_TYPE] = '^'.$_GET[Q_TYPE].'$'; }
  2850. $this->query[Q_TYPE]= $_GET[Q_TYPE];
  2851. }
  2852. function menu() {
  2853. $menu = createMenuManager();
  2854. $menu->setDB($_GET[Q_DB]);
  2855. new $this->wrapper($menu,array(array('robots','noindex')));
  2856. return 'END_DISPATCH';
  2857. }
  2858. /** the academic keyword in URLs switch from a year based viey to a publication type based view */
  2859. function academic() {
  2860. $this->displayer='AcademicDisplay';
  2861. // backward compatibility with old GET API
  2862. // this is deprecated
  2863. // instead of academic=Martin+Monperrus
  2864. // you should use author=Martin+Monperrus&academic
  2865. // be careful of the semantics of === and !==
  2866. // 'foo bar' == true is true
  2867. // 123 == true is true (and whatever number different from 0
  2868. // 0 == true is true
  2869. // '1'!=1 is **false**
  2870. if(!isset($_GET[Q_AUTHOR]) && $_GET[Q_ACADEMIC]!==true && $_GET[Q_ACADEMIC]!=='true' && $_GET[Q_ACADEMIC]!=1 && $_GET[Q_ACADEMIC]!='') {
  2871. $_GET[Q_AUTHOR]=$_GET[Q_ACADEMIC];
  2872. $this->query[Q_AUTHOR]=$_GET[Q_ACADEMIC];
  2873. }
  2874. }
  2875. function key() {
  2876. if ($_GET[Q_DB]->contains($_GET[Q_KEY])) {
  2877. $bibentry = $_GET[Q_DB]->getEntryByKey($_GET[Q_KEY]);
  2878. $entries = array($bibentry);
  2879. if (isset($_GET['astext'])) {
  2880. $bibdisplay = new BibtexDisplay();
  2881. $bibdisplay->setEntries($entries);
  2882. $bibdisplay->display();
  2883. } else {
  2884. $bibdisplay = createBibEntryDisplay();
  2885. $bibdisplay->setEntries($entries);
  2886. new $this->wrapper($bibdisplay,$bibdisplay->metadata());
  2887. }
  2888. return 'END_DISPATCH';
  2889. }
  2890. else { nonExistentBibEntryError(); }
  2891. }
  2892. /** is used to remotely analyzed a situation */
  2893. function diagnosis() {
  2894. header('Content-type: text/plain');
  2895. echo "php version: ".phpversion()."\n";
  2896. echo "bibtexbrowser version: 20120703\n";
  2897. echo "dir: ".decoct(fileperms(dirname(__FILE__)))."\n";
  2898. echo "bibtex file: ".decoct(fileperms($_GET[Q_FILE]))."\n";
  2899. exit;
  2900. }
  2901. function frameset() { ?>
  2902. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
  2903. <html xmlns="http://www.w3.org/1999/xhtml">
  2904. <head>
  2905. <meta name="generator" content="bibtexbrowser v20120703" />
  2906. <meta http-equiv="Content-Type" content="text/html; charset=<?php echo ENCODING ?>"/>
  2907. <title>You are browsing <?php echo $_GET[Q_FILE]; ?> with bibtexbrowser</title>
  2908. </head>
  2909. <frameset cols="15%,*">
  2910. <frame name="menu" src="<?php echo '?'.Q_FILE.'='. urlencode($_GET[Q_FILE]).'&amp;menu'; ?>" />
  2911. <frame name="main" src="<?php echo '?'.Q_FILE.'='. urlencode($_GET[Q_FILE]).'&amp;year=latest'?>" />
  2912. </frameset>
  2913. </html>
  2914. <?php
  2915. return 'END_DISPATCH';
  2916. }
  2917. } // end class Dispatcher
  2918. } // end if (!defined('BIBTEXBROWSER'))
  2919. new Dispatcher();
  2920. ?>