1<?php
2require_once DOKU_PLUGIN.'nsexport/packer/ziphtml/compressor.php';
3require_once DOKU_PLUGIN.'nsexport/packer/ziphtml/compress/ziplib.php';
4require_once DOKU_PLUGIN.'nsexport/packer/ziphtml/renderer.php';
5require_once DOKU_PLUGIN.'nsexport/packer/packer.php';
6
7class plugin_nsexport_packer_ziphtml extends plugin_nsexport_packer {
8    public $ext = 'zip';
9
10    public function init_packing($pages) {
11        global $conf;
12        // early check if the zip executable is available
13        $packer = $conf['plugin']['nsexport']['packer_ziphtml_zip'];
14        if (!file_exists($packer) || !is_file($packer)) {
15            return false;
16        }
17
18        // prepare some basic settings
19        $this->tmp  = io_mktmpdir();
20        if ($this->tmp === false) {
21            // no tmpdir
22            return false;
23        }
24
25        $this->media = array();
26
27        // begin data collecting
28        // add CSS
29        $http  = new DokuHTTPClient();
30        $css   = $http->get(DOKU_URL.'lib/exe/css.php?s=all&t='.$conf['template']);
31        $this->_addFile('all.css',$css);
32        $css   = $http->get(DOKU_URL.'lib/exe/css.php?t='.$conf['template']);
33        $this->_addFile('screen.css',$css);
34        $css   = $http->get(DOKU_URL.'lib/exe/css.php?s=print&t='.$conf['template']);
35        $this->_addFile('print.css',$css);
36        $css   = io_readFile(dirname(__FILE__).'/export.css',false);
37        $this->_addFile('export.css',$css);
38
39        return parent::init_packing($pages);
40    }
41
42    public function pack_page($ID_PAGE) {
43        global $conf;
44        global $lang;
45        global $ID;
46
47        $ID = $ID_PAGE;
48
49        // create relative path to top directory
50        $deep = substr_count($ID,':');
51        $ref  = '';
52        for($i=0; $i<$deep; $i++) $ref .= '../';
53
54        // create the output
55        $this->Renderer = new renderer_plugin_nsexport_xhtml;
56
57        $this->Renderer->smileys = getSmileys();
58        $this->Renderer->entities = getEntities();
59        $this->Renderer->acronyms = getAcronyms();
60        $this->Renderer->interwiki = getInterwiki();
61
62        $instructions = p_cached_instructions(wikiFN($ID,''),false,$ID);
63        foreach ( $instructions as $instruction ) {
64            // Execute the callback against the Renderer
65            call_user_func_array(array(&$this->Renderer, $instruction[0]),
66                                 $instruction[1]);
67        }
68        $html = $this->Renderer->doc;
69
70        $output  = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'.DOKU_LF;
71        $output .= ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'.DOKU_LF;
72        $output .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'"'.DOKU_LF;
73        $output .= ' lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">' . DOKU_LF;
74        $output .= '<head>'.DOKU_LF;
75        $output .= '  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />'.DOKU_LF;
76        $output .= '  <title>'.$ID.'</title>'.DOKU_LF;
77        $output .= '  <link rel="stylesheet" media="all" type="text/css" href="'.$ref.'all.css" />'.DOKU_LF;
78        $output .= '  <link rel="stylesheet" media="screen" type="text/css" href="'.$ref.'screen.css" />'.DOKU_LF;
79        $output .= '  <link rel="stylesheet" media="print" type="text/css" href="'.$ref.'print.css" />'.DOKU_LF;
80        $output .= '  <link rel="stylesheet" media="all" type="text/css" href="'.$ref.'export.css" />'.DOKU_LF;
81        $output .= '</head>'.DOKU_LF;
82        $output .= '<body>'.DOKU_LF;
83        $output .= '<div class="dokuwiki export">' . DOKU_LF;
84        $output .= tpl_toc(true);
85        $output .= $html;
86        $output .= '</div>';
87        $output .= '</body>'.DOKU_LF;
88        $output .= '</html>'.DOKU_LF;
89
90        $this->_addFile(str_replace(':','/',$ID).'.html',$output);
91        $this->media = array_merge($this->media, $this->Renderer->_media);
92    }
93
94    public function finish_packing() {
95        global $conf;
96
97        // now embed the media
98        $this->media = array_map('cleanID',$this->media);
99        $this->media = array_unique($this->media);
100        foreach($this->media as $id) {
101            if( auth_quickaclcheck($id) < AUTH_READ ) continue;
102            @set_time_limit(30);
103            $this->_addFile('_media/'.str_replace(':','/',$id),io_readFile(mediaFN($id),false));
104        }
105
106        // add the merge directory contents
107        $this->recursive_add(dirname(__FILE__).'/merge');
108
109        // finished data collecting
110        $to = $conf['tmpdir'] . '/wrk-' . $this->fileid . '.zip';
111
112        // append wiki export
113        $zipper = new nsexport_ziplib();
114        $zipper->setup($this);
115        $zipper->compress($this->tmp, $to);
116
117        // cleanup
118        $this->rmdirr($this->tmp);
119
120        // rename so ajax can find it
121        rename($to, $this->result_filename());
122    }
123
124    /**
125     * add a single file.
126     *
127     * @param string $filename     filename to store
128     * @param string $content      the file content
129     */
130    public function _addFile($filename, $content) {
131        $filename = $this->tmp . "/$filename";
132        io_makeFileDir($filename);
133        file_put_contents($filename , $content);
134    }
135
136    /**
137     * add a whole dir with subdirs.
138     */
139    public function recursive_add($base, $dir='') {
140        $fh = @opendir("$base/$dir");
141        if(!$fh) return;
142        while(false !== ($file = readdir($fh))) {
143            @set_time_limit(30);
144            if($file === '..' || $file[0] === '.') continue;
145            if(is_dir("$base/$dir/$file")) {
146                $this->recursive_add($base,"$dir/$file");
147            }else {
148                $this->_addFile("$dir/$file",io_readFile("$base/$dir/$file",false));
149            }
150        }
151        closedir($fh);
152    }
153
154    /**
155     * Delete a file, or a folder and its contents (recursive algorithm)
156     *
157     * @author      Aidan Lister <aidan@php.net>
158     * @version     1.0.3
159     * @link        http://aidanlister.com/repos/v/function.rmdirr.php
160     * @param       string   $dirname    Directory to delete
161     * @return      bool     Returns TRUE on success, FALSE on failure
162     */
163    public function rmdirr($dirname) {
164        // Sanity check
165        if (!file_exists($dirname)) {
166            return false;
167        }
168
169        // Simple delete for a file
170        if (is_file($dirname) || is_link($dirname)) {
171            return unlink($dirname);
172        }
173
174        // Loop through the folder
175        $dir = dir($dirname);
176        while (false !== $entry = $dir->read()) {
177            // Skip pointers
178            if ($entry === '.' || $entry === '..') {
179                continue;
180            }
181
182            // Recurse
183            $this->rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
184        }
185
186        // Clean up
187        $dir->close();
188        return rmdir($dirname);
189    }
190
191}
192