From d3a9c5fb391e0fc2151c6a22480555509d284ee8 Mon Sep 17 00:00:00 2001 From: Martin Monperrus Date: Wed, 25 Nov 2009 23:00:00 +0000 Subject: [PATCH] *** empty log message *** --- bibtexbrowser.php | 348 ++++++++++++++++++++++++++++++---------------- 1 file changed, 228 insertions(+), 120 deletions(-) diff --git a/bibtexbrowser.php b/bibtexbrowser.php index 7598efe..2a2f538 100755 --- a/bibtexbrowser.php +++ b/bibtexbrowser.php @@ -1,41 +1,47 @@ -bibtexbrowser screenshot -=====Features===== - -* **New (10/2009)** bibtexbrowser is able to generate RSS feeds for all queries (simply add &rss at the end of the link)! People can subscribe to the publication feed of an individual or a group so as to being kept up-to-date. -* **New (10/2009)** bibtexbrowser is able to generate a bibtex file containing only the selected entries (simply add &astext at the end of the link) -* **New (10/2009)** bibtexbrowser is now independent of the configuration of register_globals -* **New (02/2009)** bibtexbrowser can display all entries for an author with an academic style [[http://www.monperrus.net/martin/bibtexbrowser.php?bib=metrics.bib&academic=Ducasse|demo]] -* **New (01/2009)** bibtexbrowser allows multi criteria search, e.g. [[http://www.monperrus.net/martin/bibtexbrowser.php?bib=metrics.bib&type=inproceedings&year=2004|demo]] -* **New (05/2008)**: bibtexbrowser can be used to include your publication list into your home page [[http://www.monperrus.net/martin/|demo]] -* bibtexbrowser can display the menu and all entries without filtering from the file name passed as parameter [[http://www.monperrus.net/martin/bibtexbrowser.php?bib=metrics.bib|demo]] -* bibtexbrowser can display all entries out of a bibtex file [[http://www.monperrus.net/martin/bibtexbrowser.php?bib=metrics.bib&all|demo]] -* bibtexbrowser can display all entries for a given year [[http://www.monperrus.net/martin/bibtexbrowser.php?bib=metrics.bib&year=2004|demo]] -* bibtexbrowser can display a single entry [[http://www.monperrus.net/martin/bibtexbrowser.php?bib=metrics.bib&key=monperrus08d|demo]] -* bibtexbrowser can display found entries with a search word (it can be in any bib field) [[http://www.monperrus.net/martin/bibtexbrowser.php?bib=metrics.bib&search=ocl|demo]] -* bibtexbrowser can display all entries with a bib keyword -* bibtexbrowser outputs valid XHTML 1.0 Transitional -* bibtexbrowser is designed to be search engine friendly. -* bibtexbrowser can display all entries for an author [[http://www.monperrus.net/martin/bibtexbrowser.php?bib=metrics.bib&author=Barbara+A.+Kitchenham|demo]] -* bibtexbrowser can be used with different encodings (change the default iso-8859-1 encoding if your bib file is in utf-8 ''define('ENCODING','utf-8')'' ) - -=====Standalone publication lists===== +=====How to create standalone publication lists===== 1) Create a bib file with the publication records (e.g. csgroup2008.bib) * Use the link ''bibtexbrowser.php?bib=csgroup2008.bib'' (frameset based view) @@ -91,7 +97,7 @@ And tailor it with a CSS style, for example: .bibline { padding:3px; padding-left:15px; vertical-align:top;} </style> -=====Adding links to the slides ===== +=====How to add links to the slides of a conference/workshop paper?===== You can simply fill the ''comment'' field of the bib entry with an HTML link: @@ -103,11 +109,13 @@ booktitle="Proceedings of the BIB conference", comment={<a href="myslides.pdf">slides</a>} } -=====Tailoring===== +=====How to modify the style?===== + +You may modify the embedded CSS style. -There are two ways to tailor bibtexbrowser: - 1/ change the embedded CSS style - 2/ change the parameters ENCODING, PAGE_SIZE and co at the end of this documentation ~ line 120 +You may modify the main parameters (e.g. ENCODING, PAGE_SIZE, etc ~ line 120) + +You may modify the BibEntry::toString() method. =====Related_tools===== @@ -120,8 +128,9 @@ Thus, you do not need to regenerate the static HTML files each time the bib file Furthermore you can search any string in it. Heavyweight: -[[http://www.rennes.supelec.fr/ren/perso/etotel/PhpBibtexDbMng/|PHP BibTeX Database Manager]], [[http://gforge.inria.fr/projects/bibadmin/|bibadmin]], [[http://artis.imag.fr/Software/Basilic/|basilic]], [[http://phpbibman.sourceforge.net/|phpbibman]], [[http://www.aigaion.nl/|aigaion]], [[http://www.refbase.net/|refbase]], [[http://wikindx.sourceforge.net/|wikindx]] -Unlike them, **bibtexbrowser does not need a MySQL database** and does not need a tedious import step each time the bib file is changed. +[[http://www.rennes.supelec.fr/ren/perso/etotel/PhpBibtexDbMng/|PHP BibTeX Database Manager]], [[http://gforge.inria.fr/projects/bibadmin/|bibadmin]], [[http://artis.imag.fr/Software/Basilic/|basilic]], [[http://phpbibman.sourceforge.net/|phpbibman]], [[http://www.aigaion.nl/|aigaion]], [[http://www.refbase.net/|refbase]], [[http://wikindx.sourceforge.net/|wikindx]], [[http://refdb.sourceforge.net/|refdb]] +Unlike them, **bibtexbrowser does not need a MySQL database** + Main competitors: [[http://code.google.com/p/simplybibtex/|SimplyBibtex]] has the same spirit and makes different architectural and presentation choices @@ -209,9 +218,16 @@ define('YEAR', 'year'); // default bib file, if no file is specified in the query string. if (!isset($_GET[Q_FILE])) { - header('HTTP/1.1 404 Not found'); - header('Content-type: text/plain');// to be validated by W3 - die('No bibtex file passed as parameter (e.g. bibtexbrowser.php?bib=mybib.php)'); +?> +Congratulations! bibtexbrowser is correctly installed!
+Now you have to pass the name of the bibtex file as parameter (e.g. bibtexbrowser.php?bib=mybib.php)
+You may browse:
+'.$bibfile.'
'; +} +exit; + } if (!file_exists($_GET[Q_FILE])) { @@ -224,14 +240,14 @@ if (!file_exists($_GET[Q_FILE])) { // 20091010: bibtexbrowser is again PHP4 compatible :-) /*if (ereg('^4',phpversion())) { ?> - You are using PHP v
+ You are using PHP v
bibtexbrowser requires a version of PHP >= 5 (PHP5)
QuickFix: you can try to add in .htaccess of the containing directory: SetEnv PHP_VER 5 - filemtime($compiledbib)) { - // no, then reparse - $db = new BibDataBase(); - $db->load($_GET[Q_FILE]); - $_GET[Q_DB]=$db; - } - else { - // yes then take it - $_GET[Q_DB] = unserialize(file_get_contents($compiledbib)); + // is it up to date ? wrt to the bib file and the script + // then upgrading with a new version of bibtexbrowser triggers a new compilation of the bib file + if (filemtime($_GET[Q_FILE])load($_GET[Q_FILE]); - $_GET[Q_DB]=$db; - - - // are we able to save the compiled version ? - if ((!is_file($compiledbib) && is_writable(dirname($compiledbib))) || (is_file($compiledbib) && is_writable($compiledbib)) ) { - // we can use file_put_contents - // but don't do it for compatibility with PHP 4.3 - $f = fopen($compiledbib,'w'); - fwrite($f,serialize($_GET[Q_DB])); - fclose($f); - } -} +if ($parse) { + //echo ''; + // then parsing the file + $db = new BibDataBase(); + $db->load($_GET[Q_FILE]); + $_GET[Q_DB]=$db; + // are we able to save the compiled version ? + if ((!is_file($compiledbib) && is_writable(dirname($compiledbib))) || (is_file($compiledbib) && is_writable($compiledbib)) ) { + // we can use file_put_contents + // but don't do it for compatibility with PHP 4.3 + $f = fopen($compiledbib,'w'); + //we use a lock to avoid that a call to bbtexbrowser made while we write the object loads an incorrect object + if (flock($f,LOCK_EX)) fwrite($f,serialize($_GET[Q_DB])); + fclose($f); + } + //else echo ''; +} // end parsing and saving @@ -392,12 +410,12 @@ for ( $i=0; $i < strlen( $sread ); $i++) { $s=$sread[$i]; // the end of the key and no value found: it is the bibtex key e.g. \cite{Descartes1637} else if ($s==',') { $state = GETKEY; - $delegate->setEntryField(trim($finalkey),$entryvalue); + $delegate->setEntryField(trim($finalkey),trim($entryvalue)); $entryvalue='';} // this is the end of the value AND of the entry else if ($s=='}') { $state = NOTHING;$isinentry = false; - $delegate->setEntryField(trim($finalkey),$entryvalue); + $delegate->setEntryField(trim($finalkey),trim($entryvalue)); $delegate->endEntry($entrysource); $entryvalue='';} else { $entryvalue=$entryvalue.$s;} @@ -472,6 +490,7 @@ for ( $i=0; $i < strlen( $sread ); $i++) { $s=$sread[$i]; /* handles entries delimited by double quotes */ else if ($state==GETVALUEDELIMITEDBYQUOTES) { + if ($s=='\\') { $state = GETVALUEDELIMITEDBYQUOTES_ESCAPED; $inentryvaluedelimitedB=$inentryvaluedelimitedB.$s;} @@ -479,7 +498,7 @@ for ( $i=0; $i < strlen( $sread ); $i++) { $s=$sread[$i]; $state = GETVALUE; $entryvalue=$entryvalue.$inentryvaluedelimitedB; $inentryvaluedelimitedB='';} - else { $inentryvaluedelimitedB=$inentryvaluedelimitedB.$s;} + else { $inentryvaluedelimitedB=@$inentryvaluedelimitedB.$s;} } // handle anti-double quotes else if ($state==GETVALUEDELIMITEDBYQUOTES_ESCAPED) { @@ -533,6 +552,9 @@ class BibDBBuilder { /** A hashtable from keys to bib entries (BibEntry). */ var $builtdb; + /** A hashtable of constant strings */ + var $stringdb; + var $currentEntry; function BibDBBuilder($filename) { @@ -542,16 +564,37 @@ class BibDBBuilder { function beginFile() { $builtdb = array(); + $stringdb = array(); } function endFile() { //nothing } function setEntryField($finalkey,$entryvalue) { + // first we set the key to lowercase + $finalkey=strtolower($finalkey); + + // is it a constant? then we replace the value + // we support advanced features of bibtexbrowser + // see http://newton.ex.ac.uk/tex/pack/bibtex/btxdoc/node3.html + $entryvalue_array=explode('#',$entryvalue); + foreach ($entryvalue_array as $k=>$v) { + $v=strtolower($v); + if (isset($this->stringdb[$v])) + { + // this field will be formated later by xtrim and latex2html + $entryvalue_array[$k]=$this->stringdb[$v]; + + // we keep a trace of this replacement + // so as to produce correct bibtex snippets + $this->currentEntry->constants[$v]=$this->stringdb[$v]; + } + } + $entryvalue=implode('',$entryvalue_array); if ($finalkey!='url') $formatedvalue = xtrim(latex2html($entryvalue)); else $formatedvalue = trim($entryvalue); - $this->currentEntry->setField(strtolower($finalkey),$formatedvalue); + $this->currentEntry->setField($finalkey,$formatedvalue); } function setEntryType($entrytype) { @@ -570,8 +613,15 @@ class BibDBBuilder { function endEntry($entrysource) { $this->currentEntry->text = $entrysource; - // ignoring string entries and jabref comments - if (($this->currentEntry->getType()!='comment') && ($this->currentEntry->getType()!='string')) { + // ignoring jabref comments + if (($this->currentEntry->getType()=='comment')) { + /* do nothing for jabref comments */ + } else if ($this->currentEntry->getType()=='string') { + foreach($this->currentEntry->fields as $k => $v) { + //echo $k.' '.$v; + $k!='type' and $this->stringdb[$k]=$v; + } + } else { $this->builtdb[$this->currentEntry->getKey()] = $this->currentEntry; } } @@ -614,6 +664,9 @@ function char2html($line,$latexmodifier,$char,$entitiyfragment) { * just have this http://isdc.unige.ch/Newsletter/help.html */ function latex2html($line) { + $line = ereg_replace('([^\\])~','\\1 ', $line); + + // performance increases with this test if (strpos($line,'\\')===false) return $line; $chars="abcdefghijklmnopqrstuvwxyz"; @@ -627,11 +680,12 @@ function latex2html($line) { } // special things - $line = str_replace('\\\c{c}','ç', $line); - $line = str_replace('\\\c{C}','Ç', $line); + $line = str_replace('\\c{c}','ç', $line); + $line = str_replace('\\c{C}','Ç', $line); $line = str_replace('\\o','ø', $line); $line = str_replace('\\O','Ø', $line); + $line = str_replace('\\&','&', $line); // clean out extra tex curly brackets, usually used for preserving capitals $line = str_replace('}','', $line); @@ -655,10 +709,11 @@ function s3988($s) {return urlencode(utf8_encode($s));} class BibEntry { /** The fields (fieldName -> value) of this bib entry. */ - - var $fields; + /** The constants @STRINGS referred to by this entry */ + var $constants; + /** The verbatim copy (i.e., whole text) of this bib entry. */ var $text; @@ -668,6 +723,7 @@ class BibEntry { static $id = 0; $this->id = $id++; $this->fields = array(); + $this->constants = array(); $this->text =''; } @@ -679,7 +735,8 @@ class BibEntry { /** Sets a field of this bib entry. */ function setField($name, $value) { - $this->fields[$name] = $value; + // bullet proofing with this strtolower + $this->fields[strtolower($name)] = $value; } /** Sets a type of this bib entry. */ @@ -690,7 +747,13 @@ class BibEntry { /** Tries to build a good URL for this entry */ function getURL() { if ($this->hasField('url')) return $this->getField('url'); - else return "http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME']).'/'.basename(__FILE__).'?bib='.$_GET[Q_FILE].'&key='.$this->getKey(); + else return "http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME']).'/'.basename(__FILE__).'?'.createQueryString(array('key'=>$this->getKey())); + } + + /** returns a "[pdf]" link if relevant */ + function getUrlLink() { + if ($this->hasField('url')) return ' [pdf]'; + return ''; } /** Reruns the abstract */ @@ -848,7 +911,7 @@ class BibEntry { * Note that this method is NOT case sensitive */ function hasPhrase($phrase, $field = null) { if (!$field) { - return eregi($phrase,$this->getText()); + return eregi($phrase,$this->getConstants().$this->getText()); //return stripos($this->getText(), $phrase) !== false; } if ($this->hasField($field) && (eregi($phrase,$this->getField($field)) ) ) { @@ -868,12 +931,11 @@ class BibEntry { echo ''; echo $this->toString(); - $href = 'href="'.basename(__FILE__).'?'.createQueryString(array(Q_KEY => urlencode($this->getKey()))).'"'; + $href = 'href="'.basename(__FILE__).'?'.createQueryString(array(Q_KEY => $this->getKey())).'"'; echo " [bib]"; - if ($this->hasField('url')) { - echo ' [pdf]'; - } + // returns an empty string if no url present + echo $this->getUrlLink(); if ($this->hasField('doi')) { echo ' [doi]'; @@ -941,7 +1003,7 @@ class BibEntry { foreach ($this->getFormattedAuthors() as $au) $url_parts[]='rft.au='.s3988($au); - return implode('&',$url_parts); + return ''; } @@ -1033,22 +1095,35 @@ class BibEntry { } // add the Coin URL - $result .= "\n".''; + $result .= "\n".$this->toCoins(); return $result; } + /** + * rebuild the set of constants used if any as a string + */ + function getConstants() { + $result=''; + foreach ($this->constants as $k=>$v) { + $result.='@string{'.$k.'="'.$v."\"}\n"; + } + return $result; + } + /** * Displays a unformated (verbatim) text of the given bib entry. - * The text is displayed in
tag. * The object may be mutated to read the rest of the fields. */ function toEntryUnformatted() { - $text =$this->getText(); - // Note this is exactly the initial formatting thanks to the PRE tag - ?> -
- '; + echo $this->getConstants(); + if ($this->hasField('url')) { + $url=$this->getField('url'); + // this is not a parsing but a simple replacement + echo str_replace($url,''.$url.'',$this->getText()); + } else echo $this->getText(); + echo ''; } } @@ -1066,11 +1141,10 @@ function createQueryString($array_param) { $array_param[Q_FILE] = urlencode($_GET[Q_FILE]); // then a simple transformation and implode - $qstring=""; foreach ($array_param as $key => $val) { - $array_param[$key]=$key .'='. $val; + $array_param[$key]=$key .'='. urlencode($val); } - return $qstring.implode("&",$array_param); + return implode("&",$array_param); } /** @@ -1106,7 +1180,7 @@ function splitFullName($author){ else { $parts=explode(',', $author); // get the last name - $lastname = array_shift($parts); + $lastname = str_replace(',','',array_shift($parts)); $firstname = implode(" ", $parts); } return array(trim($firstname), trim($lastname)); @@ -1192,6 +1266,7 @@ class MenuManager extends BibtexBrowserDisplay { /** Displays and controls the types menu in a table. */ function typeVC() { $types = array(); + $types[''] = 'all types'; foreach ($this->db->getTypes() as $type) { $types[$type] = $type; } @@ -1344,7 +1419,7 @@ else $page = 1; $index = 0; foreach ($items as $key => $item) { if ($index >= $startIndex && $index < $endIndex) { - $href = makeHref(array($queryKey => urlencode($key))); + $href = makeHref(array($queryKey => $key)); echo ''. $item ."\n"; echo "
\n"; } @@ -1440,7 +1515,7 @@ class PagedDisplay extends BibtexBrowserDisplay { } /** overrides */ - function formatedHeader() { return '
'.$this->title.' [rss]
';} + function formatedHeader() { return '
'.$this->title.' '.createRSSLink($this->filter).'
';} /** overrides */ function getURL() { return '?'.createQueryString($this->filter);} @@ -1536,6 +1611,14 @@ class PagedDisplay extends BibtexBrowserDisplay { } } +/** creates an RSS link with text or image depending on the environment */ + function createRSSLink($filter) { + // default label + $label='[rss]'; + // auto adaptive code :-) + //if (is_file('rss.png')) $label=''; + return ''.$label.''; +} /** @@ -1608,16 +1691,23 @@ class NonExistentBibEntryError { /** Class to display the publication records sorted by publication types. */ class AcademicDisplay extends BibtexBrowserDisplay { + /** the query */ + var $query; + /** * $entries: an array of bib entries * $query: the array representing the query */ function AcademicDisplay(&$entries,&$query) { + $this->query=$query; $this->db=new BibDataBase(); $this->db->bibdb = $entries; $this->title = query2title($query); } + /** overrides */ + function formatedHeader() { return '
'.$this->title.' '.createRSSLink($this->query).'
';} + function display() { echo $this->formatedHeader(); @@ -1704,22 +1794,28 @@ class BibEntryDisplay extends BibtexBrowserDisplay { */ function BibEntryDisplay(&$bibentry) { $this->bib = $bibentry; - $this->title = $this->bib->getTitle().' (bibtex bibliographic entry)'; + $this->title = $this->bib->getTitle().' (bibtex)'; + //$this->title = $this->bib->getTitle().' (bibtex)'.$this->bib->getUrlLink(); } + function display() { + echo $this->bib->toCoins(); echo $this->formatedHeader(); - echo ''; echo $this->bib->toEntryUnformatted(); + //echo $this->bib->getUrlLink(); + //echo $this->bib->toString(); echo $this->poweredby(); } /** Creates metadata for Google Scholar + * + a description * See http://www.monperrus.net/martin/accurate+bibliographic+metadata+and+google+scholar * */ function metadata() { $result=array(); + $result['description']=trim(strip_tags($this->bib->toString())); $result['citation_title']=$this->bib->getTitle(); $result['citation_authors']=implode('; ',$this->bib->getCommaSeparatedAuthors()); $result['citation_date']=$this->bib->getYear(); @@ -1848,6 +1944,7 @@ class BibDataBase { function tagIndex(){ $result = array(); foreach ($this->bibdb as $bib) { + if (!$bib->hasField("keywords")) continue; $tags =explode(' and ', $bib->getField("keywords")); foreach($tags as $a){ $ta = trim($a); @@ -1863,6 +1960,7 @@ class BibDataBase { function yearIndex(){ $result = array(); foreach ($this->bibdb as $bib) { + if (!$bib->hasField("year")) continue; $year = $bib->getField("year"); $result[$year] = $year; } @@ -1952,7 +2050,7 @@ function HTMLWrapper(&$content,$metatags=array()/* an array name=>value*/) { getRSS()!='') echo ''; ?> $value) echo ''."\n"; ?> -<?php echo $content->getTitle(); ?> +<?php echo strip_tags($content->getTitle()); ?> @@ -2060,7 +2158,7 @@ pre { display();?> - - <?=$this->title?> - http:// - + <?php echo $this->title;?> + http:// + bibtexbrowser v__DATE__ -results as $bibentry) { ?> - <?=$bibentry->getTitle()?> - getURL())?> + <?php echo $bibentry->getTitle();?> + getURL());?> - toString())?> - getAbstract())?> + toString()).htmlentities($bibentry->getAbstract()); + // we are in XML, so we cannot have HTML entitites + // however the encoding is specified in preamble + echo html_entity_decode($desc); + ?> - getKey()?> + getKey());?> - + -wrapper='NoWrapper'; + // strtr is used for Windows where __FILE__ contains C:\toto and SCRIPT_FILENAME contains C:/toto :-( + if (strtr(__FILE__,"\\","/")!=$_SERVER['SCRIPT_FILENAME']) $this->wrapper='NoWrapper'; // first pass, we will exit if we encounter key or menu or academic // other wise we just create the $this->query @@ -2207,7 +2313,9 @@ class Dispatcher { function keywords() { $this->query[Q_TAG]=$_GET[Q_TAG]; } - function author() { $this->query[Q_AUTHOR]=$_GET[Q_AUTHOR]; } + function author() { + $this->query[Q_AUTHOR]=$_GET[Q_AUTHOR]; + } function type() { $this->query[Q_TYPE]=$_GET[Q_TYPE]; }