1<?php
2
3if (!defined('DOKU_PLUGIN')) die('meh');
4require_once(DOKU_PLUGIN . 'siteexport/inc/pdfgenerator.php');
5
6class siteexport_zipfilewriter
7{
8    /**
9     * further classes
10     */
11    private $pdfGenerator = null;
12    private $functions = null;
13
14    public function __construct($functions = null)
15    {
16        $this->functions = $functions;
17        if (class_exists('siteexport_pdfgenerator'))
18        {
19            $this->pdfGenerator = new siteexport_pdfgenerator($functions);
20        }
21    }
22
23    public function canDoPDF()
24    {
25        return $this->pdfGenerator !== null;
26    }
27
28
29    /**
30     * Wrapper for fetching the Context or the TOC for Eclipse Documentation
31     * This also puts the file into the zip package
32     **/
33    public function __moveDataToZip($DATA, $FILENAME = 'toc.xml', $ZIP = null, $JUSTWRITE = false) {
34
35        if (empty($DATA)) { return false; }
36
37        $tmpFile = tempnam($this->functions->settings->tmpDir, 'siteexport__') ?: $this->functions->settings->tmpDir . 'siteexport__';
38
39        if (@file_put_contents($tmpFile, $DATA) === false) {
40            // There was an error here
41        }
42
43        // Add to zip
44        if ($JUSTWRITE) {
45            $status = $this->__writeFileToZip($tmpFile, $FILENAME, $ZIP);
46        } else {
47            $status = $this->__addFileToZip($tmpFile, $FILENAME, $ZIP);
48        }
49
50        if (@unlink($tmpFile) === false) {
51            unset($tmpFile);
52        }
53
54        return $status;
55    }
56
57    /**
58     * Adds a file to the zip file
59     * @param $FILE String file-name of the zip
60     * @param $NAME String name of the file that is being added
61     * @param $ZIP String name of the zip file to which we add
62     */
63    public function __addFileToZip($FILE, $NAME, $ZIP = null) {
64
65        if ($NAME[0] === "/") {
66            $this->functions->debug->message("Weird, the NAME for the ZIP started with a '/'. This may result in wrong links!", null, 3);
67            $NAME = substr($NAME, 1);
68        }
69
70        // check for mpdf
71        if ($this->canDoPDF()) {
72            $this->functions->debug->message("Trying to create PDF from File '$FILE' with name '$NAME' for ZIP '$ZIP'", null, 2);
73
74            $succeeded = $this->pdfGenerator->createPDFFromFile($FILE, $NAME);
75
76            if ($this->functions->debug->debugLevel() <= 1) { // 2011-01-12 Write HTML to ZIP for Debug purpose
77                $this->__moveDataToZip($succeeded, "_debug/$NAME.html", $ZIP, true);
78            }
79
80            if ($succeeded === false) {
81                $this->functions->debug->runtimeException("Create PDF from File '$FILE' with name '$NAME' went wrong and is not being added!");
82                return false;
83            }
84        }
85
86        return $this->__writeFileToZip($FILE, $NAME, $ZIP);
87    }
88
89    /**
90     * This really writes a file to a zip-file
91     * @param $FILE String file-name of the zip
92     * @param $NAME String name of the file that is being added
93     * @param $ZIP String name of the zip file to which we add
94     */
95    private function __writeFileToZip($FILE, $NAME, $ZIPFILE) {
96        if (empty($ZIPFILE)) $ZIPFILE = $this->functions->settings->zipFile;
97
98        if (!class_exists('ZipArchive')) {
99            $this->functions->debug->runtimeException("PHP class 'ZipArchive' does not exist. Please make sure that you have the ziplib extension for PHP installed.");
100            return false;
101        }
102
103        $zip = new ZipArchive();
104        if (!$zip) {
105            $this->functions->debug->runtimeException("Can't create new instance of 'ZipArchive'. Please make sure that you have the ziplib extension for PHP installed.");
106            return false;
107        }
108
109        $code = $zip->open($ZIPFILE, ZipArchive::CREATE);
110        if ($code === TRUE) {
111
112            $this->functions->debug->message("Adding file '{$NAME}' to ZIP {$ZIPFILE}", null, 2);
113
114            $zip->addFile($FILE, $NAME);
115            $zip->close();
116
117            // If this has worked out, we may put this version into the cache ... ?
118
119            // ALibi Touching - 2011-09-13 wird nicht gebraucht nach Umstellung
120
121            return true;
122        }
123
124        $this->functions->debug->runtimeException("Zip Error #{$code} for file {$NAME}");
125        return false;
126    }
127
128    /**
129     * check if a file exists allready
130     * @param $NAME String name of the file in the zip
131     */
132    public function fileExistsInZip($NAME)
133    {
134        $zip = new ZipArchive();
135        $code = $zip->open($this->functions->settings->zipFile, ZipArchive::CREATE);
136        if ($code === TRUE) {
137            $exists = !($zip->statName($NAME) === FALSE);
138            $zip->close();
139            return $exists;
140        }
141
142        return false;
143    }
144
145    /**
146     * Checks if a valid cache file exists for the given request parameters
147     * @param $requestData
148     */
149    public function hasValidCacheFile($requestData, $depends = array())
150    {
151        $pattern = $this->functions->requestParametersToCacheHash($requestData);
152        return $this->hasValidCacheFileForPattern($pattern, $depends);
153    }
154
155    private function hasValidCacheFileForPattern($pattern, $depends = array())
156    {
157        $this->functions->debug->message("HASH-Pattern for CacheFile: ", $pattern, 2);
158        $this->functions->settings->hasValidCacheFile = false; // reset the cache settings
159        $cacheFile = $this->functions->getCacheFileNameForPattern($pattern);
160
161        $mtime = @filemtime($cacheFile); // 0 if not exists
162
163        // Check if the file is expired - if so, just create a new one.
164        if ($mtime == 0 || $mtime < time()-$this->functions->settings->cachetime)
165        {
166            $this->__clearCacheFile( $cacheFile );
167            $this->functions->debug->message("New CacheFile because the file was over the cachetime: ", $cacheFile, 2);
168            return false;
169        }
170
171        // Check for dependencies
172        if (!empty($depends))
173        {
174            $this->functions->debug->message("Checking dependencies: ", $depends, 1);
175            foreach ($depends as $site) {
176
177                if (!page_exists($site['id']))
178                {
179                    $this->functions->debug->message("File does not exist: ", $site['id'], 2);
180                    continue;
181                }
182
183                if ($mtime < @filemtime(wikiFN($site['id']))) {
184                    $this->__clearCacheFile( $cacheFile );
185                    $this->functions->debug->message("New CacheFile, because a page changed: ", $cacheFile, 2);
186                    return false; // cache older than files it depends on?
187                }
188            }
189        }
190
191        $this->functions->debug->message("CacheFile exists: ", $cacheFile, 2);
192        return $this->functions->settings->hasValidCacheFile = true;
193    }
194
195    private function __clearCacheFile( $cacheFile ) {
196        if ( @unlink($cacheFile) === false ||
197             @unlink($this->functions->settings->zipFile) === false ) {
198             $this->functions->debug->message("Cannot remove cache Files: ", $cacheFile, 2);
199        }
200    }
201
202    public function getOnlyFileInZip(&$data = null) {
203
204        if (is_null($data['file'])) $data['file'] = $this->functions->settings->zipFile;
205
206        $zip = new ZipArchive();
207        $code = $zip->open($data['file']);
208        if ($code !== TRUE) {
209            $this->functions->debug->message("Can't open the zip-file.", $data['file'], 2);
210            return false;
211        }
212
213        if ($zip->numFiles != 1) {
214            $zip->close();
215            $this->functions->debug->message("More than one ({$zip->numFiles}) file in zip.", $data['file'], 2);
216            return false;
217        }
218
219        $stat = $zip->statIndex(0);
220        $this->functions->debug->message("Stat.", $stat, 3);
221        if (substr($stat['name'], -3) != 'pdf') {
222            $zip->close();
223            $this->functions->debug->message("The file was not a PDF ({$stat['name']}).", $stat['name'], 2);
224            return false;
225        }
226
227        $data['mime'] = 'application/pdf';
228
229        // Extract single file.
230        $folder = dirname($data['file']);
231
232        $data['orig'] = utf8_basename($stat['name']);
233        $zip->extractTo($folder, $stat['name']);
234        $zip->close();
235
236        sleep(1);
237        $data['file'] .= '.' . cleanID($data['orig']); // Wee need the other file for cache reasons.
238        return (@rename($folder.'/'.$data['orig'], $data['file'])) === true;
239    }
240}
241
242