/bibtexbrowser.php * displays the menu and all entries without filtering from the $filename hardcoded in the script * * /bibtexbrowser.php?bib=bibfile.bib * displays the menu and all entries without filtering from the file bibfile.bib * * /bibtexbrowser.php?bib=bibfile.bib&all * displays all entries * * /bibtexbrowser.php?bib=bibfile.bib&year=2004 * displays all entries from year 2004 * * /bibtexbrowser.php?bib=bibfile.bib&author="James+Russel" * displays all entries from author James Russel * * /bibtexbrowser.php?bib=bibfile.bib&tag=france * displays all entries with tag france * @book{discours-de-la-methode, * author = "René Descartes", * title = "Discours de la M{\'{e}}thode", * year = 1637, * tag="france and seventeenth century" * } */ define('READLINE_LIMIT',1024); define('PAGE_SIZE',25); define('YEAR_SIZE',10); define('Q_YEAR', 'year'); define('Q_YEAR_PAGE', 'year_page'); define('Q_FILE', 'bib'); define('AUTHORS_SIZE',20); define('Q_AUTHOR', 'author'); define('Q_AUTHOR_PAGE', 'author_page'); define('TAGS_SIZE',20); define('Q_TAG', 'tag'); define('Q_TAG_PAGE', 'tag_page'); define('Q_TYPE', 'type'); define('Q_TYPE_PAGE', 'type_page'); define('Q_ALL', 'all'); define('Q_ENTRY', 'entry'); define('Q_SEARCH', 'search'); define('Q_RESULT', 'result'); define('AUTHOR', 'author'); define('EDITOR', 'editor'); define('TITLE', 'title'); define('YEAR', 'year'); error_reporting(E_ERROR); session_start(); // default bib file, if no file is specified in the query string. $filename = "uml.bib"; // retrieve the filename sent as query or hidden data, if exists. if (isset($_GET[Q_FILE])) { $filename = urldecode($_GET[Q_FILE]); } // parse a new bib file, if requested if (isset($_SESSION[Q_FILE]) && isset($_SESSION['main']) && ($filename == $_SESSION[Q_FILE])) { $dispmgr = $_SESSION['main']; } else { $dispmgr = new DisplayManager(new BibDataBase($filename)); } $_SESSION[Q_FILE] = $filename; // stores the information in the session for performance $_SESSION['main'] = & $dispmgr; if (isset($_GET[Q_ENTRY])) { $headers=getallheaders(); $headers['date'] = time(); // ajout de la date $headers['file'] = $_GET[Q_FILE].'#'.$_GET[Q_ENTRY];//$dispmgr->db->getEntry($_GET[Q_ENTRY])->getTitle(); $headers['ip'] = $_SERVER["REMOTE_ADDR"]; $file = fopen ("log-bibtexbrowser.txt", "a"); fputs($file,serialize($headers)."\n"); fclose($file); } //////////////////////////////////////////////////////// /** * Class to parse a bibtex file. */ class BibParser { /** A hashtable from IDs (number) to bib entries (BibEntry). */ var $bibdb; /** Parses the given bibtex file and stores all entries to $bibdb. */ //@ assignable $bibdb; function BibParser($filename) { $file = fopen($filename, 'r'); $entry =$this->parseEntry($file); while ($entry) { $this->bibdb[$entry->getId()] = $entry; //if ($entry->getId() >= 500) { return; } // !FIXME! $entry =$this->parseEntry($file); //print_r($entry); } fclose($file); //print_r($this->bibdb); } /** Returns the array of parsed bib entires. */ function getEntries() { return $this->bibdb; } /** Parses and returns the next bib entry from the fiven file. If * no more entry exist, NULL is returned. */ function parseEntry($file) { // parse bib type, e.g., @BOOK{ while (true) { $raw_line = $this->nextLine($file); //echo 'RAW: ' . $raw_line; if (!$raw_line) { // EOF? return NULL; } $line = trim($raw_line); if (ereg("^@.*{", $line)) { //echo 'NEW: ' . $line . "\n"; $type = trim(substr($line, 1, strpos($line,'{') - 1)); $fields = array(); $raw_bib = $raw_line; break; } } // parse fields, if any $raw_line = $this->nextLine($file); while ($raw_line) { $raw_bib .= $raw_line; $line = trim($raw_line); if (ereg("^.*=", $line)) { // new field? //echo 'FIELD: ' . $line . "\n"; //get the field type $ps = strpos($line, '='); $fkey = strtolower(trim(substr($line,0,$ps))); $fval = $this->extractFieldValue($line); if (strlen($fval)) { $fields[$fkey] = $fval; } if (ereg(",[:space:]*}$",$line)) return $this->makeBibEntry($type, $fields, $raw_bib); if (ereg("=[^{]*}$",$line)) return $this->makeBibEntry($type, $fields, $raw_bib); } else if ($line == "}") { // end of entry? //echo 'END: ' . $line . "\n"; return $this->makeBibEntry($type, $fields, $raw_bib); } else { // continued field? $fval = $this->extractFieldValue($line); if (strlen($fval) > 0) { if (!isset($fields[$fkey])) { // no value seen so far? // remove starting " if exists if ($fval[0] == '"') { $fval = ltrim(substr($fval, 1)); } } if (strlen($fval)) { if (isset($fields[$fkey])) { $fields[$fkey] = $fields[$fkey].' '.$fval; } else { $fields[$fkey] = $fval; } } } } $raw_line = $this->nextLine($file); } // entry ended without a closing brace return $this->makeBibEntry($type, $fields, $raw_bib); } /** Creates and return a bib entry by doing any postprogessing to * the arguments. E.g., canonical rep. of type names. */ function makeBibEntry($type, $fields, $raw_bib) { // remove a trailing comma, if exists. foreach ($fields as $name => $value) { $fields[$name] = rtrim($value, ','); } return new BibEntry($this->stdType($type), $fields, $raw_bib); } /** Returns the canonical representation of the given type name. */ function stdType($type) { static $types = array(); foreach ($types as $t) { if (strcasecmp($t, $type) == 0) { return $t; } } $type = ucfirst($type); $types[] = $type; return $type; } /** Extracts and returns a field value from the given line. */ function extractFieldValue($line) { $result = ereg_replace("^[^=]*=[ :space:]*", '', $line); // clean out tex stuff $result = str_replace('}','', $result); $result = str_replace('{','', $result); $result = str_replace(',','', $result); $result = str_replace("\'", '', $result); // e.g., \'{e} $result = str_replace('\`', '', $result); $result = str_replace('\^', '', $result); $result = str_replace('"', '', $result); $result = str_replace('\~', '', $result); $result = str_replace('\.', '', $result); $result = str_replace('\u', '', $result); $result = str_replace('\v', '', $result); $result = str_replace('\H', '', $result); $result = str_replace('\t', '', $result); $result = str_replace('\c', '', $result); $result = str_replace('\d', '', $result); $result = str_replace('\b', '', $result); $result = str_replace('\i', 'i', $result); $result = str_replace('\j`', 'j', $result); $result = str_replace('\j`', 'j', $result); $result = str_replace('\ ', ' ',$result); // space return trim($result); } /** Returns the next non-empty line; returns NULL upon end-of-file. */ function nextLine($file) { $rawline = fgets($file, READLINE_LIMIT); while (!feof($file)) { //echo "RAW: " . $rawline; $line = trim($rawline); if (strpos($line, '@string') === false // !FIXME!@string ignored! && strlen($line) != 0 && $line[0] != '%') { return $rawline; } $rawline = fgets($file, READLINE_LIMIT); } return NULL; } } /** A class to parse a single bib entry starting from the given * source code line. */ class SingleEntryParser extends BibParser { function SingleEntryParser() { } /** Parses and returns an entry. */ function parse($filename, $startIndex) { $file = fopen($filename, 'r'); while ($startIndex > 0) { fgets($file, READLINE_LIMIT); $startIndex--; } $e =& $this->parseEntry($file); fclose($file); return $e; } } // ---------------------------------------------------------------------- // BIB ENTRIES // ---------------------------------------------------------------------- /** * Class to represent a bibliographic entry. */ class BibEntry { /** The type (e.g., article and book) of this bib entry. */ var $type; /** The fields (fieldName -> value) of this bib entry. */ var $fields; /** The verbatim copy (i.e., whole text) of this bib entry. */ var $text; /** Creates a new bib entry. Each bib entry is assigned a unique * identification number. */ function BibEntry($type, $fields = array(), $text = '') { static $id = 0; $this->id = $id++; $this->type = $type; $this->fields =& $fields; $this->text =& $text; } /** Returns the type of this bib entry. */ function getType() { return $this->type; } /** Has this entry the given field? */ function hasField($name) { return array_key_exists($name, $this->fields); } /** Returns the authors of this entry. If no author field exists, * returns the editors. If none of authors and editors exists, * return a string 'Unknown'. */ function getAuthor() { if (array_key_exists(AUTHOR, $this->fields)) { return $this->fields[AUTHOR]; } if (array_key_exists(EDITOR, $this->fields)) { return $this->fields[EDITOR]; } return 'Unknown'; } /** Returns the title of this entry? */ function getTitle() { return $this->getField('title'); } /** Returns the value of the given field? */ function getField($name) { if ($this->hasField($name)) {return $this->fields[$name];} else return 'missing '.$name; } /** Returns the fields */ function getFields() { return $this->fields; } /** Returns the identification number. */ function getId() { return $this->id; } /** Returns the verbatim text of this bib entry. */ function getText() { return $this->text; } /** Returns true if this bib entry contains the given phrase * in the given fields. The argument $fields is an array of * field names; if null, all fields are considered. */ function hasPhrase($phrase, $fields = null) { if (!$fields) { return strpos(strtolower($this->getText()), $phrase) !== false; } foreach ($fields as $f) { if ($this->hasField($f) && strpos(strtolower($this->getField($f)), $phrase) !== false) { return true; } } return false; } } // ---------------------------------------------------------------------- // DISPLAY MANAGEMENT // ---------------------------------------------------------------------- /** * Given a query, an array of key value pairs, returns a href string * of the form: href="bibtex.php?bib=testing.bib&search=JML. */ function makeHref($query = NULL) { global $filename; $qstring = Q_FILE .'='. urlencode($filename); if ($query) { foreach ($query as $key => $val) { $qstring .= '&'. $key .'='. $val; } } return 'href="'. $_SERVER['PHP_SELF'] .'?'. $qstring .'"'; } /** * Returns the formated author name. The argument is assumed to be * , and the return value is . */ function formatAuthor($author){ $author = trim($author); return trim(!strrchr($author, ' ') ? $author : strrchr($author, ' ') . ', ' .substr($author, 0, strrpos($author, " "))); } /** * Returns a compacted string form of author names by throwing away * all author names except for the first one and appending ", et al." */ function compactAuthor($author){ $authors = explode(" and ", $author); $etal = count($authors) > 1 ? ', et al.' : ''; return formatAuthor($authors[0]) . $etal; } /** * A class providing GUI views and controllers. In general, the views * are tables that can be incorporated into bigger GUI tables. */ class DisplayManager { /** The bibliographic database, an instance of class BibDataBase. */ var $db; /** Creates a new display manager that uses the given bib database. */ function DisplayManager(&$db) { $this->db =& $db; } /** Displays the title in a table. */ function titleView() { global $filename; ?>
Generated from


db->getTypes() as $type) { $types[$type] = $type; } // retreive or calculate page number to display if (isset($_GET[Q_TYPE_PAGE])) { $page = $_GET[Q_TYPE_PAGE]; } else $page = 1; $this->displayMenu('Types', $types, $page, 10, Q_TYPE_PAGE, Q_TYPE); } /** Displays and controls the authors menu in a table. */ function authorVC() { // retrieve authors list to display $authors = $this->db->authorIndex(); // determine the authors page to display if (isset($_GET[Q_AUTHOR_PAGE])) { $page = $_GET[Q_AUTHOR_PAGE]; } else $page = 1; $this->displayMenu('Authors', $authors, $page, AUTHORS_SIZE, Q_AUTHOR_PAGE, Q_AUTHOR); } /** Displays and controls the tag menu in a table. */ function tagVC() { // retrieve authors list to display $tags = $this->db->tagIndex(); // determine the authors page to display if (isset($_GET[Q_TAG_PAGE])) { $page = $_GET[Q_TAG_PAGE]; } else $page = 1; $this->displayMenu('Keywords', $tags, $page, TAGS_SIZE, Q_TAG_PAGE, Q_TAG); } /** Displays and controls the tag menu in a table. */ function yearVC() { // retrieve authors list to display $years = $this->db->yearIndex(); // determine the authors page to display if (isset($_GET[Q_YEAR_PAGE])) { $page = $_GET[Q_YEAR_PAGE]; } else $page = 1; $this->displayMenu('Years', $years, $page, YEAR_SIZE, Q_YEAR_PAGE, Q_YEAR); } /** Displays and controls the main contents (or result) view. */ function mainVC() { $result = null; if (isset($_GET[Q_ENTRY])){ $result = new SingleResultDisplay( $this->db->getEntry( $_GET[Q_ENTRY])); } else if (isset($_GET[Q_SEARCH])){ // search? $to_find = $_GET[Q_SEARCH]; $searched = $this->db->search($to_find); if (count($searched)==1) $result = new SingleResultDisplay($searched[0]); else { $header = 'Search: ' . trim($to_find); $result = new ResultDisplay($searched, $header,array(Q_SEARCH => $to_find)); } // clicking an author, a menu item from the authors menu? } else if (isset($_GET[Q_AUTHOR])) { $to_find = urldecode($_GET[Q_AUTHOR]); $searched = $this->db->search($to_find, array('author')); $header = 'Publications of ' . ucwords($to_find); $result = new ResultDisplay($searched, $header,array(Q_AUTHOR => $to_find)); // clicking a type, a menu item from the types menu? } else if(isset($_GET[Q_TAG])) { $to_find = $_GET[Q_TAG]; $searched = $this->db->search($to_find, array('keywords')); $header = 'Keyword: ' . ucwords($to_find); $result = new ResultDisplay($searched, $header,array(Q_TAG => $to_find)); } else if(isset($_GET[Q_YEAR])) { $to_find = $_GET[Q_YEAR]; $searched = $this->db->search($to_find, array('year')); $header = 'Year: ' . ucwords($to_find); $result = new ResultDisplay($searched, $header,array(Q_YEAR => $to_find)); } else if(isset($_GET[Q_TYPE])) { $to_find = $_GET[Q_TYPE]; $searched = $this->db->searchType($to_find); $header = 'Type: ' . ucwords($to_find); $result = new ResultDisplay($searched, $header,array(Q_TYPE => $to_find)); } else if(isset($_GET[Q_ALL])) { $to_find = $_GET[Q_ALL]; $searched = array_values($this->db->bibdb); $header = 'All'; $result = new ResultDisplay($searched, $header,array(Q_ALL =>'')); } // requesting a different page of the result view? if (isset($_GET[Q_RESULT])) { $result->setPage($_GET[Q_RESULT]); // requesting a differen page of type or author menus? } // display return $result; } /** Displays a list menu in a table. * * $title: title of the menu (string) * $list: list of menu items (string) * $page: page number to display (number) * $pageSize: size of each page * $pageKey: URL query name to send the page number to the server * $targetKey: URL query name to send the target of the menu item */ function displayMenu($title, $list, $page, $pageSize, $pageKey, $targetKey) { $numEntries = count($list); $startIndex = ($page - 1) * $pageSize; $endIndex = $startIndex + $pageSize; ?> 0) { $href = makeHref(array($queryKey => $page - 2,'menu'=>'')); $result .= '«\n"; } // (1 page) reverse (<) if ($start > 0) { $href = makeHref(array($queryKey => $page - 1,'menu'=>'')); $result .= '<\n"; } // (1 page) forward (>) if ($end < $numEntries) { $href = makeHref(array($queryKey => $page + 1,'menu'=>'')); $result .= '>\n"; } // fast (2 pages) forward (>>) if (($end + $pageSize) < $numEntries) { $href = makeHref(array($queryKey => $page + 2,'menu'=>'')); $result .= '»\n"; } return $result; } /** * Displays menu items (anchors) from the start index (inclusive) to * the end index (exclusive). For each menu, the following form of * string is printed: * * * Cheon, Yoonsik *
*/ function displayMenuItems($items, $startIndex, $endIndex, $queryKey) { $index = 0; foreach ($items as $key => $item) { if ($index >= $startIndex && $index < $endIndex) { $href = makeHref(array($queryKey => urlencode($key))); echo ''. $item ."\n"; echo "
\n"; } $index++; } } } /** Class to display a search result, a list of bib entries. */ class ResultDisplay { /** the bib entries to display. */ var $result; /** the header string. */ var $header; /** the page number to display. */ var $page; /** the original filter author, year, etc */ var $filter; /** Creates an instance with the given entries and header. */ function ResultDisplay(&$result, $header,$filter) { $this->result =& $result; $this->header = $header; $this->page = 1; $this->filter = $filter; } /** Sets the page number to display. */ function setPage($page) { $this->page = $page; } /** Displays the entries preceded with the header. */ function display() { $this->displayHeader($this->header); $this->displayContents(); } /** Displays the header stringg. */ function displayHeader() { $header = $this->header ? $this->header : " "; echo "
$header

\n"; } /** * Displays the summary information of each bib entries of the * current page. For each entry, this method displays the author, * title, and type; the bib entries are displayed grouped by the * publication years. If the bib list is empty, an error message is * displayed. */ function displayContents() { $biblist =& $this->result; $page = $this->page; // print error message if no entry. if (empty($biblist)) { echo "No match found!\n"; return; } // print a page bar, a list of clickable page numbers $pageSize = PAGE_SIZE; // no. of entries per page $noPages = ceil(count($biblist) / $pageSize); if ($noPages>1) $this->displayPageBar($noPages, $page); // create a year -> entries map to display by years $years = array(); foreach ($biblist as $e) { $y = trim($e->getField(YEAR)); $years[$y][] = $e; } krsort($years); $startIndex = ($page - 1) * $pageSize; $endIndex = $startIndex + $pageSize; $index = 0; ?> $entries) { if ($index >= $endIndex) { break; } if ($index >= $startIndex && $index < $endIndex) { ?> = $startIndex && $index < $endIndex) { $author = compactAuthor($bib->getAuthor()); $id = $bib->getId(); $title = $bib->getField(TITLE); $type = $bib->getType(); $href = makeHref(array(Q_ENTRY => $id)); ?>
>
()
0 ? $page - $barSize : 1; $end = min($noPages, $start + $barSize * 2); echo '
'; } } /** Class to display a single bibentry. */ class SingleResultDisplay extends ResultDisplay { /** Creates an instance with the given bib entry and header. * It the object is an instance of BibIndexEntry, it may be * mutated to read the rest of the fields. */ function SingleResultDisplay(&$bibentry) { $this->result =& $bibentry; $this->header = $this->result->getTitle(); } /** Displays the bib entry, both in the formatted and raw text. * The object may be mutated. */ function displayContents() { $entry =& $this->result; if ($entry) { $this->displayEntryFormatted($entry); echo '
BibTeX entry:
'; $this->displayEntryUnformatted($entry); } } /** * 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 displayEntryUnformatted(&$entry) { $text =$entry->getText(); ?>
getAuthor(); $type = $bib->getType(); // display heading: author (type) ?> getFields() as $name => $value) { if ($name == 'key') { continue; } // skip the key field // make href if URL $dval = $name == 'url' ? "$value" : $value; ?>
()
bibdb =$parser->getEntries(); } /** Returns all entries as an array. Each entry is an instance of * class BibEntry. */ function getEntries() { return $this->bibdb; } /** Returns all entries categorized by types. The returned value is * a hashtable from types to arrays of bib entries. */ function getEntriesByTypes() { $result = array(); foreach ($this->bibdb as $b) { $result[$b->getType()][] = $b; } return $result; } /** Given its ID, return the bib entry. */ function getEntry($id) { return $this->bibdb[$id]; } /** Returns an array containing all the bib types (strings). */ function getTypes() { $result = array(); foreach ($this->bibdb as $b) { $result[$b->getType()] = 1; } $result = array_keys($result); return $result; } /** Generates and returns an array consisting of all authors. * The returned array is a hash table with keys * and values . */ function authorIndex(){ $result = array(); foreach ($this->bibdb as $bib) { $authors =explode(' and ', $bib->getAuthor()); foreach($authors as $a){ $ta = trim($a); if (!array_key_exists($ta, $result)) { $result[$ta] = formatAuthor($ta); } } } asort($result); return $result; } /** Generates and returns an array consisting of all tags. */ function tagIndex(){ $result = array(); foreach ($this->bibdb as $bib) { $tags =explode(' and ', $bib->getField("keywords")); foreach($tags as $a){ $ta = trim($a); $result[$ta] = $ta; } } asort($result); return $result; } /** Generates and returns an array consisting of all years. */ function yearIndex(){ $result = array(); foreach ($this->bibdb as $bib) { $tags =explode(' and ', $bib->getField("year")); foreach($tags as $a){ $ta = trim($a); $result[$ta] = $ta; } } arsort($result); return $result; } /** * Returns an array containing all bib entries matching the given * type. */ function searchType($type){ $result = array(); foreach($this->bibdb as $bib) { if($bib->getType() == $type) $result[] = $bib; } return $result; } /** Returns an array of bib entries (BibEntry) that contains the * given phrase in the given fields. If the fields are empty, all * fields are searched. */ function search($phrase, $fields = NULL) { $phrase = strtolower(trim($phrase)); if (empty($phrase)) { return array(); } $result = array(); foreach ($this->bibdb as $bib) { if ($bib->hasPhrase($phrase, $fields)) { $result[] = $bib; } } //print_r($result); return $result; } } ?> mainVC(); ?> <? if ($result != null) echo $result->header.' in '.$filename; else echo 'bibtexbrowser: dynamic bibtex to HTML'; ?> '; echo $dispmgr->searchView(); echo $dispmgr->typeVC().'
'; echo $dispmgr->yearVC().'
'; echo $dispmgr->authorVC().'
'; echo $dispmgr->tagVC().'
'; echo ''; } // end isset($_GET['menu'] else { ?> '; $result->display(); echo 'Powered by bibtexbrowser'; echo ''; } else { ?>