|
|
Line 1: |
Line 1: |
− | <?php
| + | {{svn|http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/PdfBook}} |
− | # Extension:PdfBook{{Category:Extensions|PdfBook}}{{php}}{{Category:Extensions created with Template:Extension}}
| |
− | # - Licenced under LGPL (http://www.gnu.org/copyleft/lesser.html)
| |
− | # - Author: [http://www.organicdesign.co.nz/nad User:Nad]{{Category:Extensions in progress|PdfBook}}
| |
− | # - Started: 2007-08-08
| |
− | | |
− | if (!defined('MEDIAWIKI')) die('Not an entry point.');
| |
− | | |
− | define('PDFBOOK_VERSION','0.0.12, 2008-06-22');
| |
− | | |
− | $wgPdfBookMagic = "book";
| |
− | $wgExtensionFunctions[] = 'wfSetupPdfBook';
| |
− | $wgHooks['LanguageGetMagic'][] = 'wfPdfBookLanguageGetMagic';
| |
− | | |
− | $wgExtensionCredits['parserhook'][] = array(
| |
− | 'name' => 'Pdf Book',
| |
− | 'author' => '[http://www.organicdesign.co.nz/nad User:Nad]',
| |
− | 'description' => 'Composes a book from articles in a category and exports as a PDF book',
| |
− | 'url' => 'http://www.mediawiki.org/wiki/Extension:Pdf_Book',
| |
− | 'version' => PDFBOOK_VERSION
| |
− | );
| |
− | | |
− | class PdfBook {
| |
− | | |
− | # Constructor
| |
− | function PdfBook() {
| |
− | global $wgHooks,$wgParser,$wgPdfBookMagic;
| |
− | $wgParser->setFunctionHook($wgPdfBookMagic,array($this,'magicBook'));
| |
− | $wgHooks['UnknownAction'][] = $this;
| |
− | | |
− | # Add a new pdf log type
| |
− | global $wgLogTypes,$wgLogNames,$wgLogHeaders,$wgLogActions;
| |
− | $wgLogTypes[] = 'pdf';
| |
− | $wgLogNames ['pdf'] = 'pdflogpage';
| |
− | $wgLogHeaders['pdf'] = 'pdflogpagetext';
| |
− | $wgLogActions['pdf/book'] = 'pdflogentry';
| |
− | }
| |
− | | |
− | # Expand the book-magic
| |
− | function magicBook(&$parser) {
| |
− | | |
− | # Populate $argv with both named and numeric parameters
| |
− | $argv = array();
| |
− | foreach (func_get_args() as $arg) if (!is_object($arg)) {
| |
− | if (preg_match('/^(.+?)\\s*=\\s*(.+)$/',$arg,$match)) $argv[$match[1]] = $match[2]; else $argv[] = $arg;
| |
− | }
| |
− | | |
− | return $text;
| |
− | }
| |
− | | |
− | function onUnknownAction($action,$article) {
| |
− | global $wgOut,$wgUser,$wgTitle,$wgParser;
| |
− | global $wgServer,$wgArticlePath,$wgScriptPath,$wgUploadPath,$wgUploadDirectory,$wgScript;
| |
− | | |
− | if ($action == 'pdfbook') {
| |
− | | |
− | # Log the export
| |
− | $msg = $wgUser->getUserPage()->getPrefixedText().' exported as a PDF book';
| |
− | $log = new LogPage('pdf',false);
| |
− | $log->addEntry('book',$wgTitle,$msg);
| |
− | | |
− | # Initialise PDF variables
| |
− | $layout = '--firstpage toc';
| |
− | $left = $this->setProperty('LeftMargin', '1cm');
| |
− | $right = $this->setProperty('RightMargin', '1cm');
| |
− | $top = $this->setProperty('TopMargin', '1cm');
| |
− | $bottom = $this->setProperty('BottomMargin','1cm');
| |
− | $font = $this->setProperty('Font', 'Arial');
| |
− | $size = $this->setProperty('FontSize', '8');
| |
− | $link = $this->setProperty('LinkColour', '217A28');
| |
− | $levels = $this->setProperty('TocLevels', '2');
| |
− | $exclude = $this->setProperty('Exclude', array());
| |
− | if (!is_array($exclude)) $exclude = split('\\s*,\\s*',$exclude);
| |
− |
| |
− | # Select articles from members if a category or links in content if not
| |
− | $articles = array();
| |
− | $title = $article->getTitle();
| |
− | $opt = ParserOptions::newFromUser($wgUser);
| |
− | if ($title->getNamespace() == NS_CATEGORY) {
| |
− | $db = &wfGetDB(DB_SLAVE);
| |
− | $cat = $db->addQuotes($title->getDBkey());
| |
− | $result = $db->select(
| |
− | 'categorylinks',
| |
− | 'cl_from',
| |
− | "cl_to = $cat",
| |
− | 'PdfBook',
| |
− | array('ORDER BY' => 'cl_sortkey')
| |
− | );
| |
− | if ($result instanceof ResultWrapper) $result = $result->result;
| |
− | while ($row = $db->fetchRow($result)) $articles[] = Title::newFromID($row[0]);
| |
− | }
| |
− | else {
| |
− | $text = $article->fetchContent();
| |
− | $text = $wgParser->preprocess($text,$title,$opt);
| |
− | if (preg_match_all('/^\\*\\s*\\[{2}\\s*([^\\|\\]]+)\\s*.*?\\]{2}/m',$text,$links))
| |
− | foreach ($links[1] as $link) $articles[] = Title::newFromText($link);
| |
− | }
| |
− | | |
− | # Format the article's as a single HTML document with absolute URL's
| |
− | $book = $title->getText();
| |
− | $html = '';
| |
− | $wgArticlePath = $wgServer.$wgArticlePath;
| |
− | $wgScriptPath = $wgServer.$wgScriptPath;
| |
− | $wgUploadPath = $wgServer.$wgUploadPath;
| |
− | $wgScript = $wgServer.$wgScript;
| |
− | foreach ($articles as $title) {
| |
− | $ttext = $title->getPrefixedText();
| |
− | if (!in_array($ttext,$exclude)) {
| |
− | $article = new Article($title);
| |
− | $text = $article->fetchContent();
| |
− | $text = preg_replace('/<!--([^@]+?)-->/s','@@'.'@@$1@@'.'@@',$text); # preserve HTML comments
| |
− | $text .= '__NOTOC__';
| |
− | $opt->setEditSection(false); # remove section-edit links
| |
− | $wgOut->setHTMLTitle($ttext); # use this so DISPLAYTITLE magic works
| |
− | $out = $wgParser->parse($text,$title,$opt,true,true);
| |
− | $ttext = $wgOut->getHTMLTitle();
| |
− | $text = $out->getText();
| |
− | $text = preg_replace('|(<img[^>]+?src=")(/.+?>)|',"$1$wgServer$2",$text);
| |
− | $text = preg_replace('|@{4}([^@]+?)@{4}|s','<!--$1-->',$text); # HTML comments hack
| |
− | $text = preg_replace('|<table|','<table border borderwidth=2 cellpadding=3 cellspacing=0',$text);
| |
− | $ttext = basename($ttext);
| |
− | $html .= utf8_decode("<h1>$ttext</h1>$text\n");
| |
− | }
| |
− | }
| |
− | | |
− | # If format=html in query-string, return html content directly
| |
− | if (isset($_REQUEST['format']) && $_REQUEST['format'] == 'html') {
| |
− | $wgOut->disable();
| |
− | header("Content-Type: text/html");
| |
− | header("Content-Disposition: attachment; filename=\"$book.html\"");
| |
− | print $html;
| |
− | }
| |
− | else {
| |
− | # Write the HTML to a tmp file
| |
− | $file = "$wgUploadDirectory/".uniqid('pdf-book');
| |
− | $fh = fopen($file,'w+');
| |
− | fwrite($fh,$html);
| |
− | fclose($fh);
| |
− | | |
− | # Send the file to the client via htmldoc converter
| |
− | $wgOut->disable();
| |
− | header("Content-Type: application/pdf");
| |
− | header("Content-Disposition: attachment; filename=\"$book.pdf\"");
| |
− | $cmd = "--left $left --right $right --top $top --bottom $bottom";
| |
− | $cmd .= " --header ... --footer .1. --headfootsize 8 --quiet --jpeg --color";
| |
− | $cmd .= " --bodyfont $font --fontsize $size --linkstyle plain --linkcolor $links";
| |
− | $cmd .= " --toclevels $levels --format pdf14 --numbered $layout";
| |
− | $cmd = "htmldoc -t pdf --charset iso-8859-1 $cmd $file";
| |
− | putenv("HTMLDOC_NOCGI=1");
| |
− | passthru($cmd);
| |
− | @unlink($file);
| |
− | }
| |
− | return false;
| |
− | }
| |
− |
| |
− | return true;
| |
− | }
| |
− | | |
− | # Return a property for htmldoc using global, request or passed default
| |
− | function setProperty($name,$default) {
| |
− | if (isset($_REQUEST["pdf$name"])) return $_REQUEST["pdf$name"];
| |
− | if (isset($GLOBALS["wgPdfBook$name"])) return $GLOBALS["wgPdfBook$name"];
| |
− | return $default;
| |
− | }
| |
− | | |
− | # Needed in some versions to prevent Special:Version from breaking
| |
− | function __toString() { return 'PdfBook'; }
| |
− | }
| |
− | | |
− | # Called from $wgExtensionFunctions array when initialising extensions
| |
− | function wfSetupPdfBook() {
| |
− | global $wgPdfBook;
| |
− | $wgPdfBook = new PdfBook();
| |
− | }
| |
− | | |
− | # Needed in MediaWiki >1.8.0 for magic word hooks to work properly
| |
− | function wfPdfBookLanguageGetMagic(&$magicWords,$langCode = 0) {
| |
− | global $wgPdfBookMagic;
| |
− | $magicWords[$wgPdfBookMagic] = array(0,$wgPdfBookMagic);
| |
− | return true;
| |
− | } | |