<?php if (!defined('PmWiki')) exit();
/*---------------------------------------------------------------------+
| exporthtml.php for PmWiki. Documentation: http://www.pmwiki.org/Cookbook/ExportHTMLWiki
| Copyright 2016 Hans Bracker.
| This program is free software; you can redistribute it and/or modify
| it under the terms of the GNU General Public License, Version 2, as
| published by the Free Software Foundation.
| http://www.gnu.org/copyleft/gpl.html
| This program is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
| GNU General Public License for more details.
+----------------------------------------------------------------------+
*/
$RecipeInfo['ExportHTML']['Version'] =  '2023-10-06';
$EnablePathInfo = 0; //should not be set to 1! Here to reset if set to 1 in config.
SDV($EnableLangFolders, 1);

SDVA($SaveHTML, array(
	'suffix' => '.html',
	'relativeurls'=> true, //HTML pages will have links with relative urls when possible, not absolute urls. 
	'htmldir' => 'HTML/', //name of directory with the exported html files, relative to the wiki field
	'wikipath' => 'pmwiki/', //path from web root to wiki field directory (inclusive). Needs to be set. 
	#'localhosturl' => '', //set this to point to root of local wiki farm, to have local script urls replaced by server script urls
	#'serverhosturl' => '', //set this to point to farm on server, in conjunction with above.
	//example: $SaveHTML["localhosturl"] = $UrlScheme.'://localhost/mydomain.com';
	//         $SaveHTML["serverhosturl"] = 'https://mydomain.com';
	'exclude' => "*.RecentChanges,*.Group*,Site.*,SiteAdmin.*", //wildcard patterns to exclude pages
	'include' => PageVar($pagename, '$Group').".*",
	'hidden' => 'PageTopActionsFmt,PageTopSearchFmt,PageFootActionsFmt,PageActionFmt,PageTopBarFmt,PageTextFooterFmt,PageFootMenuFmt', //excluded skin templ sections
	'htmllabel' => 'HTML', //default html label for {[pagelink]}
	'wikilabel' => 'Wiki', //default wiki label for {[pagelink]}	
	'htmltooltip' => 'go to HTML page', //tooltip for {[pagelink ..]} link to HTML page
	'wikitooltip' => 'go to Wiki page', //tooltip for {[pagelink ..]} link to wiki page
	'redirect' => false, //true: redirects to HTML page
	'update' => true,    //true: HTML page will automatically be created when saving a wiki page as part of edits 
	'pause' => 0,  //delay in secs for page refresh when iterating pagelist pages
	'htmlecho' => false, //false, //true: show html page while saving, flashed briefly or for 'pause' seconds
	'batch' => true,     //true: batch processing is enabled
	'session' => true,   //true: batch process starts new Session and uses SESSION variables
	'test' => false, //false. Set to true to prevent actual html page saves, for testing
	'list' => false, //false. Set true to display list of pages to be exported
));
if (isset($Lang) && $EnableLangFolders==1)
	$SaveHTML['htmldir'] = $SaveHTML['htmldir'].$Lang.'/'; //for language-specific subfolders, using MultiLanguageViews
$SaveHTML['pubdir'] = trim(strrchr($PubDirUrl,'/'),'/');
$SaveHTML['rooturl'] = $UrlScheme.'://'.strval(@$_SERVER['HTTP_HOST']).'/';
$SaveHTML['wikipath'] = (substr($SaveHTML['wikipath'],-1)=='/') ? $SaveHTML['wikipath'] : $SaveHTML['wikipath'].'/';
$SaveHTML['htmldir'] = (substr($SaveHTML['htmldir'],-1)=='/') ? $SaveHTML['htmldir'] : $SaveHTML['htmldir'].'/';
$SaveHTML['htmlurl'] = $SaveHTML['rooturl'].$SaveHTML['wikipath'].$SaveHTML["htmldir"];
$group = PageVar($pagename,'$Group');
$name  = PageVar($pagename,'$Name');
#DEBUG show($SaveHTML,'SaveHTML'); //show config array

# page variables for non-relative page urls
$FmtPV['$HTMLPageUrl'] = '$GLOBALS["SaveHTML"]["htmlurl"].$group."/".$name.$GLOBALS["SaveHTML"]["suffix"]';
$FmtPV['$WikiPageUrl'] = '"$ScriptUrl?n=$group/$name"'; //this will not be rewritten when exporting

#handlers and authorisations
$HandleAuth['html'] = 'edit';
$HandleActions['html'] = 'HandleExportHTML';
$HandleAuth['htmlbatch'] = 'admin';
$HandleActions['htmlbatch'] = 'HandleExportHTML';

# conditional markup (:if nohtml:)
$NoHTMLExport = true; //is set to false when exporting to HTML
$Conditions['nohtml'] = '(boolean)@$GLOBALS["NoHTMLExport"]';

## function called as part of $EditFunctions during page update
if ($SaveHTML['update']==true && $group!='Site' && $group!='SiteAdmin' && !preg_match('/.*?\-Draft$/',$name)) { 
	$EditFunctions[] = 'ExportHTMLUpdate';
	$EditRedirectFmt = '{$FullName}?action=html';
}
function ExportHTMLUpdate($pagename, &$page, &$new) {
	global $IsPagePosted, $EditRedirectFmt,$SaveHTML;
	if (!$IsPagePosted) return;
 	if ($_REQUEST['action']=='edit') $_REQUEST['action'] = 'html';
	HandleExportHTML($pagename, 'edit');
} //}}}

## pagelink markup {[pagelink wikilabel htmllabel [edit|login] ]}
Markup('exporthtmllink','directives','/\\{\\[pagelink\\s*(.*?)\\s*\\]\\}/', "ExportHTMLPageLink");
function ExportHTMLPageLink($m) {
	global $SaveHTML, $NoHTMLExport, $ScriptUrl;
	extract($GLOBALS['MarkupToHTML']);
	if(isset($m[1])) $args = ParseArgs($m[1]); 
	$group = PageVar($pagename,'$Group');	
	$name = PageVar($pagename,'$Name');
	if ($NoHTMLExport==1)	{ //link for wiki page
		$label = (isset($args[''][1])) ? $args[''][1] : $SaveHTML["htmllabel"];
		$tooltip = $SaveHTML["htmltooltip"];
		$url = $SaveHTML["htmlurl"]."$group/$name".$SaveHTML["suffix"];
	}
	else { //link for HTML page
		$label = (isset($args[''][0])) ? $args[''][0] : $SaveHTML["wikilabel"];
		$tooltip = $SaveHTML["wikitooltip"];
		$url = $ScriptUrl."?n=$group/$name";
		if (isset($args[''][2]))
			switch ($args[''][2]) {
				case 'login':	$url .= "&action=login"; break;
				case 'edit':	$url .= "&action=edit";	break;		
			}
	} 
	return Keep('<a class="wikilink" href="'.$url.'" title="'.$tooltip.'">'.$label.'</a>');
} //}}}

## main function to export HTML page, called with action=html or action=htmlbatch
function HandleExportHTML($pagename, $auth) {
	global $action, $SaveHTML, $NoHTMLExport, $action, $ScriptUrl, $FmtV, $PageStartFmt, $PageEndFmt, 
	$HTMLHeaderFmt, $MetaRobots, $MakeBatchPageListFunction, $Lang, $MLVList, $FmtPV, $EnableLangFolders;
	$NoHTMLExport = false;
	//iterating batch process for multi language pages or action=htmlbatch
	if (($Lang && $EnableLangFolders==1) OR ($action=='htmlbatch' && $SaveHTML['batch']==true)) {
		$next = ExportHTMLBatch($pagename);
		if ($next=='next') return;
	}
	$group = PageVar($pagename,'$Group');
	$name = PageVar($pagename,'$Name');
	if ( !$group || !$name || !$SaveHTML['suffix']) Redirect($pagename);

  $fname = FmtPageName("{$name}{$SaveHTML['suffix']}", $pagename);
	$filename = "{$SaveHTML['htmldir']}{$group}/{$name}{$SaveHTML['suffix']}";

	//hide page sections with action links etc 
	if (!is_array($SaveHTML['hidden'])) 
		$SaveHTML['hidden'] = preg_split("/[\\s,|;]+/", $SaveHTML['hidden'], -1, PREG_SPLIT_NO_EMPTY);
	foreach ($SaveHTML['hidden'] as $sect) SetTmplDisplay($sect,0);
	$HTMLHeaderFmt['popupedit'] = ""; //suppress special popupedit styles
	$HTMLHeaderFmt['fox'] = ""; //supress special 'fox' styles
	$MetaRobots = 'index,follow'; //add 'index, follow' for robots metatag

	$page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
	if (!$page) Abort("?cannot read $pagename");
	if (PageExists($pagename)) $text = @$page['text'];
	$text = '(:groupheader:)'.@$text.'(:groupfooter:)';
  
	//check for redirect markup 
	if (preg_match('/\\(:redirect\\s+(\\S.*?):\\)/i',$text,$m)) {
		$redirname = MakePageName($pagename,$m[1]);
		$redirurl = $ScriptUrl."?n=".$redirname;
		$HandleBrowseFmt = "<html><head>
    	<meta http-equiv='Refresh' Content='0; URL=$redirurl' />
    	<title>Redirect</title></head><body></body></html>";
	} else {
		$FmtV['$PageText'] = MarkupToHTML($pagename, $text);
		$HandleBrowseFmt = array(&$PageStartFmt, '$PageText', &$PageEndFmt);
	}
    ob_start();
    PrintFmt($pagename, $HandleBrowseFmt);
    $html = ob_get_contents();
	if ($SaveHTML['htmlecho']==1) ob_end_flush();  //page echoed
	else ob_end_clean();  //silent
 	ExportHTMLUrlRewrite($pagename, $group, $html);
    mkdirp(dirname($filename)); 
    if ($SaveHTML['test']==true) $success = 'test'; //no files get written
    else $success = file_put_contents($filename, $html);

	// echo success or error message
	if(isset($Lang) && $EnableLangFolders==1) $langid = "<b>".$MLVList[$Lang]."</b> ";
	else $langid = '';
	if ($success =='test') echo "<span style='color:red'>TEST-RUN: </span><span style='color:green'>$langid $fname ----> ".$SaveHTML['htmldir']."{$group}/ </span><br />";
	else if ($success > 0)	echo "<span style='color:green'>$langid $fname saved to ".$SaveHTML['htmldir']."{$group}/ </span><br />";
	else              echo "<span style='color:red'>$fname could not be saved!</span><br />";
	if ($action=='htmlbatch' || ($Lang && $EnableLangFolders==1)) return; 
		
  	//show page, after single page export
 		if ($SaveHTML['redirect']==true)
 			$urlfmt = $SaveHTML["htmlurl"].$group."/".$name.$SaveHTML["suffix"];
 		else $urlfmt = $ScriptUrl."?n=".$pagename;
 		echo '<meta http-equiv="Refresh" Content="'.$SaveHTML["pause"].'; URL='.$urlfmt.'"/>';
		exit;
} //}}}

## iterative batch process using meta 'Refresh' tag
function ExportHTMLBatch($pagename) {
	global $action, $SaveHTML, $ScriptUrl, $MakeBatchPageListFunction, $Lang, $MLVList, $EnableLangFolders;
	if (!isset($_REQUEST['i'])) $_REQUEST['i'] = 0; //init, i=0 does not need to be url parameter
	if ($SaveHTML['session']==true && $_REQUEST['i']==0) session_start();
	ob_start();
	$next = intval($_REQUEST['i']);
	if ($_REQUEST['i']==0) {
		$_SESSION['BatchBasePage'] = ($Lang && $EnableLangFolders==1)? $pagename."&setlang=".$Lang : $pagename;
	}
	// try to get cached pagelist from session data
	if ($SaveHTML['session']==true && $next!=0 && isset($_SESSION['BatchPageList'])) {
		$plist = $xlist = $_SESSION['BatchPageList'];
		if ($Lang && $EnableLangFolders==1) $xlist = $_SESSION['BatchXPageList'];		
	} else { //build pagelist
		if ($action=='htmlbatch') {
			SDV($MakeBatchPageListFunction, 'MakeBatchPageList');
			$MakeBatchPageListFunction($pagename, $plist);
		} 
		else $plist = array($pagename);  //single page with multilanguage
		if ($Lang && $EnableLangFolders==1) {  //build extended pagelist with ?setlang=<id> url parameters added
			$xlist = array();
			$lgs = array_keys($MLVList);
			foreach($lgs as $lg) {
				foreach($plist as $pn)
					$xlist[] = $pn."&setlang=".$lg;
			}
		}	
		else $xlist = $plist;		
		if ($SaveHTML['session']==true) { 
			$_SESSION['BatchPageList'] = $plist;
			if ($Lang && $EnableLangFolders==1) $_SESSION['BatchXPageList'] = $xlist;
		}
	}
	$count = count($xlist)+1;
	if ($SaveHTML['list']==true) { show($plist,'xlist'); exit; } //for debugging	
	if ($next < $count) {
		$pn = $xlist[$next];  
		$next++;
		$refreshurl = $ScriptUrl."?n=".$pn;
		$refreshurl .= '&i='.$next ;
		// reuse current request parameters in the next call
		foreach ($_REQUEST as $rq => $val) {
			if ($rq!='n' && $rq!='i' && $rq!='setlang' && session_name()!=$rq && $rq!='csum' && $rq!='author' && $rq!='text' && $rq!='post' && $rq!='basetime') 
				$refreshurl .= '&'.urlencode($rq).'='.urlencode($val);
		}
		echo '<meta http-equiv="Refresh" Content="'.$SaveHTML['pause'].'; URL='.$refreshurl.'"/>';
	}
	else {
		if ($SaveHTML['session']==true) {
			$_SESSION['BatchPageList'] = NULL;
			unset($_SESSION['BatchPageList']);
			if ($Lang) unset($_SESSION['BatchXPageList']);
			$pagename = $_SESSION['BatchBasePage'];
			unset($_SESSION['BatchBasePage']);			
		}
		//show initial page if saved in $_SESSION var, otherwise show last page
		$urlfmt = $ScriptUrl."?n=".$pagename;
		Redirect($pagename, $urlfmt);
	}
	if ($next==1 || !in_array($pagename,$plist)) return "next";

} //}}}

## make pagelist for batch process from 'include' and 'exclude' patterns 
## and from url 'p' parameter pattern
function MakeBatchPageList($pagename, &$pagelist) {
	global $SaveHTML;
	$expat = GlobToPCRE(FixGlob($SaveHTML['exclude']));
	$exlist = ($expat[0]!='') ? ListPages("/$expat[0]/") : array();
	$inpat = GlobToPCRE(FixGlob($SaveHTML['include']));
	$inlist = ($inpat[0]!='') ? ListPages("/$inpat[0]/") : array();
	$reqpat = ($_REQUEST['p'])? GlobToPCRE(FixGlob($_REQUEST['p'])) : '';
	$excl = ($reqpat[1]!='') ? ListPages("/$reqpat[1]/") : array();
	$inlist = ($reqpat[0]!='') ? ListPages("/$reqpat[0]/") : $inlist;
	$exlist = array_merge($exlist , $excl);
	$pagelist = array_diff($inlist, $exlist);
	sort($pagelist);
} //}}}

## rewrite urls for the HTML page, using relative urls
function ExportHTMLUrlRewrite($pagename, $group, &$html) {
	global $SaveHTML, $HTMLRewritePatterns, $ScriptUrl, $GroupPattern, $NamePattern, 
		$UploadDir, $UploadUrlFmt, $PubDirUrl, $Lang;
	$selfgroup = preg_quote("../".$group."/");
	if($SaveHTML['relativeurls']==true) { //make relative urls for HTML pages
		$root = "../".preg_replace('!\w+\/!','../',$SaveHTML["htmldir"]); //for relative path replacements
		SDVA($HTMLRewritePatterns, array(
			'/<!--[\s\/]?\\w.*?-->[\n\s]*/' => '',
			'!(action=)\''.$ScriptUrl.'\?n=('.$GroupPattern.')\.('.$NamePattern.')!' => 'action=\''.$ScriptUrl.'?n=$2/$3',
			'!'.$ScriptUrl.'\?n=('.$GroupPattern.')\.('.$NamePattern.')\?setlang=(\w+)!' => '../../$3/$1/$2'.$SaveHTML['suffix'],
			'!'.$ScriptUrl.'\?n=('.$GroupPattern.')\.('.$NamePattern.')!' => '../$1/$2'.$SaveHTML['suffix'],
			'!'.$ScriptUrl.'/('.$GroupPattern.')/('.$NamePattern.')!' => '../$1/$2'.$SaveHTML['suffix'],
			'!'.$PubDirUrl.'(.*?)!' => $root.$SaveHTML["pubdir"].'$1',
			'!'.$selfgroup.'!' => '',
			'!\?action=browse!' => '',
		));
		if(isset($UploadUrlFmt) && isset($UploadDir))
			SDV($HTMLRewritePatterns['!'.$UploadUrlFmt.'!'], $root.$UploadDir);

	} else { //make absolute urls
		SDVA($HTMLRewritePatterns, array(
			'!'.$ScriptUrl.'\?n=('.$GroupPattern.')\.('.$NamePattern.')!' => $SaveHTML['htmlurl'].'$1/$2'.$SaveHTML['suffix'],
			'!'.$ScriptUrl.'/('.$GroupPattern.')/('.$NamePattern.')!' => $SaveHTML['htmlurl'].'$1/$2'.$SaveHTML['suffix'],			
			'!'.$selfgroup.'!' => '',
			'!\?action=browse!' => '',		
		));	
	}
	if(isset($SaveHTML["localhosturl"]) && isset($SaveHTML["serverhosturl"]))
		SDV($HTMLRewritePatterns['!'.$SaveHTML["localhosturl"].'(.*?)!'], $SaveHTML["serverhosturl"].'$1');	
	foreach($HTMLRewritePatterns as $pat=>$rep) {
		$html = preg_replace($pat, $rep, $html); 
	}
} //}}}
# debug helper function to echo preformatted array with optional label
if(!function_exists("show")) {
	function show($arr,$lbl='') {echo "<br /><pre><b>$lbl</b> ";print_r($arr);echo "</pre>";}
}
/// EOF