fcd70b7dca979d6172292019afc534c13bd60732
[atutor.git] / mods / wiki / plugins / page / wikidump2.php
1 <?php
2
3 /*
4    Allows to download a tarball including all WikiPages and images that
5    currently are in the database.
6 */
7
8
9 #-- text
10 $ewiki_t["en"]["WIKIDUMP"] = "Here you can tailor your WikiDump to your needs.  <br /> When you are ready, click the \"_{DOWNLOAD_ARCHIVE}\" button.";
11 $ewiki_t["en"]["DOWNLOAD_ARCHIVE"] = "Download WikiDump";
12
13 define("EWIKI_WIKIDUMP_ARCNAME", "WikiDump_");
14 define("EWIKI_WIKIDUMP_DEFAULTTYPE", "TAR");
15 define("EWIKI_WIKIDUMP_MAXLEVEL", 1);
16 define('EWIKI_DUMP_FILENAME_REGEX',"/\W/");
17
18 #-- glue
19 if((function_exists(gzcompress) && EWIKI_WIKIDUMP_DEFAULTTYPE=="ZIP") || EWIKI_WIKIDUMP_DEFAULTTYPE=="TAR"){
20   $ewiki_plugins["page"]["WikiDump"] = "ewiki_page_wiki_dump_tarball";
21   $ewiki_plugins["action"]['wikidump'] = "ewiki_page_wiki_dump_tarball";
22 }
23
24 $ewiki_t["c"]["EWIKIDUMPCSS"] = '
25   <style  TYPE="text/css">
26   <!--
27   body {
28     background-color:#eeeeff;
29     padding:2px;
30   }     
31   
32   H2 {
33     background:#000000;
34     color:#ffffff;
35     border:1px solid #000000;
36   }
37   -->
38   </style>
39   ';  
40   
41
42 function ewiki_page_wiki_dump_tarball($id=0, $data=0, $action=0) {
43
44    #-- return legacy page
45    if (empty($_REQUEST["download_tarball"])) {
46     if($action=="wikidump"){
47       $url = ewiki_script("", "WikiDump");
48       return(ewiki_make_title($id, $id, 2) . ewiki_t(<<<END
49 _{WIKIDUMP}
50 <br /><br />
51 <form action="$url" method="POST" enctype="multipart/form-data">
52 <input type="hidden" name="dump_id" value="$id">
53 <input type="hidden" name="dump_depth" value=1>
54 <input type="submit" name="download_tarball" value= "_{DOWNLOAD_ARCHIVE}">
55 <br /><br />
56 <input type="checkbox" name="dump_images" value="1" checked> _{with images}<br />
57 <input type="hidden" name="dump_fullhtml" value="1">
58 <input type="hidden" name="dump_virtual" value="0"><br />
59 Archive Format:
60 <select NAME="dump_arctype">
61   <option VALUE="ZIP">ZIP
62   <option VALUE="TAR">TAR
63 </select>
64
65 </form>
66 END
67       ));
68       } else {
69         return "";
70       }
71    }
72    #-- tarball generation
73    else {
74       $di = $_REQUEST["dump_images"];
75       $fh = $_REQUEST["dump_fullhtml"];
76       $vp = $_REQUEST["dump_virtual"];
77       $rp = $_REQUEST["dump_id"];
78       
79       #-- $_REQUEST["dump_depth"]==100 will give a complete dump
80       if(($_REQUEST["dump_depth"]>EWIKI_WIKIDUMP_MAXLEVEL) && ($_REQUEST["dump_depth"]!=100)){
81         $dd=EWIKI_WIKIDUMP_MAXLEVEL;
82       } else {
83         $dd = $_REQUEST["dump_depth"];
84       }
85       $at = $_REQUEST["dump_arctype"];
86       $al = 9;#$_REQUEST["dump_arclevel"];
87       $_REQUEST = $_GET = $_POST = array();
88       if(!ewiki_auth($rp, $str_null, "view")){
89         return ewiki_make_title($id, $id, 2)."<p>You either do not have permission to access the page $rp or it does not exist.</p>";
90       }
91       ewiki_page_wiki_dump_send($di, $fh, $vp, $rp, $dd, $at, $al);
92    }
93 }
94
95
96 function ewiki_page_wiki_dump_send($imgs=1, $fullhtml=0, $virtual=0, $rootid, $depth=1, $arctype=EWIKI_WIKIDUMP_DEFAULTTYPE, $complevel=1) {
97
98   global $ewiki_config, $ewiki_plugins;
99   
100   #-- disable protected email
101   foreach($ewiki_plugins["link_url"] as $key => $linkplugin){
102     if($linkplugin == "ewiki_email_protect_link"){
103       unset($ewiki_plugins["link_url"][$key]);
104     }
105   }
106
107   #-- set uservars
108   $a_uservars = ewiki_get_uservar("WikiDump", array());
109   if(!is_array($a_uservars)){
110     $a_uservars = unserialize($a_uservars);
111   }
112   $a_uservars[$rootid] = $depth;
113   ewiki_set_uservar("WikiDump", $a_uservars);
114   
115   #-- if $fullhtml
116   $HTML_TEMPLATE = '<html>
117     <head>'.ewiki_t("EWIKIDUMPCSS").'
118     <title>$title</title>
119     </head>
120     <body bgcolor="#ffffff";>
121     <div id="PageText">
122     <h2>$title</h2>
123     $content
124     </div>
125     </body>
126     </html>
127     ';
128   
129   #-- reconfigure ewiki_format() to generate offline pages and files
130   $html_ext = ".htm";
131   if ($fullhtml) {
132     $html_ext = ".html";
133   }
134   $ewiki_config["script"] = "%s$html_ext";
135   $ewiki_config["script_binary"] = "%s";
136   
137   #-- fetch also dynamic pages
138   $a_virtual = array_keys($ewiki_plugins["page"]);
139   
140
141   #-- get all pages / binary files
142   $a_validpages = ewiki_valid_pages(1, $virtual);
143   $a_pagelist = ewiki_sitemap_create($rootid, $a_validpages, $depth, 1);
144
145   foreach($a_pagelist as $key => $value){
146     if(is_array($a_validpages[$value]["refs"])){
147       foreach($a_validpages[$value]["refs"] as $refs){
148         if($a_validpages[$refs]["type"]=="image"){
149           $a_pagelist[]=$refs;
150         }
151       }
152     }
153   }
154   
155   foreach($a_pagelist as $key => $value){
156     if($a_validpages[$value]["type"]=="image"){
157       $a_images[]=urlencode($value);
158       $a_rimages[]=urlencode(preg_replace(EWIKI_DUMP_FILENAME_REGEX, "", $value));
159       unset($a_validpages[$value]);
160     }
161   }
162
163   $a_sitemap = ewiki_sitemap_create($rootid, $a_validpages, $depth, 0);
164
165   if ($a_pagelist) {
166     #-- create new zip file
167     if($arctype == "ZIP"){
168       $archivename=EWIKI_WIKIDUMP_ARCNAME."$rootid.zip";
169       $archive = new ewiki_virtual_zip();
170     } elseif ($arctype == "TAR") {
171       $archivename=EWIKI_WIKIDUMP_ARCNAME."$rootid.tar";
172       $archive = new ewiki_virtual_tarball();
173     } else {
174       die();
175     }
176     
177     $a_pagelist = array_unique($a_pagelist);
178     
179     #-- convert all pages
180     foreach($a_pagelist as $pagename){
181       if ((!in_array($pagename, $a_virtual))) {
182         $id = $pagename;
183         #-- not a virtual page
184         $row = ewiki_db::GET($pagename);
185         $content = "";
186       } elseif($virtual) {
187         $id = $pagename;
188         #-- is a virtual page
189         $pf = $ewiki_plugins["page"][$id];
190         $content = $pf($id, $content, "view");
191         if ($fullhtml) {
192           $content = str_replace('$content', $content, str_replace('$title', $id, $HTML_TEMPLATE));
193         }
194         $fn = urlencode($id);
195         $fn = preg_replace(EWIKI_DUMP_FILENAME_REGEX, "", $fn);
196         $fn = $fn.$html_ext;
197       } else {
198         continue;
199       }
200     
201       if (empty($content)){
202         switch ($row["flags"] & EWIKI_DB_F_TYPE) {
203           case (EWIKI_DB_F_TEXT):
204             $content = ewiki_format($row["content"]);
205             $content = str_replace($a_images, $a_rimages, $content);
206             $fn = preg_replace(EWIKI_DUMP_FILENAME_REGEX, "",  urlencode($id));
207             $fn = $fn.$html_ext;
208             if ($fullhtml) {
209               $content =  str_replace('$content', $content, str_replace('$title', $id, $HTML_TEMPLATE));
210             }
211             break;
212           
213           case (EWIKI_DB_F_BINARY):
214             if (($row["meta"]["class"]=="image") && ($imgs)) {
215               $fn = urlencode(preg_replace(EWIKI_DUMP_FILENAME_REGEX, "", $id));
216               $content = &$row["content"];
217             }
218             else {
219               #-- php considers switch statements as loops so continue 2 is needed to 
220               #-- hit the end of the for loop 
221               continue(2);
222             }
223             break;
224           
225           default:
226             # don't want it
227             continue(2);
228         }
229       }
230   
231       $content=preg_replace_callback(
232         '/(<a href=")(.*?)(\.html">)/',
233         create_function(
234         // single quotes are essential here,
235         // or alternative escape all $ as \$
236         '$matches',
237         'return($matches[1].preg_replace(EWIKI_DUMP_FILENAME_REGEX,"",$matches[2]).$matches[3]);'
238         ),
239         $content
240         );
241
242       #-- add file
243       $archive->add($content, $fn, array(
244         "mtime" => $row["lastmodified"],
245         "uname" => "ewiki",
246         "mode" => 0664 | (($row["flags"]&EWIKI_DB_F_WRITEABLE)?0002:0000),
247         ), $complevel);
248     }
249     
250     #-- create index page
251     $timer=array();
252     $level=-1;
253     $fordump=1;
254     $str_formatted="<ul>\n<li><a href=\"".$rootid.$html_ext."\">".$rootid."</a></li>";
255     $fin_level=format_sitemap($a_sitemap, $rootid, $str_formatted, $level, $timer, $fordump);
256     $str_formatted.="</ul>".str_pad("", $fin_level*6, "</ul>\n");
257     $str_formatted=preg_replace_callback(
258         '/(<a href=")(.*?)(\.html">)/',
259         create_function(
260            // single quotes are essential here,
261            // or alternative escape all $ as \$
262            '$matches',
263            'return($matches[1].preg_replace(EWIKI_DUMP_FILENAME_REGEX,"",$matches[2]).$matches[3]);'
264         ),
265         $str_formatted
266       );
267   
268     #-- add index page
269     $archive->add($str_formatted, "Index_$rootid".$html_ext, array(
270       "mtime" => $row["lastmodified"],
271       "uname" => "ewiki",
272       "mode" => 0664 | (($row["flags"]&EWIKI_DB_F_WRITEABLE)?0002:0000),
273       ), $complevel);
274          
275     #-- Headers
276     Header("Content-type: application/octet-stream");
277     Header("Content-disposition: attachment; filename=\"$archivename\"");
278     Header("Cache-control: private");
279     Header("Original-Filename: $archivename");    
280     Header("X-Content-Type: application/octet-stream");
281     Header("Content-Location: $archivename");
282
283
284     #-- end output
285     echo $archive->close();
286   
287   }
288   
289   #-- fin 
290   die();
291 }
292
293
294
295
296 ############################################################################
297
298
299
300
301 #-- allows to generate a tarball from virtual files
302 #   (supports no directories or symlinks and other stuff)
303 class ewiki_virtual_tarball {
304
305    var $f = 0;
306    var $datasec = array(); 
307
308    function close() {
309       #-- fill up file
310       $this->write(str_repeat("\000", 9*1024));
311       $data = implode("", $this -> datasec); 
312       return $data;
313    }
314
315
316    function write($str) {
317      $this ->datasec[] = $str;
318    }
319
320
321    function oct($int, $len) {
322       $o = "\000";
323       while (--$len) {
324          $o = ($int & 0x07) . $o;
325          $int = $int >> 3;
326       }
327       return($o);
328    }
329
330
331    #-- add virtual file
332    function add($content, $filename, $args=array(), $ignored) {
333    $args = array_merge($args, array(
334          "mode" => 000664,
335          "mtime" => time(),
336          "ctime" => time(),
337          "uid" => 65534,       #-- common for user "nobody"
338          "gid" => 65534,
339          "uname" => "nobody",
340          "gname" => "nobody",
341          "type" => "0",
342       ));
343       $args["mode"] |= 0100000;
344       $args["size"] = strlen($content);
345       $checksum = "        ";
346       $magic = "ustar  \000";
347       $filename = substr($filename, 0, 99);
348
349       #-- header record
350       $header  = str_pad($filename, 100, "\000")            # 0x0000
351                . $this->oct($args["mode"], 8)               # 0x0064
352                . $this->oct($args["uid"], 8)                # 0x006C
353                . $this->oct($args["gid"], 8)                # 0x0074
354                . $this->oct($args["size"], 12)              # 0x007C
355                . $this->oct($args["mtime"], 12)             # 0x0088
356                . ($checksum)                                # 0x0094
357                . ($args["type"])                            # 0x009C
358                . str_repeat("\000", 100)                    # 0x009D
359                . ($magic)                                   # 0x0101
360                . str_pad($args["uname"], 32, "\000")        # 0x0109
361                . str_pad($args["gname"], 32, "\000")        # 0x0129
362                ;                                            # 0x0149
363       $header = str_pad($header, 512, "\000");
364
365       #-- calculate and add header checksum
366       $cksum = 0;
367       for ($n=0; $n<512; $n++) {
368          $cksum += ord($header[$n]);
369       }
370       $header = substr($header, 0, 0x0094)
371               . $this->oct($cksum, 7) . " "
372               . substr($header, 0x009C);
373
374       #-- output
375       if ($fill = (512 - (strlen($content) % 512))) {
376          $content .= str_repeat("\000", $fill);
377       }
378       $this->write($header . $content);
379    }
380 }
381
382
383 class ewiki_virtual_zip 
384
385         var $datasec = array(); 
386         var $ctrl_dir = array(); 
387         var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; 
388         var $old_offset = 0; 
389         
390         function add($data, $name, $ignored, $complevel) { 
391                 $name = str_replace("\\", "/", $name); 
392                 $unc_len = strlen($data); 
393                 $crc = crc32($data); 
394                 $zdata = gzcompress($data, $complevel); 
395                 $zdata = substr ($zdata, 2, -4); 
396                 $c_len = strlen($zdata); 
397                 $fr = "\x50\x4b\x03\x04"; 
398                 $fr .= "\x14\x00"; 
399                 $fr .= "\x00\x00"; 
400                 $fr .= "\x08\x00"; 
401                 $fr .= "\x00\x00\x00\x00"; 
402                 $fr .= pack("V",$crc); 
403                 $fr .= pack("V",$c_len); 
404                 $fr .= pack("V",$unc_len); 
405                 $fr .= pack("v", strlen($name) ); 
406                 $fr .= pack("v", 0 ); 
407                 $fr .= $name; 
408                 $fr .= $zdata; 
409                 $fr .= pack("V",$crc); 
410                 $fr .= pack("V",$c_len); 
411                 $fr .= pack("V",$unc_len); 
412                 
413                 $this -> datasec[] = $fr; 
414                 $new_offset = strlen(implode("", $this->datasec)); 
415                 
416                 $cdrec = "\x50\x4b\x01\x02"; 
417                 $cdrec .="\x00\x00"; 
418                 $cdrec .="\x14\x00"; 
419                 $cdrec .="\x00\x00"; 
420                 $cdrec .="\x08\x00"; 
421                 $cdrec .="\x00\x00\x00\x00"; 
422                 $cdrec .= pack("V",$crc); 
423                 $cdrec .= pack("V",$c_len); 
424                 $cdrec .= pack("V",$unc_len); 
425                 $cdrec .= pack("v", strlen($name) ); 
426                 $cdrec .= pack("v", 0 ); 
427                 $cdrec .= pack("v", 0 ); 
428                 $cdrec .= pack("v", 0 ); 
429                 $cdrec .= pack("v", 0 ); 
430                 $cdrec .= pack("V", 32 ); 
431                 $cdrec .= pack("V", $this -> old_offset ); 
432                 
433                 $this -> old_offset = $new_offset; 
434                 
435                 $cdrec .= $name; 
436                 $this -> ctrl_dir[] = $cdrec; 
437         } 
438         
439         function close() { 
440                 $data = implode("", $this -> datasec); 
441                 $ctrldir = implode("", $this -> ctrl_dir); 
442                 
443                 return 
444                         $data . 
445                         $ctrldir . 
446                         $this -> eof_ctrl_dir . 
447                         pack("v", sizeof($this -> ctrl_dir)) . 
448                         pack("v", sizeof($this -> ctrl_dir)) . 
449                         pack("V", strlen($ctrldir)) . 
450                         pack("V", strlen($data)) . 
451                         "\x00\x00"; 
452         } 
453 }
454
455
456 ?>