3 # This is a replacement for the ewiki.php internal MySQL database access
4 # interface; this one saves all WikiPages in so called "flat files", and
5 # there are now two different formats you can choose from:
6 # * rfc822-style (or say message/http like),
7 # which leads to files you can edit with any available text editor
8 # * in a compressed and faster 'binary' format,
9 # which supports more functionality (hit counting)
10 # enable with EWIKI_DB_FAST_FILES set to 1
11 # As this plugin can read both, you are free to switch at any time.
13 # To enable it, just include() this plugin __before__ the main/core
14 # ewiki.php script using:
16 # include("plugins/db/flat_files.php");
18 # If you only will use the file database, you could go to the bottom of the
19 # "ewiki.php" script and replace the 'ewiki_database_mysql' class with the
20 # one defined herein. Then make also sure, that the initialization code knows
21 # about it (there is a class name reference in $ewiki_plugins["database"]).
25 # The config option EWIKI_DBFILES_DIRECTORY must point to a directory
26 # allowing write access for www-data (the user id, under which webservers
27 # run usually), use 'chmod 757 dirname/' (from ftp or shell) to achieve this
31 # Some versions of PHP and zlib do not work correctly under Win32, so
32 # you should disable it either in the php.ini, or via .htaccess:
33 # php_option disable_functions "gzopen gzread gzwrite gzseek gzclose"
34 # You need the plugins/db/fakezlib.php script for very old PHP versions.
36 # db_fast_files` code was contributed_by("Carsten Senf <ewiki@csenf.de>");
39 #-- choose flat file format
40 define("EWIKI_DB_FAST_FILES", 0);
41 define("EWIKI_DBFF_ACCURATE", 0);
44 #-- plugin registration
45 $ewiki_plugins["database"][0] = "ewiki_database_files";
49 class ewiki_database_files {
51 function ewiki_database_files() {
55 function GET($id, $version=false) {
57 if (!$version && !($version = $this->LASTVER($id))) {
61 $dbfile = $this->FN("$id.$version");
62 if ($f = @gzopen($dbfile, "rb")) {
63 $dat = gzread($f, 1<<21);
68 if ($dat && (substr($dat, 0, 2) == "a:")) {
69 $r = unserialize($dat);
73 $p = strpos($dat, "\012\015\012");
74 $p2 = strpos($dat, "\012\012");
75 if ((!$p2) || ($p) && ($p < $p2)) {
81 $r["content"] = substr($dat, $p);
82 $dat = substr($dat, 0, $p);
84 foreach (explode("\012", $dat) as $h) {
86 $r[trim(strtok($h, ":"))] = str_replace(EWIKI_DBFILES_NLR, "\n", trim(strtok("\000")));
94 function WRITE($hash, $overwrite=0) {
97 $dbfile = $this->FN($hash["id"].".".$hash["version"]);
98 if (!$overwrite && file_exists($dbfile)) {
103 if (EWIKI_DB_FAST_FILES) {
104 $val = serialize($hash);
105 if (($f = gzopen($dbfile, "wb".EWIKI_DBFILES_GZLEVEL))) {
113 foreach ($hash as $hn=>$hv) if ($hn != "content") {
114 $headers .= $hn . ": " . str_replace("\n", EWIKI_DBFILES_NLR, $hv) . "\015\012";
116 if ($f = fopen($dbfile, "wb")) {
118 fputs($f, $headers . "\015\012" . $hash["content"]);
128 if (EWIKI_DB_FAST_FILES) {
129 $dbfile = $this->FN("$id.1");
130 if ($f = gzopen($dbfile, "rb")) {
131 $r = unserialize(gzread($ff, 1<<21));
135 if ($f = gzopen($dbfile, "wb".EWIKI_DBFILES_GZLEVEL)) {
136 gzwrite($fp, serialize($r));
142 function FIND($list) {
143 $existing = array_flip($this->ALLFILES());
145 foreach ($list as $id) {
146 $dbfile = $this->FN($id, 0);
147 $r[$id] = isset($existing[$dbfile]) ?1:0;
148 if (EWIKI_DBFF_ACCURATE && $r[$id] && strpos($id, "://")) {
149 $uu = $this->GET($id);
151 $r[$id] = unserialize($uu["meta"]);
152 $r[$id]["flags"] = $uu["flags"];
154 $r[$id] = $uu["flags"];
162 function GETALL($fields, $mask=0, $filter=0) {
163 $r = new ewiki_dbquery_result($fields);
164 foreach ($this->ALLFILES() as $id) {
171 function SEARCH($field, $content, $ci="i", $regex=0, $mask=0, $filter=0) {
172 $r = new ewiki_dbquery_result(array($field));
173 $strsearch = $ci ? "stristr" : "strpos";
174 foreach ($this->ALLFILES() as $id) {
175 $row = $this->GET($id);
176 if ($mask && ($filter == $row["flags"] & $mask)) {
180 !$regex && ($strsearch($row[$field], $content)!==false)
181 || $regex && preg_match("\007$content\007$ci", $row[$field]);
190 function DELETE($id, $version) {
191 $fn = $this->FN("$id.$version");
196 if (!is_writeable(EWIKI_DBFILES_DIRECTORY) || !is_dir(EWIKI_DBFILES_DIRECTORY)) {
197 mkdir(EWIKI_DBFILES_DIRECTORY)
198 or die("db_flat_files: »database« directory '".EWIKI_DBFILES_DIRECTORY."' is not writeable!\n");
204 #-- db plugin internal ----------------------------------------------
206 function FN($id, $prepend_path=1) {
207 $fn = EWIKI_DBFILES_ENCODE ? urlencode($id) : strtr($id, '/:', '\\:');
209 $fn = EWIKI_DBFILES_DIRECTORY.DIRECTORY_SEPARATOR . $fn;
216 $id = EWIKI_DBFILES_ENCODE ? urldecode($fn) : strtr($fn, '\\:', '/:');
221 function LASTVER($id) {
222 $find = $this->FN($id, 0);
223 $find_n = strlen($find);
226 $dh = opendir(EWIKI_DBFILES_DIRECTORY);
227 while ($fn = readdir($dh)) {
228 if ( (strpos($fn, $find) === 0) && //@FIXME: empty delimiter
229 ($dot = strrpos($fn, ".")) && ($dot == $find_n) &&
230 ($uu = substr($fn, ++$dot)) && ($uu > $n) )
239 function ALLFILES() {
241 $dh = opendir(EWIKI_DBFILES_DIRECTORY);
243 while ($fn = readdir($dh)) {
244 if (is_file(EWIKI_DBFILES_DIRECTORY . "/" . $fn)) {
245 $id = $this->ID($fn);
246 if (($dot = strrpos($id, ".")) && (substr($id, $dot+1) >= 1)) {
247 $file = substr($id, 0, $dot);
252 $r = array_unique($r);
257 $r = array_unique($r);
262 } // end of class ewiki_database_files