Fix ML utf-8 issues
[platal.git] / classes / xdb.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2007 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 **************************************************************************/
21
22 class XDB
23 {
24 public static $connec = null;
25 var $_trace_data = array();
26
27 public static function _prepare($args)
28 {
29 $query = array_map(Array('XDB', '_db_escape'), $args);
30 $query[0] = str_replace('{?}', '%s', str_replace('%', '%%', $args[0]));
31 return call_user_func_array('sprintf', $query);
32 }
33
34 public static function _reformatQuery($query)
35 {
36 $query = preg_split("/\n\\s*/", trim($query));
37 $length = 0;
38 foreach ($query as $key=>$line) {
39 $local = -2;
40 if (preg_match('/^([A-Z]+(?:\s+(?:JOIN|BY|FROM|INTO))?)\s+(.*)/u', $line, $matches)
41 && $matches[1] != 'AND' && $matches[1] != 'OR')
42 {
43 $local = strlen($matches[1]);
44 $line = $matches[1] . ' ' . $matches[2];
45 $length = max($length, $local);
46 }
47 $query[$key] = array($line, $local);
48 }
49 $res = '';
50 foreach ($query as $array) {
51 list($line, $local) = $array;
52 $local = max(0, $length - $local);
53 $res .= str_repeat(' ', $local) . $line . "\n";
54 $length += 2 * (substr_count($line, '(') - substr_count($line, ')'));
55 }
56 return $res;
57 }
58
59 public static function _query($query)
60 {
61 global $globals;
62
63 if ($globals->debug & 1) {
64 $explain = array();
65 if (strpos($query, 'FOUND_ROWS()') === false) {
66 $_res = mysqli_query(XDB::$connec, "EXPLAIN $query");
67 if ($_res) {
68 while ($row = mysqli_fetch_assoc($_res)) {
69 $explain[] = $row;
70 }
71 @mysqli_free_result($_res);
72 }
73 }
74 $trace_data = array('query' => XDB::_reformatQuery($query), 'explain' => $explain);
75 $time_start = microtime();
76 }
77
78 $res = mysqli_query(XDB::$connec, $query);
79
80 if ($globals->debug & 1) {
81 list($ue, $se) = explode(" ", microtime());
82 list($us, $ss) = explode(" ", $time_start);
83 $time = intval((($ue - $us) + ($se - $ss)) * 1000);
84 $trace_data['error'] = mysqli_error(XDB::$connec);
85 $trace_data['exectime'] = $time;
86 $trace_data['rows'] = @mysqli_num_rows($res) ? mysqli_num_rows($res) : mysqli_affected_rows(XDB::$connec);
87 $GLOBALS['XDB::trace_data'][] = $trace_data;
88 if (mysqli_errno(XDB::$connec)) {
89 $GLOBALS['XDB::error'] = true;
90 }
91 }
92
93 return $res;
94 }
95
96 public static function query()
97 {
98 return new XOrgDBResult(XDB::_prepare(func_get_args()));
99 }
100
101 public static function execute()
102 {
103 return XDB::_query(XDB::_prepare(func_get_args()));
104 }
105
106 public static function iterator()
107 {
108 return new XOrgDBIterator(XDB::_prepare(func_get_args()));
109 }
110
111 public static function iterRow()
112 {
113 return new XOrgDBIterator(XDB::_prepare(func_get_args()), MYSQL_NUM);
114 }
115
116 public static function insertId()
117 {
118 return mysqli_insert_id(XDB::$connec);
119 }
120
121 public static function _db_escape($var)
122 {
123 switch (gettype($var)) {
124 case 'boolean':
125 return $var ? 1 : 0;
126
127 case 'integer':
128 case 'double':
129 case 'float':
130 return $var;
131
132 case 'string':
133 return "'".addslashes($var)."'";
134
135 case 'NULL':
136 return 'NULL';
137
138 case 'object':
139 case 'array':
140 return "'".addslashes(serialize($var))."'";
141
142 default:
143 die(var_export($var, true).' is not a valid for a database entry');
144 }
145 }
146
147 public static function trace_format(&$page, $template = 'skin/common.database-debug.tpl') {
148 $page->assign('trace_data', @$GLOBALS['XDB::trace_data']);
149 $page->assign('db_error', @$GLOBALS['XDB::error']);
150 return $page->fetch($template);
151 }
152 }
153
154 class XOrgDBResult
155 {
156
157 var $_res;
158
159 function XOrgDBResult($query)
160 {
161 $this->_res = XDB::_query($query);
162 }
163
164 function free()
165 {
166 mysqli_free_result($this->_res);
167 unset($this);
168 }
169
170 function _fetchRow()
171 {
172 return mysqli_fetch_row($this->_res);
173 }
174
175 function _fetchAssoc()
176 {
177 return mysqli_fetch_assoc($this->_res);
178 }
179
180 function fetchAllRow()
181 {
182 $result = Array();
183 while ($result[] = mysqli_fetch_row($this->_res)) { }
184 array_pop($result);
185 $this->free();
186 return $result;
187 }
188
189 function fetchAllAssoc()
190 {
191 $result = Array();
192 while ($result[] = mysqli_fetch_assoc($this->_res)) { }
193 array_pop($result);
194 $this->free();
195 return $result;
196 }
197
198 function fetchOneAssoc()
199 {
200 $tmp = $this->_fetchAssoc();
201 $this->free();
202 return $tmp;
203 }
204
205 function fetchOneRow()
206 {
207 $tmp = $this->_fetchRow();
208 $this->free();
209 return $tmp;
210 }
211
212 function fetchOneCell()
213 {
214 $tmp = $this->_fetchRow();
215 $this->free();
216 return $tmp[0];
217 }
218
219 function fetchColumn($key = 0)
220 {
221 $res = Array();
222 if (is_numeric($key)) {
223 while($tmp = $this->_fetchRow()) {
224 $res[] = $tmp[$key];
225 }
226 } else {
227 while($tmp = $this->_fetchAssoc()) {
228 $res[] = $tmp[$key];
229 }
230 }
231 $this->free();
232 return $res;
233 }
234
235 function numRows()
236 {
237 return mysqli_num_rows($this->_res);
238 }
239 }
240
241 class XOrgDBIterator
242 {
243 private $_result;
244 private $_pos;
245 private $_total;
246 private $_mode = MYSQL_ASSOC;
247
248 function __construct($query, $mode = MYSQL_ASSOC)
249 {
250 $this->_result = new XOrgDBResult($query);
251 $this->_pos = 0;
252 $this->_total = $this->_result->numRows();
253 $this->_mode = $mode;
254 }
255
256 function next()
257 {
258 $this->_pos ++;
259 if ($this->_pos > $this->_total) {
260 $this->_result->free();
261 unset($this);
262 return null;
263 }
264 return $this->_mode != MYSQL_ASSOC ? $this->_result->_fetchRow() : $this->_result->_fetchAssoc();
265 }
266
267 function first()
268 {
269 return $this->_pos == 1;
270 }
271
272 function last()
273 {
274 return $this->_last == $this->_total;
275 }
276
277 function total()
278 {
279 return $this->_total;
280 }
281 }
282
283 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
284 ?>