JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
fdb works, added fault-tollerent read_wole_file
[wfpl.git] / fdb.php
1 <?php
2
3 #  Copyright (C) 2007 Jason Woofenden
4 #
5 #  This file is part of wfpl.
6 #
7 #  wfpl is free software; you can redistribute it and/or modify it under the
8 #  terms of the GNU Lesser General Public License as published by the Free
9 #  Software Foundation; either version 2.1 of the License, or (at your option)
10 #  any later version.
11 #
12 #  wfpl is distributed in the hope that it will be useful, but WITHOUT ANY
13 #  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 #  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15 #  more details.
16 #
17 #  You should have received a copy of the GNU Lesser General Public License
18 #  along with wfpl; if not, write to the Free Software Foundation, Inc., 51
19 #  Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
21
22 # This file contains code to use a web-writeable directory full of files as a
23 # very simple database.
24
25 # Keys are truncated to 32 bytes, made lowercase, and all characters that are
26 # not alpha/numeric are replaced with underscores. Periods and hyphens are only
27 # replaced if they are at the begining.
28
29 # Data can be either a string or an array.
30
31 # To set up the database, make a directory that's writeable by PHP and call
32 # fdb_set_dir() passing the path to that directory.
33
34
35 require_once('code/wfpl/file.php');
36
37 # call this to set what directory is used to store the files
38 function fdb_set_dir($dir) {
39         $GLOBALS['fdb_dir'] = $dir;
40 }
41
42 function fdb_get_dir() {
43         if(!isset($GLOBALS['fdb_dir'])) {
44                 die('you must call fdb_set_dir() before calling other functions in code/wfpl/fdb.php');
45         }
46         return $GLOBALS['fdb_dir'];
47 }
48
49 # return a 4 bytes that represent the passed integer as a big-endian binary number
50 function to_raw_int($int) {
51         return chr($int >> 24) . chr(($int >> 16) & 0xff) . chr(($int >> 8) & 0xff) . chr($int & 0xff);
52 }
53
54 # return a php number from the string you pass in. The first 4 bytes of the
55 # string are read in as a binary value in big-endian format.
56 function from_raw_int($quad) {
57         return (ord(substr($quad, 0, 1)) << 24) + (ord(substr($quad, 1, 1)) << 16) + (ord(substr($quad, 2, 1)) << 8) + ord(substr($quad, 3, 1));
58 }
59
60 function int_at($string, $index) {
61         return from_raw_int(substr($string, $index * 4, 4));
62 }
63
64 # remove the first 4 bytes of the string, and return them as an int
65 function pop_int(&$string) {
66         $int = from_raw_int(substr($string, 0, 4));
67         $string = substr($string, 4);
68         return $int;
69 }
70
71
72 function fdb_fix_key($key) {
73         $key = ereg_replace('[^a-z0-9.-]', '_', strtolower($key));
74         $key = ereg_replace('^[-.]', '_', strtolower($key));
75         return substr($key, 0, 32);
76 }
77
78
79 function fdb_get_raw($key) {
80         $key = fdb_fix_key($key);
81         return read_whole_file_or_false(fdb_get_dir() . "/$key");
82 }
83
84 function fdb_set_raw($key, $data) {
85         $key = fdb_fix_key($key);
86         write_whole_file(fdb_get_dir() . "/$key", $data);
87 }
88
89 # like fdb_get() except it returns an array even when there's just one element
90 function fdb_geta($key) {
91         $key = fdb_fix_key($key);
92         $data = fdb_get_raw($key);
93         if($data === false) {
94                 return false;
95         }
96         $header_count = pop_int($data);
97         $out = array();
98         while($header_count--) {
99                 $size = pop_int($data);
100                 $out[] = substr($data, 0, $size);
101                 $data = substr($data, $size);
102         }
103         return $out;
104 }
105
106 # returns:
107 #
108 # false if the key is not found in the database
109 #
110 # an array from the file otherwise
111 #
112 # a string if there's one field in that file (use fdb_geta() if you want an
113 # array in this case too)
114 function fdb_get($key) {
115         $ret = fdb_geta($key);
116         if($ret == false) {
117                 return false;
118         }
119         if(count($ret) == 1) {
120                 return $ret[0];
121         } else {
122                 return $ret;
123         }
124 }
125
126 # data can be a string or array
127 function fdb_set($key, $data) {
128         $key = fdb_fix_key($key);
129         if(!is_array($data)) {
130                 $data = array($data);
131         }
132         $out = to_raw_int(count($data));
133         foreach($data as $dat) {
134                 $out .= to_raw_int(strlen($dat));
135                 $out .= $dat;
136         }
137         fdb_set_raw($key, $out);
138 }
139
140 ?>