<?php
class PdfBookHooks {
public static function onRegistration() {
global $wgLogTypes, $wgLogNames, $wgLogHeaders, $wgLogActions;
$wgLogTypes[] = 'pdf';
$wgLogNames ['pdf'] = 'pdflogpage';
$wgLogHeaders['pdf'] = 'pdflogpagetext';
$wgLogActions['pdf/book'] = 'pdflogentry';
}
/**
* Perform the export operation
*/
public static function onUnknownAction( $action, $article ) {
global $wgOut, $wgUser, $wgParser, $wgRequest, $wgAjaxComments, $wgPdfBookDownload;
global $wgServer, $wgArticlePath, $wgScriptPath, $wgUploadPath, $wgUploadDirectory, $wgScript;
if( $action == 'pdfbook' ) {
// Create a cache filename from the query-string parameters
$cache = $wgUploadDirectory . '/pdf-book-cache' . md5( json_encode( $_GET ) );
$title = $article->getTitle();
$book = $title->getText();
$opt = ParserOptions::newFromUser( $wgUser );
// Log the export
$msg = wfMessage( 'pdfbook-log', $wgUser->getUserPage()->getPrefixedText() )->text();
$log = new LogPage( 'pdf', false );
$log->addEntry( 'book', $article->getTitle(), $msg );
// Initialise PDF variables
$format = self::setProperty( 'format', '', '' );
$nothumbs = self::setProperty( 'nothumbs', '', '' );
$notitle = self::setProperty( 'notitle', '', '' );
$comments = $wgAjaxComments ? self::setProperty( 'comments', '', false ) : '';
$layout = $format == 'single' ? '--webpage' : '--firstpage toc';
$charset = self::setProperty( 'Charset', 'iso-8859-1' );
$left = self::setProperty( 'LeftMargin', '2cm' );
$right = self::setProperty( 'RightMargin', '2cm' );
$top = self::setProperty( 'TopMargin', '2cm' );
$bottom = self::setProperty( 'BottomMargin','1.5cm' );
$font = self::setProperty( 'Font', 'Sans' );
$size = self::setProperty( 'FontSize', '10' );
$ls = self::setProperty( 'LineSpacing', 1.5 );
$linkcol = self::setProperty( 'LinkColour', '555555' );
$levels = self::setProperty( 'TocLevels', '3' );
$exclude = self::setProperty( 'Exclude', array() );
$width = self::setProperty( 'Width', '' );
$options = self::setProperty( 'Options', '' );
$width = $width ? "--browserwidth 800" : '';
if( !is_array( $exclude ) ) $exclude = preg_split( '\\s*,\\s*', $exclude );
// If the file doesn't exist, render the content now
// if( !file_exists( $cache ) ) {
// Select articles from members if a category or links in content if not
if( $format == 'single' || $format == 'html' ) $articles = array( $title );
else {
$articles = array();
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->getPage()->getContent()->getNativeData();
$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
$html = '';
$wgArticlePath = $wgServer . $wgArticlePath;
$wgPdfBookTab = false;
$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->getPage()->getContent()->getNativeData();
$text = preg_replace( "/<!--([^@]+?)-->/s", "@@" . "@@$1@@" . "@@", $text ); // preserve HTML comments
if( $format != 'single' ) $text .= "__NOTOC__";
$opt->setEditSection( false ); // remove section-edit links
$out = $wgParser->parse( $text, $title, $opt, true, true );
$text = $out->getText();
if( $format == 'html' ) {
$text = preg_replace( "|(<img[^>]+?src=\")(/.+?>)|", "$1$wgServer$2", $text ); // make image urls absolute
} else {
$pUrl = parse_url( $wgScriptPath ) ;
$imgpath = str_replace( '/' , '\/', $pUrl['path'] . '/' . basename( $wgUploadDirectory ) ) ; // the image's path
$text = preg_replace( "|(<img[^>]+?src=\"$imgpath)(/.+?>)|", "<img src=\"$wgUploadDirectory$2", $text );
}
if( $nothumbs == 'true') $text = preg_replace( "|images/thumb/(\w+/\w+/[\w\.\-]+).*\"|", "images/$1\"", $text ); // Convert image links from thumbnail to full-size
$text = preg_replace( "|<div\s*class=['\"]?noprint[\"']?>.+?</div>|s", "", $text ); // non-printable areas
$text = preg_replace( '/<span class="mw-headline" id="(.*?)">(.*?)<\/span>/', "$2", $text ); // span entfernen
$text = preg_replace( "|@{4}([^@]+?)@{4}|s", "<!--$1-->", $text ); // HTML comments hack
$ttext = basename( $ttext );
$h1 = $notitle ? "" : "<center><h1>$ttext</h1></center>";
// Add comments if selected and AjaxComments is installed
if( $comments ) {
$comments = $wgAjaxComments->onUnknownAction( 'ajaxcommentsinternal', $article );
}
$html .= utf8_decode( "$h1$text\n$comments" );
}
}
// Build the cache file
if( $format == 'html' ) file_put_contents( $cache, $html );
else {
// Write the HTML to a tmp file
if( !is_dir( $wgUploadDirectory ) ) mkdir( $wgUploadDirectory );
$file = $wgUploadDirectory . '/' . uniqid( 'pdf-book' );
file_put_contents( $file, $html );
// Build the htmldoc command
$footer = $format == 'single' ? "..." : ".1.";
$toc = $format == 'single' ? "" : " --toclevels $levels";
$cmd = "--left $left --right $right --top $top --bottom $bottom --size 6x9in --duplex --toctitle Inhalt"
. " --header c.. --footer $footer --headfootsize 8 --quiet --jpeg --color --book --bodyimage http://jurtenland.de/wiki/images/c/c5/Pdfbookinhalt.png"
. " --bodyfont $font --fontsize $size --fontspacing $ls --linkstyle plain --linkcolor $linkcol"
. "$toc --no-title --no-numbered --charset $charset $options $layout $width";
$cmd = $format == 'htmltoc'
? "htmldoc -t html --format html $cmd $file"
: "htmldoc -t pdf --format pdf14 $cmd $file";
// Execute the command outputting to the cache file
putenv( "HTMLDOC_NOCGI=1" );
shell_exec( "$cmd > \"$cache\"" );
unlink( $file );
}
}
// Output the cache file
$wgOut->disable();
if( $format == 'html' || $format == 'htmltoc' ) {
header( "Content-Type: text/html" );
header( "Content-Disposition: attachment; filename=\"$book.html\"" );
} else {
header( "Content-Type: application/pdf" );
if( $wgPdfBookDownload ) header( "Content-Disposition: attachment; filename=\"$book.pdf\"" );
else header( "Content-Disposition: inline; filename=\"$book.pdf\"" );
}
readfile( $cache );
return false;
}
return true;
}
/**
* Return a sanitised property for htmldoc using global, request or passed default
*/
private static function setProperty( $name, $val, $prefix = 'pdf' ) {
global $wgRequest;
if( $wgRequest->getText( "$prefix$name" ) ) $val = $wgRequest->getText( "$prefix$name" );
if( $wgRequest->getText( "amp;$prefix$name" ) ) $val = $wgRequest->getText( "amp;$prefix$name" ); // hack to handle ampersand entities in URL
if( isset( $GLOBALS["wgPdfBook$name"] ) ) $val = $GLOBALS["wgPdfBook$name"];
return preg_replace( '|[^-_:.a-z0-9]|i', '', $val );
}
/**
* Add PDF to actions tabs in MonoBook based skins
*/
public static function onSkinTemplateTabs( $skin, &$actions) {
global $wgPdfBookTab, $wgUser;
if( $wgPdfBookTab && $wgUser->isLoggedIn() ) {
$actions['pdfbook'] = array(
'class' => false,
'text' => wfMessage( 'pdfbook-action' )->text(),
'href' => self::actionLink( $skin )
);
}
return true;
}
/**
* Add PDF to actions tabs in vector based skins
*/
public static function onSkinTemplateNavigation( $skin, &$actions ) {
global $wgPdfBookTab, $wgUser;
if( $wgPdfBookTab && $wgUser->isLoggedIn() ) {
$actions['views']['pdfbook'] = array(
'class' => false,
'text' => wfMessage( 'pdfbook-action' )->text(),
'href' => self::actionLink( $skin )
);
}
return true;
}
/**
* Get the URL for the action link
*/
public static function actionLink( $skin ) {
$qs = 'action=pdfbook&format=single';
foreach( $_REQUEST as $k => $v ) if( $k != 'title' ) $qs .= "&$k=$v";
return $skin->getTitle()->getLocalURL( $qs );
}
}