<?php if(!defined('PmWiki'))exit;
/**
  Export PmWiki to static HTML files then optionally compress/zip.
  Written by (c) 2017 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.

  Copyright 2017 Petko Yotov www.pmwiki.org/petko
*/
$RecipeInfo['BackupHTMLZip']['Version'] = '20170717';

SDVA($HandleActions, array('bhzip'=>'HandleBHZip'));
SDVA($BHZip, array(
  'pages'=>'*.*,-PmWiki*.*,-SiteAdmin.*,-*.WikiSandbox,-Site.*',
  'adminperms' => false,
  'skin' => false,
  'css' => false,

  'autostart_delay_hours' => 0,
  'squelch_hours' => 1,

  'dir' => 'backup',
  'htaccess' => "Order Deny,Allow\nDeny from all\n",

  'namefmt' => 'backup-%Y%m%d_%H%M%S',
  'zipbinary' => 'zip',
  'zipexclude' => '*~ .svn *,cache',
  'zippassword' => false,
  'delcache' => true,
  'zipkeeplatest' => 10,

  'memory_limit' => '128M',
  'max_execution_time' => 180,
));

if($BHZip['autostart_delay_hours']>0 && (!@$action || $action=="browse"))
  $PostConfig['CheckBHZip'] = 300;

if($action == 'bhzip') {
  ini_set('memory_limit', $BHZip['memory_limit']);
  ini_set('max_execution_time', $BHZip['max_execution_time']);
  if($BHZip['skin']) $Skin = $BHZip['skin'];

  ## Convert (:redirect:) to link.
  Markup('redirect', '<include',
    '/\\(:redirect\\s+(\\S+).*?:\\)/i',
    "(:nl:)$[Page redirects to] [[$1]](:nl:)");
}

function HandleBHZip($pagename, $auth = 'ALWAYS') {
  global $BHZip, $EnableRedirect, $FarmPubDirUrl, $PubDirUrl, $UploadUrl, $ScriptUrl, $pagename, $WikiTitle, $Now,
    $TmplFmt, $EnableStopWatch, $TmplDisplay, $InclCount, $FmtP, $FmtPV, $EnableDirectDownload, $UploadUrlFmt,
    $EnablePathInfo, $DefaultPasswords, $UploadDir, $FarmD, $UploadDir, $HTMLStylesFmt, $HTMLStartFmt, $HTMLEndFmt;

  $latest = 0;
  foreach(glob($BHZip['dir'].'/*.zip') as $f) {
    $latest = max($latest,filemtime($f));
  }
  if($BHZip['squelch_hours'] &&
    $latest + $BHZip['squelch_hours']*3600 > $Now) {
    Abort("$[Too early for a new snapshot.] (squelch_hours)");
  }

  if($auth != 'ALWAYS') { # request password if needed
    $page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
  }

  $orig_pagename = $pagename;

  PrintFmt($pagename, $HTMLStartFmt);

  if($BHZip['adminperms']) {
    $rand = mt_rand(100000, 999999);
    $DefaultPasswords['admin'] = pmcrypt($rand);
    $_POST['authpw'] = $rand;
  }
  if($BHZip['css']) {
    $HTMLStylesFmt['bhzip'] = $BHZip['css'];
  }

  $EnableStopWatch = 0;
  $EnablePathInfo = 1;
  $ScriptUrl = '..';
  $FmtPV['$oPageUrl'] = $FmtPV['$PageUrl'];
  $FmtPV['$PageUrl'] = 'PUE("../$group/$name.html")';

  $PubDirUrl = '../_pub';
  $FarmPubDirUrl = '../_fpub';
  $UploadUrlFmt = '../_uploads';
  $EnableDirectDownload = 1;

  array_shift($TmplFmt['Start']); # remove HTTP headers;

  SetTmplDisplay('PageActionFmt',0);
  $EnableRedirect = 0;

  $d = $BHZip['dir'];

  if(! file_exists("$d/.htaccess") ) {
    mkdirp($d);
    bh_file_put_contents("$d/.htaccess", $BHZip['htaccess']);
    bh_symlink("$FarmD/pub", "$d/_fpub");
    
    if(is_dir('pub') ) {
      if( realpath("pub") == realpath("$FarmD/pub") )
        $PubDirUrl = '../_fpub';
      else {
        bh_symlink(realpath("pub"), "$d/_pub");
      }
    }
    if(is_dir($UploadDir)) {
      bh_symlink(realpath($UploadDir), "$d/_uploads");
    }
  }

  $list = ListPages($BHZip['pages']);
  sort($list);

  $groups = array();

  foreach($list as $pn) {
    $pagename = $pn;

    $page = ($auth == 'ALWAYS')
      ? ReadPage($pn, READPAGE_CURRENT)
      : RetrieveAuthPage($pn, $auth, false, READPAGE_CURRENT);

    if(! $page ) continue;

    list($g, $n) = explode('.', $pn);
    $groups[$g]++;

    ob_start();
    HandleBrowse($pagename, 'ALWAYS');
    $html = ob_get_clean();

    mkdirp("$d/$g");
    bh_file_put_contents("$d/$g/$n.html", $html);

    echo "$g/$n.html ".XL('written').". <br/>\n";
    flush();

    $TmplDisplay = array('PageActionFmt'=>0);
    unset($InclCount);
  }

  list($g, $n) = explode('.', ResolvePageName('')); # default page

  $namefmt = strftime( $BHZip['namefmt'] );
  $idxname = "$namefmt.html";

  $idxhtml = "<html><head>
    <meta http-equiv='Refresh' Content='0; URL=$g/$n.html' />
    <title>Redirect</title></head><body>
    <a href='$g/$n.html'>".XL('Page redirects to')
    ." $g/$n.html</a></body></html>";

  bh_file_put_contents("$d/$idxname", $idxhtml);

  $groups[$idxname]++;

  $b = $BHZip['zipbinary'];
  if($b) {
    $zname = "$namefmt.zip";

    flush();

    $x = $BHZip['zipexclude'] ? " -x {$BHZip['zipexclude']}" : "";
    $m = $BHZip['delcache'] ? " --move " : "";
    $p = $BHZip['zippassword'] ? " -P \"{$BHZip['zippassword']}\"" : "";

    $pwd = getcwd();
    chdir($d);

    $zip = exec("$b $p -r $m $zname ".implode(" ", array_keys($groups)). " $x");
    $zip = exec("$b $p -r -u $zname _uploads _pub _fpub $x");

    $zkl = $BHZip['zipkeeplatest'];
    if($zkl && $zkl>0) {
      $zips = array();
      foreach(glob('*.zip') as $f) {
        $zips[$f] = filemtime($f);
      }
      arsort($zips);
      $zips = array_keys($zips);

      for($i=$zkl; $i<count($zips); $i++) {
        unlink($zips[$i]);
      }
    }
    chdir($pwd);
  }

  echo "$zname " . XL('written')."<br/>\n";

  echo "<a href='".PageVar($orig_pagename, '$oPageUrl')."'>"
    .  XL('Continue to') . " $WikiTitle</a><br/>\n";

  PrintFmt($orig_pagename, $HTMLEndFmt);
}


function CheckBHZip($pagename) {
  global $BHZip, $action, $HTMLStartFmt, $HTMLEndFmt, $Now, $WikiTitle;

  $latest = 0;
  foreach(glob($BHZip['dir'].'/*.zip') as $f) {
    $latest = max($latest,filemtime($f));
  }
  foreach(glob($BHZip['dir'].'/*.html') as $f) {
    $latest = max($latest,filemtime($f));
  }
  foreach(glob($BHZip['dir'].'/*.skip') as $f) {
    $latest = max($latest,filemtime($f));
  }
  if($latest + $BHZip['autostart_delay_hours']*3600 >= $Now) return;

  mkdirp($BHZip['dir']);
  $namefmt = strftime( $BHZip['namefmt'] );
  touch("{$BHZip['dir']}/$namefmt.skip");

  $pagename = ResolvePageName($pagename);

  $heading = XL('Automatic backup');
  $message = XL('New backup snapshot is scheduled now. This may take up to 3 minutes.');
  $go = XL("Create snapshot now (recommended)");
  $skip = sprintf(XL('Skip snapshot for the next %s hours'), $BHZip['autostart_delay_hours']);
  $url = PageVar($pagename, '$PageUrl');

  $html = "<h2>$WikiTitle: $heading</h2>
  <p>$message</p>
  <p>
    <a href='$url?action=bhzip'>$go</a> -
    <a href='$url'>$skip</a>
  </p>";
  PrintFmt($pagename, array($HTMLStartFmt, $html, $HTMLEndFmt));

  exit;
}

function bh_file_put_contents($fname, $text) {
  file_put_contents($fname, $text);
  fixperms($fname);
}
function bh_symlink($src, $dst) {
  symlink($src, $dst);
  fixperms($dst);
}