1<?php
2
3/**
4 * USING
5 *
6 * zip.php <key> <user> <serialized pages> <serialized userinfo[grps]>
7 */
8
9
10if ('cli' !== php_sapi_name()) die();
11
12if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../../').'/');
13define('NOSESSION',1);
14require_once(DOKU_INC.'inc/init.php');
15require_once(DOKU_INC.'inc/common.php');
16require_once(DOKU_INC.'inc/parserutils.php');
17require_once(DOKU_INC.'inc/cliopts.php');
18require_once(DOKU_INC.'inc/auth.php');
19require_once(DOKU_INC.'inc/io.php');
20
21$args = Doku_Cli_Opts::readPHPArgv();
22
23if (count($args) !== 5) die(-1);
24
25class nsexport_zip {
26
27    public $tmp;
28
29    public function _addFile($filename, $content) {
30        $filename = $this->tmp . "/$filename";
31        io_makeFileDir($filename);
32        file_put_contents($filename , $content);
33    }
34
35    public function recursive_add($base, $dir=''){
36        $fh = @opendir("$base/$dir");
37        if(!$fh) return;
38        while(false !== ($file = readdir($fh))) {
39            @set_time_limit(30);
40            if($file === '..' || $file[0] === '.') continue;
41            if(is_dir("$base/$dir/$file")){
42                $this->recursive_add($base,"$dir/$file");
43            }else{
44                $this->_addFile("$dir/$file",io_readFile(ltrim("$base/$dir/$file",'/'),false));
45            }
46        }
47        closedir($fh);
48    }
49
50    /**
51     * Delete a file, or a folder and its contents (recursive algorithm)
52     *
53     * @author      Aidan Lister <aidan@php.net>
54     * @version     1.0.3
55     * @link        http://aidanlister.com/repos/v/function.rmdirr.php
56     * @param       string   $dirname    Directory to delete
57     * @return      bool     Returns TRUE on success, FALSE on failure
58     */
59    public function rmdirr($dirname)
60    {
61        // Sanity check
62        if (!file_exists($dirname)) {
63            return false;
64        }
65
66        // Simple delete for a file
67        if (is_file($dirname) || is_link($dirname)) {
68            return unlink($dirname);
69        }
70
71        // Loop through the folder
72        $dir = dir($dirname);
73        while (false !== $entry = $dir->read()) {
74            // Skip pointers
75            if ($entry === '.' || $entry === '..') {
76                continue;
77            }
78
79            // Recurse
80            $this->rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
81        }
82
83        // Clean up
84        $dir->close();
85        return rmdir($dirname);
86    }
87
88    public function start($key, $user, $pages, $groups) {
89        global $conf;
90        global $lang;
91
92        $pages = unserialize($pages);
93
94        require_once(DOKU_INC.'inc/HTTPClient.php');
95        error_reporting(0);
96
97        // check if the 7ip executable is availible
98        // FIXME
99        $packer = $this->getConf('packer_ziphtml_zip');
100        if (!file_exists($packer) || !is_file($packer))
101        {
102            return;
103        }
104
105        $media = array();
106        $tmpdir  = io_mktmpdir();
107        if ($tmpdir === false) {
108            // no tmpdir
109            return;
110        }
111        $this->tmp = $tmpdir;
112
113
114        // add CSS
115        $http  = new DokuHTTPClient();
116        $css   = $http->get(DOKU_URL.'lib/exe/css.php?s=all&t='.$conf['template']);
117        $this->_addFile('all.css',$css);
118        $css   = $http->get(DOKU_URL.'lib/exe/css.php?t='.$conf['template']);
119        $this->_addFile('screen.css',$css);
120        $css   = $http->get(DOKU_URL.'lib/exe/css.php?s=print&t='.$conf['template']);
121        $this->_addFile('print.css',$css);
122        $css   = io_readFile(dirname(__FILE__).'/export.css',false);
123        $this->_addFile('export.css',$css);
124
125        unset($html);
126
127        foreach($pages as $ID){
128            if( auth_aclcheck($ID, $user, $groups) < AUTH_READ ) continue;
129            @set_time_limit(30);
130
131            // create relative path to top directory
132            $deep = substr_count($ID,':');
133            $ref  = '';
134            for($i=0; $i<$deep; $i++) $ref .= '../';
135
136            // create the output
137            $html = p_cached_output(wikiFN($ID,''), 'nsexport_xhtml');
138
139            $output  = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'.DOKU_LF;
140            $output .= ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'.DOKU_LF;
141            $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'"'.DOKU_LF;
142            $output .= ' lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">' . DOKU_LF;
143            $output .= '<head>'.DOKU_LF;
144            $output .= '  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />'.DOKU_LF;
145            $output .= '  <title>'.$ID.'</title>'.DOKU_LF;
146            $output .= '  <link rel="stylesheet" media="all" type="text/css" href="'.$ref.'all.css" />'.DOKU_LF;
147            $output .= '  <link rel="stylesheet" media="screen" type="text/css" href="'.$ref.'screen.css" />'.DOKU_LF;
148            $output .= '  <link rel="stylesheet" media="print" type="text/css" href="'.$ref.'print.css" />'.DOKU_LF;
149            $output .= '  <link rel="stylesheet" media="all" type="text/css" href="'.$ref.'export.css" />'.DOKU_LF;
150            $output .= '</head>'.DOKU_LF;
151            $output .= '<body>'.DOKU_LF;
152            $output .= '<div class="dokuwiki export">' . DOKU_LF;
153            $output .= tpl_toc(true);
154            $output .= $html;
155            $output .= '</div>';
156            $output .= '</body>'.DOKU_LF;
157            $output .= '</html>'.DOKU_LF;
158
159            $this->_addFile(str_replace(':','/',$ID).'.html',$output);
160            $media = array_merge($media,(array) p_get_metadata($ID,'plugin_nsexport'));
161        }
162
163        // now embed the media
164        $media = array_map('cleanID',$media);
165        $media = array_unique($media);
166        foreach($media as $id){
167            if( auth_quickaclcheck($id) < AUTH_READ ) continue;
168            @set_time_limit(30);
169            $this->_addFile('_media/'.str_replace(':','/',$id),io_readFile(mediaFN($id),false));
170        }
171
172
173        // add the merge directory contents
174        $this->recursive_add(dirname(__FILE__).'/merge');
175
176        echo basename($this->tmp);
177
178    }
179
180    /**
181     * Do the action
182     */
183    public function _export_html($pages){
184        global $conf;
185        @ignore_user_abort(true);
186        $filename = $conf['tmpdir'].'/offline-'.time().rand(0,99999).'.zip';
187        $this->zip = $filename;
188        $zfn = preg_replace('/^([a-z]{1}):/i','$1:\\',$filename);
189        $efn = preg_replace('/^([a-z]{1}):/i','$1:\\',$this->tmp.'/');
190
191        // send to browser
192        header('Content-Type: application/zip');
193        header('Content-Disposition: attachment; filename="export.zip"');
194        header('Expires: 0');
195        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
196        header('Content-Transfer-Encoding: binary');
197        header('Pragma: public');
198        flush();
199        @set_time_limit(0);
200
201        chdir($efn);
202        $zip = $this->getConf('packer_ziphtml_zip');
203        $comp = $this->getConf('packer_ziphtml_compress');
204        $cmd = "$zip -q -$comp -r - .";
205        system($cmd);
206
207        // cleanup
208        $this->rmdirr($this->tmp);
209    }
210}
211