<?php if(!defined('PmWiki'))exit; /** Print WikiGroups and convert to PDF for PmWiki Written by (c) 2017-2021 Petko Yotov www.pmwiki.org/petko This text is written for PmWiki; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. See pmwiki.php for full details and lack of warranty. This text is partly based on the ThumbList2 picture gallery and on the PmWiki upload.php script. Copyright 2017-2021 Petko Yotov www.pmwiki.org/petko */ $RecipeInfo['PrintGroup']['Version'] = '20210822'; SDVA($HandleActions, array('printgroup'=>'HandlePrintGroup', 'pdfgroup'=>'HandlePrintGroup', 'pdfpage'=>'HandlePrintGroup', 'groupurls' => 'HandleGroupUrls', )); SDVA($PrintGroup, array( 'outpdf' => true, # false to only store the PDF without sending to browser 'adminperms' => false, 'keeplatest' => 10, 'pdfbinary' => 'wkhtmltopdf', # path to wkhtmltopdf 'pdfargs' => '', 'datefmt' => '%Y%m%d_%H%M%S', 'customcss' => '', 'dir' => "$WorkDir/.printgroup", 'enableallpages' => true, 'keeptemphtml' => true, # all pages from the wiki, from which to deduce the group names to export 'allgroupspattern' => '*.*,-PmWiki*.*,-Site.*,-SiteAdmin.*,-*.WikiSandbox', # group pages to skip when exporting; HomePage and SideBar are # automatically added at the top and will not be repeated 'pageskippattern' => '-*.RecentChanges,-*.GroupHeader,-*.GroupFooter,-*.GroupAttributes', 'GroupTemplate' => '<!DOCTYPE html> <html> <head> <title>$WikiTitle | {$Group} / {$Title}</title> <meta name="viewport" content="width=device-width, initial-scale=1"/> <meta http-equiv="Content-Type" content="text/html; charset=$Charset" /> <style type="text/css"> body { font-family: Arial, Helvetica, sans-serif; } .articletitle { font-size: 180%; background-color: #ccc; } .toplinks {float: right;} .pg_allpages { font-size: 90%; } .pg_allpages ul, .pg_allpages li { list-style-type: none; padding: 0; margin: 0; } .pg_allpages li { display: inline-block; width: 14em; margin-right: 1em; } a {text-decoration: none; margin-left: 4px;} .pg_allpages li a {margin-left: 0px;} article.printgroup > footer, article.printgroup > footer a {color: #888; text-decoration: none; } article.printgroup > footer { font-size: 90%; border-top: 1px solid #ccc; } article.printgroup { page-break-after: auto;} article.printgroup:last-child { page-break-after: auto;} a[href^="#"] {color: #007;} .frame { border:1px solid #cccccc; padding:4px; background-color:#f9f9f9; } .lfloat { float:left; margin-right:7px; } .rfloat { float:right; margin-left:7px; } table.markup { border:2px dotted #ccf; width:100%; } h1, h2, h3, h4, h5, h6 { margin-top:15px; margin-bottom:9px; } h1, h2, h3, h6 { font-weight:normal; } h4, h5 { font-weight:bold; } h1 code, h2 code, h3 code, h4 code { font-size:15px; } h1 { font-size:27px; } h2 { font-size:22px; } h3 { font-size:18px; } h4 { font-size:16px; } h5 { font-size:15px; } h6 { font-size:15px; } pre, code { font-size:14px; } pre, code, .diffmarkup { font-family:"Lucida Console","Andale Mono","Courier New",Courier,monospace; } pre { line-height: 18px; } pre code, code code, pre pre { font-size:100%; } pre, code.escaped { max-width: 100%; white-space: pre-wrap;} ul, ol, pre, dl, p { margin-top:0px; margin-bottom:0px; } code.escaped { white-space: nowrap; display: inline-block; vertical-align: bottom; text-indent: 0; } .vspace { margin-top:25px; } .indent { margin-left:15px; } .outdent { margin-left:15px; text-indent:-15px; } a.createlinktext { text-decoration:none; border-bottom:1px dotted gray; } a.createlink { text-decoration:none; position:relative; top:-7px; font-weight:bold; font-size:smaller; border-bottom:none; } img { border:0px; } .vspace { margin-top: 20px; } .indent { margin-left:40px; } .outdent { margin-left:40px; text-indent:-40px; } .rtl .indent, .rtl.indent, .rtl .outdent, .rtl.outdent { margin-left:0; margin-right: 40px; } ul, ol { padding: 0 0 0 40px; } dd { margin-left: 40px; } table.horiz td.markup1, table.horiz td.markup2 { display: table-cell; } td.markup1, td.markup2 { padding-left:10px; padding-right:10px; } table.vert td.markup1 { border-bottom:1px solid #ccf; } table.horiz td.markup1 { width:23em; border-right:1px solid #ccf; border-bottom:none; } div.faq p, div.faq pre { margin-left:40px; } div.faq p.question { margin:15px 0 12px 0; } div.faqtoc div.faq p.question { margin:8px 0 8px 20px; } select, textarea, input { font-size: 14px; } .miniedit {display: none;} /*customcss*/ </style> </head> <body> <a id="pg_top"></a> <div id="wikilogo"><a href="{$ScriptUrl}"><img src="$PageLogoUrl" alt="$WikiTitle"/></a></div> {GroupText} </body> </html> ', 'PageTemplate' => ' <article class="printgroup"> <span class="toplinks"><a href="#_SideBar">$[toc]</a> <a href="#pg_top">$[top]</a></span> <h1 class="articletitle"><a id="_{$Name}"></a>{$Title}</h1> {PageText} <footer> <span class="toplinks"><a href="#_SideBar">$[toc]</a> <a href="#pg_top">$[top]</a></span> $[Last modified by] {$LastModifiedBy} $[on] {$LastModified}.<br/> $[Original URL]: <a href="{$PageUrl}">{$PageUrl}</a> </footer> </article> ', )); ## (:redirect:) Markup('redirect', '<include', '/\\(:redirect\\s+(\\S+).*?:\\)/i', "(:nl:)$[Page redirects to] [[$1]](:nl:)"); ## [[#anchor]] Markup('[[#','<[[','/(?>\\[\\[#([A-Za-z][-.:\\w]*))\\]\\]/', "PrintGroup_Anchors"); function PrintGroup_Anchors($m) { extract($GLOBALS['MarkupToHTML']); $a = '_'.preg_replace('!^.*\\.!','', $pagename).'_'.$m[1]; if(! TrackAnchors($a)) return Keep("<a id='$a'></a>", 'L'); else return ''; } function HandlePrintGroup($pagename, $auth="read"){ global $PrintGroup, $FmtPV, $Now, $LinkFunctions, $Charset, $action, $EnableRedirect, $DefaultPasswords; ob_start(); # errors/warnings $EnableRedirect = false; if($PrintGroup['adminperms']) { $rand = mt_rand(100000, 999999); $DefaultPasswords['admin'] = pmcrypt($rand); $_POST['authpw'] = $rand; } list($Group, $Name) = explode('.', $pagename); $date = strftime($PrintGroup['datefmt'], $Now); $HomePage = MakePageName($pagename, "$Group."); $RecentChanges = MakePageName($pagename, "$Group.RecentChanges"); $SideBar = MakePageName($pagename, "$Group.SideBar"); if($action == "pdfpage") { $pagelist = array($pagename); $fname = "$pagename-$date"; $delpattern = "$pagename-*"; } else { $fname = "$Group-$date"; $delpattern = "$Group-*"; $LinkFunctions['<:page>'] = 'LinkPagePrintGroup'; $list = ListPages("$Group.*,-$HomePage,-$SideBar,{$PrintGroup['pageskippattern']}"); sort($list); $pagelist = array($HomePage, $SideBar); foreach($list as $pn) $pagelist[] = $pn; } $HTML = ""; $count = 0; foreach($pagelist as $pn) { $page = RetrieveAuthPage($pn, 'read', 0, READPAGE_CURRENT); if(!$page) continue; $text = @$page['text']; $template = FmtPageName($PrintGroup['PageTemplate'], $pn); if($pn == $SideBar && $PrintGroup['enableallpages']) { $text .= " >>pg_allpages<< * '''[[{$HomePage}|+]]''' "; foreach($list as $n) { $text .= "* [[$n|+]]\n"; } $text .= ">><<\n"; } $html = MarkupToHTML($pn, $text); $HTML .= str_replace('{PageText}', $html, $template); } $template = FmtPageName($PrintGroup['GroupTemplate'], $HomePage); $template = str_replace('/*customcss*/', $PrintGroup['customcss'], $template); $HTML = str_replace('{GroupText}', $HTML, $template); mkdirp($PrintGroup['dir']); if(!file_exists("{$PrintGroup['dir']}/.htaccess")) file_put_contents("{$PrintGroup['dir']}/.htaccess", "Order Deny,Allow\nDeny from all\n"); $tmpname = "{$PrintGroup['dir']}/$fname.html"; $pdfname = "{$PrintGroup['dir']}/$fname.pdf"; file_put_contents($tmpname, $HTML); fixperms($tmpname); PrintGroupDelOld("$delpattern.html"); if($action == 'printgroup') { ob_end_clean(); header("Content-type: text/html;"); header("Content-disposition: inline; filename=\"$tmpname\""); header("Content-length: ".filesize($tmpname)); readfile($tmpname); exit; } $exec = "{$PrintGroup['pdfbinary']} -q --load-error-handling ignore --encoding $Charset {$PrintGroup['pdfargs']} $tmpname $pdfname"; // xmp($exec, 1); exec($exec, $output, $return); clearstatcache(); if(! file_exists($pdfname)) Abort("$pdfname doesn't exist!"); fixperms($pdfname); if(! $PrintGroup['keeptemphtml']) unlink($tmpname); PrintGroupDelOld("$delpattern.pdf"); if($PrintGroup['outpdf']) { ob_end_clean(); header("Content-type: application/pdf;"); header("Content-disposition: attachment; filename=\"$fname.pdf\""); header("Content-length: ".filesize($pdfname)); readfile($pdfname); } else Redirect($pagename); exit; } function PrintGroupDelOld($pattern) { global $PrintGroup; $kl = $PrintGroup['keeplatest']; $d = $PrintGroup['dir']; if($kl && $kl>0) { $files = array(); foreach(glob("$d/$pattern") as $f) { $files[$f] = filemtime($f); } arsort($files); $files = array_keys($files); for($i=$kl; $i<count($files); $i++) { unlink($files[$i]); } } } function LinkPagePrintGroup($pagename,$imap,$path,$alt,$txt,$fmt=NULL) { global $QueryFragPattern, $LinkPageExistsFmt, $LinkPageSelfFmt, $LinkPageCreateSpaceFmt, $LinkPageCreateFmt, $UrlLinkFmt, $AppLinkMap; $path = preg_replace('/(#[-.:\\w]*)#.*$/', '$1', $path); # PITS:01388 list($G, $N) = explode('.', $pagename); $alt = str_replace(array('"',"'"),array('"','''),$alt); if (is_array($txt)) { # PITS:01392 $suffix = $txt[1]; $txt = $txt[0]; } if (!$fmt && $path[0] == '#') { $path = preg_replace("/[^-.:\\w]/", '', $path); if (trim($txt) == '+') $txt = PageVar($pagename, '$Title') . @$suffix; if ($alt) $alt = " title='$alt'"; return ($path) ? "<a href='#_{$N}_$path'$alt>".str_replace("$", "$", $txt)."</a>" : ''; } if (!preg_match("/^\\s*([^#?]+)($QueryFragPattern)?$/",$path,$match)) return ''; $tgtname = MakePageName($pagename, $match[1]); if (!$tgtname) return ''; $qf = @$match[2]; if (!$fmt) { if (!PageExists($tgtname) && !preg_match('/[&?]action=/', $qf)) $fmt = preg_match('/\\s/', $txt) ? $LinkPageCreateSpaceFmt : $LinkPageCreateFmt; else $fmt = ($tgtname == $pagename && $qf == '') ? $LinkPageSelfFmt : $LinkPageExistsFmt; } list($g, $n) = explode('.', $tgtname); if($G==$g && PageExists($tgtname)){ $url = "#_$n"; if(@$qf[0] == '#') { $url .= "_" . substr($qf, 1); $qf = ""; } } else { # other group, or page doesn't exist $fmt = $UrlLinkFmt; $url = PageVar($tgtname, '$PageUrl'); } if (trim($txt) == '+') $txt = PageVar($tgtname, '$Titlespaced'); $txt = str_replace("$", "$", $txt); $fmt = str_replace(array('$LinkUrl', '$LinkText', '$LinkAlt'), array($url.PUE($qf), $txt, $alt), $fmt); return FmtPageName($fmt,$tgtname); } function HandleGroupUrls($pagename) { global $PrintGroup; $list = ListPages($PrintGroup['allgroupspattern']); sort($list); $groups = array(); foreach($list as $pn) { list($g, $p) = explode('.', $pn); @$groups[$g]++; } $groups = array_keys($groups); $out = ""; $naction = ($_REQUEST['out'] == 'html') ? 'printgroup' : 'pdfgroup'; foreach($groups as $g) { $pn = MakePageName("$g.1", "$g."); $out .= PageVar($pn, '$PageUrl') . "?action=$naction\r\n"; } header("Content-Type: text/plain"); echo $out; exit; }