69ee0d75a48ab39875b13d2c9185aa1403d787da
[atutor.git] / mods / wiki / plugins / db / read_pmwiki1.php
1 <?php
2
3 /*
4    This DB plugin allows to import PmWiki flat file databases. It is hard
5    to extend it as general backend, because that database format isn't all
6    too suiteable for ewiki (_BINARY entries are impossible with it and we
7    need random version access, not linear scan-through).
8    Importing goes by only reading a given sub database (it's always divided
9    into fragments). You eventually could access all by using "ext_subwiki"
10    and complicating the yoursite wrapper script (must extract PMWIKI_GROUP
11    from ?id= string much like PmWiki does itself).
12
13    In the _DIRS constant you define the paths to PmWikis wiki.d/ data
14    stores (there are typically two of them), where the first gets used
15    as active (writeable) directory.
16 */
17
18
19 #-- config
20 define("SUBWIKI_SEPARATOR", ".");
21 define("PMWIKI_DB_DIRS", "../pmwiki/wiki.d/:../pmiki/wikilib.d/");
22 define("PMWIKI_GROUP", "Main");
23
24
25 #-- run time
26 $subwiki = $_REQUEST["group"];
27 if (!$subwiki) {
28    $subwiki = PMWIKI_GROUP;
29 }
30
31
32 #-- register
33 $ewiki_plugins["database"][0] = "ewiki_database_pmwiki";
34
35
36 #-- backend
37 class ewiki_database_pmwiki {
38
39    var $dirs;
40    var $group;
41
42    function ewiki_database_pmwiki ($dirs=PMWIKI_DB_DIRS, $group=PMWIKI_GROUP) {
43       $this->dirs = explode(":", $dirs);
44       $this->group = $group;
45    }
46
47
48    #-- retrieve/decode pages
49    function GET($id, $version=false) {
50
51       static $last_id, $last;
52       $diffs = array();
53       $other = array();
54
55       #-- speedy access
56       if ($id == $last_id) {
57       
58          list($hash, $diffs, $other) = $last;
59          
60       }
61       #-- generic read
62       elseif ( ($fn = $this->FN($id)) && ($f = fopen($fn, "r")) )
63       {
64          $hash = array();
65          $nl = "\n";
66          do {
67          
68            #-- read line per line
69            $line = fgets($f, 1<<18);  // 256K
70            if ($l = strpos($line, "=")) {
71               $field = trim(substr($line, 0, $l));
72               $line = rtrim(substr($line, $l+1), "\n");
73            }
74            else {
75               // broken file?
76               $field = ":eof:";
77               continue;
78            }
79
80            #-- special field           
81            if ($field == "newline") {
82               $nl = $line;
83            }
84            #-- old revision fields
85            elseif (strpos($field, ":")) {
86               list($fi,$n1,$n2,$n3) = explode(":", $field);
87               if ($n2) {
88                  $diffs[$n2] = $line;
89               }
90               else {
91                  $other[$fi][$n1] = $line;
92               }
93            }
94            #-- ordinary entries
95            else {
96               switch ($field) {
97                  case "text":
98                     $hash["content"] = $line;
99                     break;
100                  case "name":
101                     if ($l = strpos($line, ".")) {
102                        $l = substr($line, $l+1);
103                     }
104                     $hash["id"] = $line;
105                     break;
106                  case "time":
107                     $hash["lastmodified"] = $line;
108                     break;
109                  case "host":
110                     if (empty($hash["author"])) {
111                        $hash["author"] = $line;
112                     }
113                     else {
114                        $hash["author"] .= " ($line)";
115                     }
116                     break;
117                  case "author":
118                     if (empty($hash["author"])) {
119                        $hash["author"] = $line;
120                     }
121                     else {
122                        $hash["author"] = $line . " ($hash[author])";
123                     }
124                     break;
125                  case "rev":
126                     $hash["version"] = $line;
127                     break;
128                  default:
129                     if ($field=="agent") {
130                        $field = "user-agent";
131                     }
132                     $hash["meta"][$field] = $line;
133               }
134            }
135
136          } while (!feof($f));
137          fclose($f);
138          
139          $last_id = $id;
140          $last = array($hash, $diffs, $other);
141          
142       }// read-in
143
144
145       #-- validity check
146       if ($hash["lastmodified"] && $hash["version"]) {
147
148          #-- guess missing information
149          $hash["created"] = filectime($fn);
150          $uu = array_flip(array_keys($diffs));
151          $last_diff_time = each($uu);
152 //         $hash["created"] = $last_diff_time;
153          $hash["hits"] = 0;
154          $hash["flags"] = EWIKI_DB_F_TEXT;
155          $hash["refs"] = "\n\n";
156          $hash["meta"] = (array)$hash["meta"];
157
158          #-- if prev version requested
159          if ($version && ($hash["version"] > $version)) {
160
161             #-- apply patches until it matches requested {version}
162             foreach ($diffs as $mtime=>$rpatch) {
163                if ($hash["version"] == $version) {
164                   break;
165                }
166
167                $hash["author"] = trim(
168                   $others[$mtime]["author"] . ' ('.$others[$mtime]["host"].')'
169                );
170                $hash["content"] = $this->PATCH($hash["content"], $rpatch);
171                $hash["version"]--;
172             }
173                 
174             if ($version < $hash["version"]) {
175                $hash = false;
176             }
177          }
178           
179       }
180       else {
181          $hash = NULL;
182       }
183
184       return($hash);    
185    }
186
187
188    #-- works
189    function GETALL($fields, $mask=0, $filter=0) { 
190       $r = new ewiki_dbquery_result($fields);
191       foreach ($this->LS() as $fn) {
192          if ($data = $this->GET($fn)) {
193             $r->add($data);
194          } 
195       }
196       return $r;
197    }
198
199
200    #-- stub
201    function HIT($id) {
202    }
203
204
205    #-- works
206    function FIND($list) {
207       $r = array();
208       $ls = $this->LS();
209       foreach ($list as $id) {
210          $r[$id] = in_array($id, $ls);
211       }
212       return $r;
213    }
214    
215
216    #-- search for given filename
217    function FN($base_id) {
218       $grp = $this->group;
219       $dot = SUBWIKI_SEPARATOR;
220       foreach ($this->dirs as $dir) {
221          if (file_exists($fn = "$dir/$grp$dot$base_id")) {
222             return $fn;
223          }
224       }
225    }
226
227    #-- returns list of all existing files
228    function LS() {
229       $cmp = $this->group . SUBWIKI_SEPARATOR;
230       $ncmp = strlen($cmp);
231       $r = array();
232       foreach ($this->dirs as $dir) if ($dh = opendir($dir)) {
233          while ($fn = readdir($fn)) if (!is_dir($fn)) {
234             if (strncmp($fn, $cmp, $ncmp) == 0) {
235                $r[] = substr($fn, $ncmp);
236             }
237          }
238          closedir($dh);
239       }
240       return $r;
241    }
242    
243    #-- for decoding older versions
244    function PATCH($content, $rpatch) {
245       $f1 = EWIKI_TMP."/ewiki-pmwiki-db-import-".crc32($content)."-".time();
246       $f2 = $f1 . ".patch";
247       fwrite($f = fopen($f1, "w"), $content) && fclose($f);
248       fwrite($f = fopen($f2, "w"), $rpatch) && fclose($f);
249       `patch $f1 $f2`;
250       $content = fread($f = fopen($f1, "r"), 1<<18); fclose($f);
251       unlink($f1);
252       unlink($f2);
253       return $content;
254    }
255
256
257 } // end of class
258
259
260
261 ?>