|
1 <?php |
|
2 |
|
3 /* |
|
4 * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between |
|
5 * Version 1.0 (Banshee) |
|
6 * Copyright (C) 2006-2007 Dan Fuhry |
|
7 * |
|
8 * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License |
|
9 * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |
|
10 * |
|
11 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied |
|
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. |
|
13 */ |
|
14 |
|
15 function getConfig($n) { |
|
16 global $enano_config; |
|
17 if(isset($enano_config[$n])) return $enano_config[$n]; |
|
18 else return false; |
|
19 } |
|
20 |
|
21 function setConfig($n, $v) { |
|
22 global $enano_config, $db; |
|
23 $enano_config[$n] = $v; |
|
24 $v = $db->escape($v); |
|
25 $e=$db->sql_query('DELETE FROM '.table_prefix.'config WHERE config_name=\''.$n.'\';'); |
|
26 if(!$e) $db->_die('Error during generic setConfig() call row deletion.'); |
|
27 $e=$db->sql_query('INSERT INTO '.table_prefix.'config(config_name, config_value) VALUES(\''.$n.'\', \''.$v.'\')'); |
|
28 if(!$e) $db->_die('Error during generic setConfig() call row insertion.'); |
|
29 } |
|
30 |
|
31 function makeUrl($t, $query = false, $escape = false) |
|
32 { |
|
33 global $db, $session, $paths, $template, $plugins; // Common objects |
|
34 $flags = ''; |
|
35 $sep = urlSeparator; |
|
36 if(isset($_GET['printable'])) { $flags .= $sep.'printable'; $sep = '&'; } |
|
37 if(isset($_GET['theme'])) { $flags .= $sep.'theme='.$session->theme; $sep = '&'; } |
|
38 if(isset($_GET['style'])) { $flags .= $sep.'style='.$session->style; $sep = '&'; } |
|
39 $url = $session->append_sid(contentPath.$t.$flags); |
|
40 if($query) |
|
41 { |
|
42 $sep = strstr($url, '?') ? '&' : '?'; |
|
43 $url = $url . $sep . $query; |
|
44 } |
|
45 return ($escape) ? htmlspecialchars($url) : $url; |
|
46 } |
|
47 |
|
48 function makeUrlNS($n, $t, $query = false, $escape = false) |
|
49 { |
|
50 global $db, $session, $paths, $template, $plugins; // Common objects |
|
51 $flags = ''; |
|
52 if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator; |
|
53 else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?'; |
|
54 if(isset($_GET['printable'])) { $flags .= $sep.'printable'; $sep = '&'; } |
|
55 if(isset($_GET['theme'])) { $flags .= $sep.'theme='.$session->theme; $sep = '&'; } |
|
56 if(isset($_GET['style'])) { $flags .= $sep.'style='.$session->style; $sep = '&'; } |
|
57 |
|
58 if(defined('ENANO_BASE_CLASSES_INITIALIZED')) |
|
59 { |
|
60 $url = contentPath.$paths->nslist[$n].$t.$flags; |
|
61 } |
|
62 else |
|
63 { |
|
64 $url = contentPath.$n.':'.$t.$flags; |
|
65 } |
|
66 |
|
67 if($query) |
|
68 { |
|
69 if(strstr($url, '?')) $sep = '&'; |
|
70 else $sep = '?'; |
|
71 $url = $url . $sep . $query . $flags; |
|
72 } |
|
73 |
|
74 if(defined('ENANO_BASE_CLASSES_INITIALIZED')) |
|
75 { |
|
76 $url = $session->append_sid($url); |
|
77 } |
|
78 |
|
79 return ($escape) ? htmlspecialchars($url) : $url; |
|
80 } |
|
81 |
|
82 function makeUrlComplete($n, $t, $query = false, $escape = false) |
|
83 { |
|
84 global $db, $session, $paths, $template, $plugins; // Common objects |
|
85 $flags = ''; |
|
86 if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator; |
|
87 else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?'; |
|
88 if(isset($_GET['printable'])) { $flags .= $sep.'printable'; $sep = '&'; } |
|
89 if(isset($_GET['theme'])) { $flags .= $sep.'theme='.$session->theme; $sep = '&'; } |
|
90 if(isset($_GET['style'])) { $flags .= $sep.'style='.$session->style; $sep = '&'; } |
|
91 if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $url = $session->append_sid(contentPath.$paths->nslist[$n].$t.$flags); |
|
92 else $url = contentPath.$n.':'.$t.$flags; |
|
93 if($query) |
|
94 { |
|
95 if(strstr($url, '?')) $sep = '&'; |
|
96 else $sep = '?'; |
|
97 $url = $url . $sep . $query . $flags; |
|
98 } |
|
99 $baseprot = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://' . $_SERVER['HTTP_HOST']; |
|
100 $url = $baseprot . $url; |
|
101 return ($escape) ? htmlspecialchars($url) : $url; |
|
102 } |
|
103 |
|
104 /** |
|
105 * Redirect the user to the specified URL. |
|
106 * @param string $url The URL, either relative or absolute. |
|
107 * @param string $title The title of the message |
|
108 * @param string $message A short message to show to the user |
|
109 * @param string $timeout Timeout, in seconds, to delay the redirect. Defaults to 3. |
|
110 */ |
|
111 |
|
112 function redirect($url, $title = 'Redirecting...', $message = 'Please wait while you are redirected.', $timeout = 3) |
|
113 { |
|
114 global $db, $session, $paths, $template, $plugins; // Common objects |
|
115 |
|
116 if ( $timeout == 0 ) |
|
117 { |
|
118 header('Location: ' . $url); |
|
119 header('HTTP/1.1 307 Temporary Redirect'); |
|
120 } |
|
121 |
|
122 $template->add_header('<meta http-equiv="refresh" content="' . $timeout . '; url=' . str_replace('"', '\\"', $url) . '" />'); |
|
123 $template->add_header('<script type="text/javascript"> |
|
124 function __r() { |
|
125 // FUNCTION AUTOMATICALLY GENERATED |
|
126 window.location="' . str_replace('"', '\\"', $url) . '"; |
|
127 } |
|
128 setTimeout(\'__r();\', ' . $timeout . '000); |
|
129 </script> |
|
130 '); |
|
131 |
|
132 $template->tpl_strings['PAGE_NAME'] = $title; |
|
133 $template->header(true); |
|
134 echo '<p>' . $message . '</p><p>If you are not redirected within ' . ( $timeout + 1 ) . ' seconds, <a href="' . str_replace('"', '\\"', $url) . '">please click here</a>.</p>'; |
|
135 $template->footer(true); |
|
136 |
|
137 $db->close(); |
|
138 exit(0); |
|
139 |
|
140 } |
|
141 |
|
142 // Removed wikiFormat() from here, replaced with RenderMan::render |
|
143 |
|
144 function isPage($p) { |
|
145 global $db, $session, $paths, $template, $plugins; // Common objects |
|
146 if(isset($paths->pages[$p])) return true; |
|
147 $d = RenderMan::strToPageID($p); |
|
148 if($d[1] != 'Special' && $d[1] != 'Template' && $d[1] != 'Admin') return false; |
|
149 $a = explode('/', $p); |
|
150 if(isset($paths->pages[$a[0]])) return true; |
|
151 else return false; |
|
152 } |
|
153 |
|
154 function arrayItemUp($arr, $keyname) { |
|
155 $keylist = array_keys($arr); |
|
156 $keyflop = array_flip($keylist); |
|
157 $idx = $keyflop[$keyname]; |
|
158 $idxm = $idx - 1; |
|
159 $temp = $arr[$keylist[$idxm]]; |
|
160 if($arr[$keylist[0]] == $arr[$keyname]) return $arr; |
|
161 $arr[$keylist[$idxm]] = $arr[$keylist[$idx]]; |
|
162 $arr[$keylist[$idx]] = $temp; |
|
163 return $arr; |
|
164 } |
|
165 |
|
166 function arrayItemDown($arr, $keyname) { |
|
167 $keylist = array_keys($arr); |
|
168 $keyflop = array_flip($keylist); |
|
169 $idx = $keyflop[$keyname]; |
|
170 $idxm = $idx + 1; |
|
171 $temp = $arr[$keylist[$idxm]]; |
|
172 $sz = sizeof($arr); $sz--; |
|
173 if($arr[$keylist[$sz]] == $arr[$keyname]) return $arr; |
|
174 $arr[$keylist[$idxm]] = $arr[$keylist[$idx]]; |
|
175 $arr[$keylist[$idx]] = $temp; |
|
176 return $arr; |
|
177 } |
|
178 |
|
179 function arrayItemTop($arr, $keyname) { |
|
180 $keylist = array_keys($arr); |
|
181 $keyflop = array_flip($keylist); |
|
182 $idx = $keyflop[$keyname]; |
|
183 while( $orig != $arr[$keylist[0]] ) { |
|
184 // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger |
|
185 if($idx < 0) return $arr; |
|
186 if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) { |
|
187 /* echo 'Infinite loop caught in arrayItemTop(<br /><pre>'; |
|
188 print_r($arr); |
|
189 echo '</pre><br />, '.$keyname.');<br /><br />EnanoCMS: Critical error during function call, exiting to prevent excessive server load.'; |
|
190 exit; */ |
|
191 return $arr; |
|
192 } |
|
193 $arr = arrayItemUp($arr, $keylist[$idx]); |
|
194 $idx--; |
|
195 } |
|
196 return $arr; |
|
197 } |
|
198 |
|
199 function arrayItemBottom($arr, $keyname) { |
|
200 $keylist = array_keys($arr); |
|
201 $keyflop = array_flip($keylist); |
|
202 $idx = $keyflop[$keyname]; |
|
203 $sz = sizeof($arr); $sz--; |
|
204 while( $orig != $arr[$keylist[$sz]] ) { |
|
205 // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger |
|
206 if($idx > $sz) return $arr; |
|
207 if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) { |
|
208 echo 'Infinite loop caught in arrayItemBottom(<br /><pre>'; |
|
209 print_r($arr); |
|
210 echo '</pre><br />, '.$keyname.');<br /><br />EnanoCMS: Critical error during function call, exiting to prevent excessive server load.'; |
|
211 exit; |
|
212 } |
|
213 $arr = arrayItemDown($arr, $keylist[$idx]); |
|
214 $idx++; |
|
215 } |
|
216 return $arr; |
|
217 } |
|
218 |
|
219 // Convert IP address to hex string |
|
220 // Input: 127.0.0.1 (string) |
|
221 // Output: 0x7f000001 (string) |
|
222 // Updated 12/8/06 to work with PHP4 and not use eval() (blech) |
|
223 function ip2hex($ip) { |
|
224 if ( preg_match('/^([0-9a-f:]+)$/', $ip) ) |
|
225 { |
|
226 // this is an ipv6 address |
|
227 return str_replace(':', '', $ip); |
|
228 } |
|
229 $nums = explode('.', $ip); |
|
230 if(sizeof($nums) != 4) return false; |
|
231 $str = '0x'; |
|
232 foreach($nums as $n) |
|
233 { |
|
234 $str .= (string)dechex($n); |
|
235 } |
|
236 return $str; |
|
237 } |
|
238 |
|
239 // Convert DWord to IP address |
|
240 // Input: 0x7f000001 |
|
241 // Output: 127.0.0.1 |
|
242 // Updated 12/8/06 to work with PHP4 and not use eval() (blech) |
|
243 function hex2ip($in) { |
|
244 if(substr($in, 0, 2) == '0x') $ip = substr($in, 2, 8); |
|
245 else $ip = substr($in, 0, 8); |
|
246 $octets = enano_str_split($ip, 2); |
|
247 $str = ''; |
|
248 $newoct = Array(); |
|
249 foreach($octets as $o) |
|
250 { |
|
251 $o = (int)hexdec($o); |
|
252 $newoct[] = $o; |
|
253 } |
|
254 return implode('.', $newoct); |
|
255 } |
|
256 |
|
257 // Function strip_php moved to RenderMan class |
|
258 |
|
259 function die_semicritical($t, $p) |
|
260 { |
|
261 global $db, $session, $paths, $template, $plugins; // Common objects |
|
262 $db->close(); |
|
263 |
|
264 if ( ob_get_status() ) |
|
265 ob_end_clean(); |
|
266 |
|
267 dc_here('functions: <span style="color: red">calling die_semicritical</span>'); |
|
268 |
|
269 $tpl = new template_nodb(); |
|
270 $tpl->load_theme('oxygen', 'bleu'); |
|
271 $tpl->tpl_strings['SITE_NAME'] = getConfig('site_name'); |
|
272 $tpl->tpl_strings['SITE_DESC'] = getConfig('site_desc'); |
|
273 $tpl->tpl_strings['COPYRIGHT'] = getConfig('copyright_notice'); |
|
274 $tpl->tpl_strings['PAGE_NAME'] = $t; |
|
275 $tpl->header(); |
|
276 echo $p; |
|
277 $tpl->footer(); |
|
278 |
|
279 exit; |
|
280 } |
|
281 |
|
282 function die_friendly($t, $p) |
|
283 { |
|
284 global $db, $session, $paths, $template, $plugins; // Common objects |
|
285 |
|
286 if ( ob_get_status() ) |
|
287 ob_end_clean(); |
|
288 |
|
289 dc_here('functions: <span style="color: red">calling die_friendly</span>'); |
|
290 $paths->cpage['name'] = $t; |
|
291 $template->tpl_strings['PAGE_NAME'] = $t; |
|
292 $template->header(); |
|
293 echo $p; |
|
294 $template->footer(); |
|
295 $db->close(); |
|
296 |
|
297 exit; |
|
298 } |
|
299 |
|
300 function grinding_halt($t, $p) |
|
301 { |
|
302 global $db, $session, $paths, $template, $plugins; // Common objects |
|
303 |
|
304 $db->close(); |
|
305 |
|
306 if ( ob_get_status() ) |
|
307 ob_end_clean(); |
|
308 |
|
309 dc_here('functions: <span style="color: red">calling grinding_halt</span>'); |
|
310 $tpl = new template_nodb(); |
|
311 $tpl->load_theme('oxygen', 'bleu'); |
|
312 $tpl->tpl_strings['SITE_NAME'] = 'Critical error'; |
|
313 $tpl->tpl_strings['SITE_DESC'] = 'This website is experiencing a serious error and cannot load.'; |
|
314 $tpl->tpl_strings['COPYRIGHT'] = 'Unable to retrieve copyright information'; |
|
315 $tpl->tpl_strings['PAGE_NAME'] = $t; |
|
316 $tpl->header(); |
|
317 echo $p; |
|
318 $tpl->footer(); |
|
319 exit; |
|
320 } |
|
321 |
|
322 function show_category_info() { |
|
323 global $db, $session, $paths, $template, $plugins; // Common objects |
|
324 dc_here('functions: showing category info'); |
|
325 if($template->no_headers && !strpos($_SERVER['REQUEST_URI'], 'ajax.php')) return ''; |
|
326 if($paths->namespace=='Category') |
|
327 { |
|
328 $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'categories WHERE category_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\'Category\' ORDER BY page_id;'); |
|
329 if(!$q) $db->_die('The category information could not be selected.'); |
|
330 $ticker = -1; |
|
331 echo '<h3>Subcategories</h3>'; |
|
332 if($db->numrows() < 1) echo '<p>There are no subcategories in this category.</p>'; |
|
333 echo '<table border="0" cellspacing="1" cellpadding="4">'; |
|
334 while($row = $db->fetchrow()) |
|
335 { |
|
336 $ticker++;if($ticker==3) $ticker=0; |
|
337 if($ticker==0) echo '<tr>'; |
|
338 echo '<td style="width: 200px;"><a href="'.makeUrlNS($row['namespace'], $row['page_id']).'">'.$paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'].'</a></td>'; |
|
339 if($ticker==2) echo '</tr>'; |
|
340 } |
|
341 $db->free_result(); |
|
342 if($ticker) echo '</tr>'; |
|
343 echo '</table>'; |
|
344 |
|
345 $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'categories WHERE category_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace!=\'Category\' ORDER BY page_id;'); |
|
346 if(!$q) $db->_die('The category information could not be selected.'); |
|
347 $ticker = -1; |
|
348 echo '<h3>Pages</h3>'; |
|
349 if($db->numrows() < 1) echo '<p>There are no pages in this category.</p>'; |
|
350 echo '<table border="0" cellspacing="1" cellpadding="4">'; |
|
351 while($row = $db->fetchrow()) |
|
352 { |
|
353 $ticker++;if($ticker==3) $ticker=0; |
|
354 if($ticker==0) echo '<tr>'; |
|
355 echo '<td style="width: 200px;"><a href="'.makeUrlNS($row['namespace'], $row['page_id']).'">'.$paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'].'</a></td>'; |
|
356 if($ticker==2) echo '</tr>'; |
|
357 } |
|
358 $db->free_result(); |
|
359 if($ticker) echo '</tr>'; |
|
360 echo '</table><br /><br />'; |
|
361 } |
|
362 $q = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\''); |
|
363 if(!$q) $db->_die('The error seems to have occurred during selection of category data.'); |
|
364 if($db->numrows() > 0) { |
|
365 echo '<div class="mdg-comment" style="margin-left: 0;">Categories: '; |
|
366 $i=0; |
|
367 while($r = $db->fetchrow()) |
|
368 { |
|
369 if($i>0) echo ', '; |
|
370 $i++; |
|
371 echo '<a href="'.makeUrlNS('Category', $r['category_id']).'">'.$paths->pages[$paths->nslist['Category'].$r['category_id']]['name'].'</a>'; |
|
372 } |
|
373 if( ( $paths->wiki_mode && !$paths->page_protected ) || ( $session->get_permissions('edit_cat') && $session->get_permissions('even_when_protected') ) ) echo ' [ <a href="'.makeUrl($paths->page, 'do=catedit', true).'" onclick="ajaxCatEdit(); return false;">edit categorization</a> ]</div>'; |
|
374 } else { |
|
375 echo '<div class="mdg-comment" style="margin-left: 0;">Categories: '; |
|
376 echo '(Uncategorized)'; |
|
377 if( ( $paths->wiki_mode && !$paths->page_protected ) || ( $session->get_permissions('edit_cat') && $session->get_permissions('even_when_protected') ) ) echo ' [ <a href="'.makeUrl($paths->page, 'do=catedit', true).'" onclick="ajaxCatEdit(); return false;">edit categorization</a> ]</div>'; |
|
378 else echo '</div>'; |
|
379 } |
|
380 $db->free_result(); |
|
381 } |
|
382 |
|
383 function show_file_info() |
|
384 { |
|
385 global $db, $session, $paths, $template, $plugins; // Common objects |
|
386 if($paths->namespace != 'File') return null; // Prevent unnecessary work |
|
387 $selfn = $paths->cpage['urlname_nons']; // substr($paths->page, strlen($paths->nslist['File']), strlen($paths->cpage)); |
|
388 if(substr($paths->cpage['name'], 0, strlen($paths->nslist['File']))==$paths->nslist['File']) $selfn = substr($paths->cpage['urlname_nons'], strlen($paths->nslist['File']), strlen($paths->cpage['urlname_nons'])); |
|
389 $q = $db->sql_query('SELECT mimetype,time_id,size FROM '.table_prefix.'files WHERE page_id=\''.$selfn.'\' ORDER BY time_id DESC;'); |
|
390 if(!$q) $db->_die('The file type could not be fetched.'); |
|
391 if($db->numrows() < 1) { echo '<div class="mdg-comment" style="margin-left: 0;"><h3>Uploaded file</h3><p>There are no files uploaded with this name yet. <a href="'.makeUrlNS('Special', 'UploadFile/'.$paths->cpage['urlname_nons']).'">Upload a file...</a></p></div><br />'; return; } |
|
392 $r = $db->fetchrow(); |
|
393 $mimetype = $r['mimetype']; |
|
394 $datestring = date('F d, Y h:i a', (int)$r['time_id']); |
|
395 echo '<div class="mdg-comment" style="margin-left: 0;"><p><h3>Uploaded file</h3></p><p>Type: '.$r['mimetype'].'<br />Size: '; |
|
396 $fs = $r['size']; |
|
397 echo $fs.' bytes'; |
|
398 $fs = (int)$fs; |
|
399 if($fs >= 1048576) |
|
400 { |
|
401 $fs = round($fs / 1048576, 1); |
|
402 echo ' ('.$fs.' MB)'; |
|
403 } elseif($fs >= 1024) { |
|
404 $fs = round($fs / 1024, 1); |
|
405 echo ' ('.$fs.' KB)'; |
|
406 } |
|
407 echo '<br />Uploaded: '.$datestring.'</p>'; |
|
408 if(substr($mimetype, 0, 6)!='image/' && ( substr($mimetype, 0, 5) != 'text/' || $mimetype == 'text/html' || $mimetype == 'text/javascript' )) |
|
409 { |
|
410 echo '<div class="warning-box">This file type may contain viruses or other code that could harm your computer. You should exercise caution if you download it.</div>'; |
|
411 } |
|
412 if(substr($mimetype, 0, 6)=='image/') |
|
413 { |
|
414 echo '<p><a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn).'"><img style="border: 0;" alt="'.$paths->page.'" src="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.htmlspecialchars(urlSeparator).'preview').'" /></a></p>'; |
|
415 } |
|
416 echo '<p><a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.'/'.$r['time_id'].htmlspecialchars(urlSeparator).'download').'">Download this file</a>'; |
|
417 if(!$paths->page_protected && ( $paths->wiki_mode || $session->get_permissions('upload_new_version') )) |
|
418 { |
|
419 echo ' | <a href="'.makeUrlNS('Special', 'UploadFile'.'/'.$selfn).'">Upload new version</a>'; |
|
420 } |
|
421 echo '</p>'; |
|
422 if($db->numrows() > 1) |
|
423 { |
|
424 echo '<h3>File history</h3><p>'; |
|
425 while($r = $db->fetchrow()) |
|
426 { |
|
427 echo '(<a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.'/'.$r['time_id'].htmlspecialchars(urlSeparator).'download').'">this ver</a>) '; |
|
428 if($session->get_permissions('history_rollback')) |
|
429 echo ' (<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">revert</a>) '; |
|
430 $mimetype = $r['mimetype']; |
|
431 $datestring = date('F d, Y h:i a', (int)$r['time_id']); |
|
432 echo $datestring.': '.$r['mimetype'].', '; |
|
433 $fs = $r['size']; |
|
434 $fs = (int)$fs; |
|
435 if($fs >= 1048576) |
|
436 { |
|
437 $fs = round($fs / 1048576, 1); |
|
438 echo ' '.$fs.' MB'; |
|
439 } elseif($fs >= 1024) { |
|
440 $fs = round($fs / 1024, 1); |
|
441 echo ' '.$fs.' KB'; |
|
442 } else { |
|
443 echo ' '.$fs.' bytes'; |
|
444 } |
|
445 echo '<br />'; |
|
446 } |
|
447 echo '</p>'; |
|
448 } |
|
449 $db->free_result(); |
|
450 echo '</div><br />'; |
|
451 } |
|
452 |
|
453 function display_page_headers() |
|
454 { |
|
455 global $db, $session, $paths, $template, $plugins; // Common objects |
|
456 if($session->get_permissions('vote_reset') && $paths->cpage['delvotes'] > 0) |
|
457 { |
|
458 $hr = implode(', ', explode('|', $paths->cpage['delvote_ips'])); |
|
459 $is = 'is'; |
|
460 $s = ''; |
|
461 $s2 = 's'; |
|
462 if ( $paths->cpage['delvotes'] > 1) |
|
463 { |
|
464 $is = 'are'; |
|
465 $s = 's'; |
|
466 $s2 = ''; |
|
467 } |
|
468 echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;" id="mdgDeleteVoteNoticeBox"> |
|
469 <b>Notice:</b> There '.$is.' '.$paths->cpage['delvotes'].' user'.$s.' that think'.$s2.' this page should be deleted.<br /> |
|
470 <b>Users that voted:</b> ' . $hr . '<br /> |
|
471 <a href="'.makeUrl($paths->page, 'do=deletepage').'" onclick="ajaxDeletePage(); return false;">Delete page</a> | <a href="'.makeUrl($paths->page, 'do=resetvotes').'" onclick="ajaxResetDelVotes(); return false;">Reset votes</a> |
|
472 </div>'; |
|
473 } |
|
474 } |
|
475 |
|
476 function display_page_footers() |
|
477 { |
|
478 global $db, $session, $paths, $template, $plugins; // Common objects |
|
479 if(isset($_GET['nofooters'])) return; |
|
480 $code = $plugins->setHook('send_page_footers'); |
|
481 foreach ( $code as $cmd ) |
|
482 { |
|
483 eval($cmd); |
|
484 } |
|
485 show_file_info(); |
|
486 show_category_info(); |
|
487 } |
|
488 |
|
489 function password_prompt($id = false) |
|
490 { |
|
491 global $db, $session, $paths, $template, $plugins; // Common objects |
|
492 if(!$id) $id = $paths->page; |
|
493 if(isset($paths->pages[$id]['password']) && strlen($paths->pages[$id]['password']) == 40 && !isset($_REQUEST['pagepass'])) |
|
494 { |
|
495 die_friendly('Password required', '<p>You must supply a password to access this page.</p><form action="'.makeUrl($paths->pages[$id]['urlname']).'" method="post"><p>Password: <input name="pagepass" type="password" /></p><p><input type="submit" value="Submit" /></p>'); |
|
496 } elseif(isset($_REQUEST['pagepass'])) { |
|
497 $p = (preg_match('#^([a-f0-9]*){40}$#', $_REQUEST['pagepass'])) ? $_REQUEST['pagepass'] : sha1($_REQUEST['pagepass']); |
|
498 if($p != $paths->pages[$id]['password']) die_friendly('Password required', '<p style="color: red;">The password you entered is incorrect.</p><form action="'.makeUrl($paths->page).'" method="post"><p>Password: <input name="pagepass" type="password" /></p><p><input type="submit" value="Submit" /></p>'); |
|
499 } |
|
500 } |
|
501 |
|
502 function str_hex($string){ |
|
503 $hex=''; |
|
504 for ($i=0; $i < strlen($string); $i++){ |
|
505 $hex .= ' '.dechex(ord($string[$i])); |
|
506 } |
|
507 return substr($hex, 1, strlen($hex)); |
|
508 } |
|
509 |
|
510 // Function pulled from phpBB's smtp.php |
|
511 function smtp_get_response($socket, $response, $line = __LINE__) |
|
512 { |
|
513 $server_response = ''; |
|
514 while (substr($server_response, 3, 1) != ' ') |
|
515 { |
|
516 if (!($server_response = fgets($socket, 256))) |
|
517 { |
|
518 die_friendly('SMTP Error', "<p>Couldn't get mail server response codes</p>"); |
|
519 } |
|
520 } |
|
521 |
|
522 if (!(substr($server_response, 0, 3) == $response)) |
|
523 { |
|
524 die_friendly('SMTP Error', "<p>Ran into problems sending mail. Response: $server_response</p>"); |
|
525 } |
|
526 } |
|
527 |
|
528 function smtp_send_email($to, $subject, $message, $from) |
|
529 { |
|
530 return smtp_send_email_core($to, $subject, $message, "From: <$from>\n"); |
|
531 } |
|
532 |
|
533 // Replacement or substitute for PHP's mail command |
|
534 // Ported from phpBB - copyright (C) phpBB group, GPL. |
|
535 function smtp_send_email_core($mail_to, $subject, $message, $headers = '') |
|
536 { |
|
537 global $board_config; |
|
538 |
|
539 // Fix any bare linefeeds in the message to make it RFC821 Compliant. |
|
540 $message = preg_replace("#(?<!\r)\n#si", "\r\n", $message); |
|
541 |
|
542 if ($headers != '') |
|
543 { |
|
544 if (is_array($headers)) |
|
545 { |
|
546 if (sizeof($headers) > 1) |
|
547 { |
|
548 $headers = join("\n", $headers); |
|
549 } |
|
550 else |
|
551 { |
|
552 $headers = $headers[0]; |
|
553 } |
|
554 } |
|
555 $headers = chop($headers); |
|
556 |
|
557 // Make sure there are no bare linefeeds in the headers |
|
558 $headers = preg_replace('#(?<!\r)\n#si', "\r\n", $headers); |
|
559 |
|
560 // Ok this is rather confusing all things considered, |
|
561 // but we have to grab bcc and cc headers and treat them differently |
|
562 // Something we really didn't take into consideration originally |
|
563 $header_array = explode("\r\n", $headers); |
|
564 @reset($header_array); |
|
565 |
|
566 $headers = ''; |
|
567 while(list(, $header) = each($header_array)) |
|
568 { |
|
569 if (preg_match('#^cc:#si', $header)) |
|
570 { |
|
571 $cc = preg_replace('#^cc:(.*)#si', '\1', $header); |
|
572 } |
|
573 else if (preg_match('#^bcc:#si', $header)) |
|
574 { |
|
575 $bcc = preg_replace('#^bcc:(.*)#si', '\1', $header); |
|
576 $header = ''; |
|
577 } |
|
578 $headers .= ($header != '') ? $header . "\r\n" : ''; |
|
579 } |
|
580 |
|
581 $headers = chop($headers); |
|
582 $cc = explode(', ', $cc); |
|
583 $bcc = explode(', ', $bcc); |
|
584 } |
|
585 |
|
586 if (trim($subject) == '') |
|
587 { |
|
588 die_friendly(GENERAL_ERROR, "No email Subject specified"); |
|
589 } |
|
590 |
|
591 if (trim($message) == '') |
|
592 { |
|
593 die_friendly(GENERAL_ERROR, "Email message was blank"); |
|
594 } |
|
595 |
|
596 // setup SMTP |
|
597 $host = getConfig('smtp_server'); |
|
598 if ( empty($host) ) |
|
599 return 'No smtp_host in config'; |
|
600 if ( strstr($host, ':' ) ) |
|
601 { |
|
602 $n = explode(':', $host); |
|
603 $smtp_host = $n[0]; |
|
604 $port = intval($n[1]); |
|
605 } |
|
606 else |
|
607 { |
|
608 $smtp_host = $host; |
|
609 $port = 25; |
|
610 } |
|
611 |
|
612 $smtp_user = getConfig('smtp_user'); |
|
613 $smtp_pass = getConfig('smtp_password'); |
|
614 |
|
615 // Ok we have error checked as much as we can to this point let's get on |
|
616 // it already. |
|
617 if( !$socket = @fsockopen($smtp_host, $port, $errno, $errstr, 20) ) |
|
618 { |
|
619 die_friendly(GENERAL_ERROR, "Could not connect to smtp host : $errno : $errstr"); |
|
620 } |
|
621 |
|
622 // Wait for reply |
|
623 smtp_get_response($socket, "220", __LINE__); |
|
624 |
|
625 // Do we want to use AUTH?, send RFC2554 EHLO, else send RFC821 HELO |
|
626 // This improved as provided by SirSir to accomodate |
|
627 if( !empty($smtp_user) && !empty($smtp_pass) ) |
|
628 { |
|
629 enano_fputs($socket, "EHLO " . $smtp_host . "\r\n"); |
|
630 smtp_get_response($socket, "250", __LINE__); |
|
631 |
|
632 enano_fputs($socket, "AUTH LOGIN\r\n"); |
|
633 smtp_get_response($socket, "334", __LINE__); |
|
634 |
|
635 enano_fputs($socket, base64_encode($smtp_user) . "\r\n"); |
|
636 smtp_get_response($socket, "334", __LINE__); |
|
637 |
|
638 enano_fputs($socket, base64_encode($smtp_pass) . "\r\n"); |
|
639 smtp_get_response($socket, "235", __LINE__); |
|
640 } |
|
641 else |
|
642 { |
|
643 enano_fputs($socket, "HELO " . $smtp_host . "\r\n"); |
|
644 smtp_get_response($socket, "250", __LINE__); |
|
645 } |
|
646 |
|
647 // From this point onward most server response codes should be 250 |
|
648 // Specify who the mail is from.... |
|
649 enano_fputs($socket, "MAIL FROM: <" . getConfig('contact_email') . ">\r\n"); |
|
650 smtp_get_response($socket, "250", __LINE__); |
|
651 |
|
652 // Specify each user to send to and build to header. |
|
653 $to_header = ''; |
|
654 |
|
655 // Add an additional bit of error checking to the To field. |
|
656 $mail_to = (trim($mail_to) == '') ? 'Undisclosed-recipients:;' : trim($mail_to); |
|
657 if (preg_match('#[^ ]+\@[^ ]+#', $mail_to)) |
|
658 { |
|
659 enano_fputs($socket, "RCPT TO: <$mail_to>\r\n"); |
|
660 smtp_get_response($socket, "250", __LINE__); |
|
661 } |
|
662 |
|
663 // Ok now do the CC and BCC fields... |
|
664 @reset($bcc); |
|
665 while(list(, $bcc_address) = each($bcc)) |
|
666 { |
|
667 // Add an additional bit of error checking to bcc header... |
|
668 $bcc_address = trim($bcc_address); |
|
669 if (preg_match('#[^ ]+\@[^ ]+#', $bcc_address)) |
|
670 { |
|
671 enano_fputs($socket, "RCPT TO: <$bcc_address>\r\n"); |
|
672 smtp_get_response($socket, "250", __LINE__); |
|
673 } |
|
674 } |
|
675 |
|
676 @reset($cc); |
|
677 while(list(, $cc_address) = each($cc)) |
|
678 { |
|
679 // Add an additional bit of error checking to cc header |
|
680 $cc_address = trim($cc_address); |
|
681 if (preg_match('#[^ ]+\@[^ ]+#', $cc_address)) |
|
682 { |
|
683 enano_fputs($socket, "RCPT TO: <$cc_address>\r\n"); |
|
684 smtp_get_response($socket, "250", __LINE__); |
|
685 } |
|
686 } |
|
687 |
|
688 // Ok now we tell the server we are ready to start sending data |
|
689 enano_fputs($socket, "DATA\r\n"); |
|
690 |
|
691 // This is the last response code we look for until the end of the message. |
|
692 smtp_get_response($socket, "354", __LINE__); |
|
693 |
|
694 // Send the Subject Line... |
|
695 enano_fputs($socket, "Subject: $subject\r\n"); |
|
696 |
|
697 // Now the To Header. |
|
698 enano_fputs($socket, "To: $mail_to\r\n"); |
|
699 |
|
700 // Now any custom headers.... |
|
701 enano_fputs($socket, "$headers\r\n\r\n"); |
|
702 |
|
703 // Ok now we are ready for the message... |
|
704 enano_fputs($socket, "$message\r\n"); |
|
705 |
|
706 // Ok the all the ingredients are mixed in let's cook this puppy... |
|
707 enano_fputs($socket, ".\r\n"); |
|
708 smtp_get_response($socket, "250", __LINE__); |
|
709 |
|
710 // Now tell the server we are done and close the socket... |
|
711 enano_fputs($socket, "QUIT\r\n"); |
|
712 fclose($socket); |
|
713 |
|
714 return TRUE; |
|
715 } |
|
716 |
|
717 /** |
|
718 * Tell which version of Enano we're running. |
|
719 * @param bool $long if true, uses English version names (e.g. alpha, beta, release candidate). If false (default) uses abbreviations (1.0a1, 1.0b3, 1.0RC2, etc.) |
|
720 * @return string |
|
721 */ |
|
722 |
|
723 function enano_version($long = false, $no_nightly = false) |
|
724 { |
|
725 $r = getConfig('enano_version'); |
|
726 $rc = ( $long ) ? ' release candidate ' : 'RC'; |
|
727 $b = ( $long ) ? ' beta ' : 'b'; |
|
728 $a = ( $long ) ? ' alpha ' : 'a'; |
|
729 if($v = getConfig('enano_rc_version')) $r .= $rc.$v; |
|
730 if($v = getConfig('enano_beta_version')) $r .= $b.$v; |
|
731 if($v = getConfig('enano_alpha_version')) $r .= $a.$v; |
|
732 if ( defined('ENANO_NIGHTLY') && !$no_nightly ) |
|
733 { |
|
734 $nightlytag = ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR; |
|
735 $nightlylong = ' nightly; build date: ' . ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR; |
|
736 $r = ( $long ) ? $r . $nightlylong : $r . '-nightly-' . $nightlytag; |
|
737 } |
|
738 return $r; |
|
739 } |
|
740 |
|
741 function _dualurlenc($t) { |
|
742 return rawurlencode(rawurlencode($t)); |
|
743 } |
|
744 |
|
745 function _die($t) { |
|
746 $_ob = 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\'' . rawurlencode('' . $t . '') . '\')'; |
|
747 die($_ob); |
|
748 } |
|
749 |
|
750 function jsdie($text) { |
|
751 global $db, $session, $paths, $template, $plugins; // Common objects |
|
752 $text = rawurlencode($text . "\n\nSQL Backtrace:\n" . $db->sql_backtrace()); |
|
753 echo 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.$text.'\');'; |
|
754 } |
|
755 |
|
756 // HTML sanitizing function - written by Kallahar |
|
757 // Original function at: http://quickwired.com/kallahar/smallprojects/php_xss_filter_function.php |
|
758 |
|
759 // UNUSED - todo: remove this in gold or put it to use |
|
760 |
|
761 function RemoveXSS($val) { |
|
762 // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed |
|
763 // this prevents some character re-spacing such as <java\0script> |
|
764 // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs |
|
765 $val = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $val); |
|
766 |
|
767 // straight replacements, the user should never need these since they're normal characters |
|
768 // this prevents like <IMG SRC=@avascript:alert('XSS')> |
|
769 $search = 'abcdefghijklmnopqrstuvwxyz'; |
|
770 $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; |
|
771 $search .= '1234567890!@#$%^&*()'; |
|
772 $search .= '~`";:?+/={}[]-_|\'\\'; |
|
773 for ($i = 0; $i < strlen($search); $i++) { |
|
774 // ;? matches the ;, which is optional |
|
775 // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars |
|
776 |
|
777 // @ @ search for the hex values |
|
778 $val = preg_replace('/(&#[x|X]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ; |
|
779 // @ @ 0{0,7} matches '0' zero to seven times |
|
780 $val = preg_replace('/(�{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ; |
|
781 } |
|
782 |
|
783 // now the only remaining whitespace attacks are \t, \n, and \r |
|
784 $ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base'); |
|
785 $ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload'); |
|
786 $ra = array_merge($ra1, $ra2); |
|
787 |
|
788 $found = true; // keep replacing as long as the previous round replaced something |
|
789 while ($found == true) { |
|
790 $val_before = $val; |
|
791 for ($i = 0; $i < sizeof($ra); $i++) { |
|
792 $pattern = '/'; |
|
793 for ($j = 0; $j < strlen($ra[$i]); $j++) { |
|
794 if ($j > 0) { |
|
795 $pattern .= '('; |
|
796 $pattern .= '(&#[x|X]0{0,8}([9][a][b]);?)?'; |
|
797 $pattern .= '|(�{0,8}([9][10][13]);?)?'; |
|
798 $pattern .= ')?'; |
|
799 } |
|
800 $pattern .= $ra[$i][$j]; |
|
801 } |
|
802 $pattern .= '/i'; |
|
803 $replacement = substr($ra[$i], 0, 2).'<b></b>'.substr($ra[$i], 2); // add in <> to nerf the tag |
|
804 $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags |
|
805 if ($val_before == $val) { |
|
806 // no replacements were made, so exit the loop |
|
807 $found = false; |
|
808 } |
|
809 } |
|
810 } |
|
811 return $val; |
|
812 } |
|
813 |
|
814 /** |
|
815 * Capitalizes the first letter of a string |
|
816 * @param $text string the text to be transformed |
|
817 * @return string |
|
818 */ |
|
819 |
|
820 function capitalize_first_letter($text) |
|
821 { |
|
822 return strtoupper(substr($text, 0, 1)) . substr($text, 1); |
|
823 } |
|
824 |
|
825 /** |
|
826 * Checks if a value in a bitfield is on or off |
|
827 * @param $bitfield int the bit-field value |
|
828 * @param $value int the value to switch off |
|
829 * @return bool |
|
830 */ |
|
831 |
|
832 function is_bit($bitfield, $value) |
|
833 { |
|
834 return ( $bitfield & $value ) ? true : false; |
|
835 } |
|
836 |
|
837 /** |
|
838 * Trims spaces/newlines from the beginning and end of a string |
|
839 * @param $text the text to process |
|
840 * @return string |
|
841 */ |
|
842 |
|
843 function trim_spaces($text) |
|
844 { |
|
845 $d = true; |
|
846 while($d) |
|
847 { |
|
848 $c = substr($text, 0, 1); |
|
849 $a = substr($text, strlen($text)-1, strlen($text)); |
|
850 if($c == "\n" || $c == "\r" || $c == "\t" || $c == ' ') $text = substr($text, 1, strlen($text)); |
|
851 elseif($a == "\n" || $a == "\r" || $a == "\t" || $a == ' ') $text = substr($text, 0, strlen($text)-1); |
|
852 else $d = false; |
|
853 } |
|
854 return $text; |
|
855 } |
|
856 |
|
857 /** |
|
858 * Enano-ese equivalent of str_split() which is only found in PHP5 |
|
859 * @param $text string the text to split |
|
860 * @param $inc int size of each block |
|
861 * @return array |
|
862 */ |
|
863 |
|
864 function enano_str_split($text, $inc = 1) |
|
865 { |
|
866 if($inc < 1) return false; |
|
867 if($inc >= strlen($text)) return Array($text); |
|
868 $len = ceil(strlen($text) / $inc); |
|
869 $ret = Array(); |
|
870 for($i=0;$i<strlen($text);$i=$i+$inc) |
|
871 { |
|
872 $ret[] = substr($text, $i, $inc); |
|
873 } |
|
874 return $ret; |
|
875 } |
|
876 |
|
877 /** |
|
878 * Converts a hexadecimal number to a binary string. |
|
879 * @param text string hexadecimal number |
|
880 * @return string |
|
881 */ |
|
882 function hex2bin($text) |
|
883 { |
|
884 $arr = enano_str_split($text, 2); |
|
885 $ret = ''; |
|
886 for ($i=0; $i<sizeof($arr); $i++) |
|
887 { |
|
888 $ret .= chr(hexdec($arr[$i])); |
|
889 } |
|
890 return $ret; |
|
891 } |
|
892 |
|
893 /** |
|
894 * Generates and/or prints a human-readable backtrace |
|
895 * @param bool $return - if true, this function returns a string, otherwise returns null |
|
896 * @return mixed |
|
897 */ |
|
898 |
|
899 function enano_debug_print_backtrace($return = false) |
|
900 { |
|
901 ob_start(); |
|
902 echo '<pre>'; |
|
903 debug_print_backtrace(); |
|
904 echo '</pre>'; |
|
905 $c = ob_get_contents(); |
|
906 ob_end_clean(); |
|
907 if($return) return $c; |
|
908 else echo $c; |
|
909 return null; |
|
910 } |
|
911 |
|
912 /** |
|
913 * Like rawurlencode(), but encodes all characters |
|
914 * @param string $text the text to encode |
|
915 * @param optional string $prefix text before each hex character |
|
916 * @param optional string $suffix text after each hex character |
|
917 * @return string |
|
918 */ |
|
919 |
|
920 function hexencode($text, $prefix = '%', $suffix = '') |
|
921 { |
|
922 $arr = enano_str_split($text); |
|
923 $r = ''; |
|
924 foreach($arr as $a) |
|
925 { |
|
926 $nibble = (string)dechex(ord($a)); |
|
927 if(strlen($nibble) == 1) $nibble = '0' . $nibble; |
|
928 $r .= $prefix . $nibble . $suffix; |
|
929 } |
|
930 return $r; |
|
931 } |
|
932 |
|
933 /** |
|
934 * Enano-ese equivalent of get_magic_quotes_gpc() |
|
935 * @return bool |
|
936 */ |
|
937 |
|
938 function enano_get_magic_quotes_gpc() |
|
939 { |
|
940 if(function_exists('get_magic_quotes_gpc')) |
|
941 { |
|
942 return ( get_magic_quotes_gpc() == 1 ); |
|
943 } |
|
944 else |
|
945 { |
|
946 return ( strtolower(@ini_get('magic_quotes_gpc')) == '1' ); |
|
947 } |
|
948 } |
|
949 |
|
950 /** |
|
951 * Recursive stripslashes() |
|
952 * @param array |
|
953 * @return array |
|
954 */ |
|
955 |
|
956 function stripslashes_recurse($arr) |
|
957 { |
|
958 foreach($arr as $k => $xxxx) |
|
959 { |
|
960 $val =& $arr[$k]; |
|
961 if(is_string($val)) |
|
962 $val = stripslashes($val); |
|
963 elseif(is_array($val)) |
|
964 $val = stripslashes_recurse($val); |
|
965 } |
|
966 return $arr; |
|
967 } |
|
968 |
|
969 /** |
|
970 * If magic_quotes_gpc is on, calls stripslashes() on everything in $_GET/$_POST/$_COOKIE |
|
971 * @ignore - this doesn't work |
|
972 * @todo port version from the PHP manual |
|
973 * @return void |
|
974 */ |
|
975 function strip_magic_quotes_gpc() |
|
976 { |
|
977 if(enano_get_magic_quotes_gpc()) |
|
978 { |
|
979 $_POST = stripslashes_recurse($_POST); |
|
980 $_GET = stripslashes_recurse($_GET); |
|
981 $_COOKIE = stripslashes_recurse($_COOKIE); |
|
982 } |
|
983 } |
|
984 |
|
985 /** |
|
986 * A very basic single-character compression algorithm for binary strings/bitfields |
|
987 * @param string $bits the text to compress |
|
988 * @return string |
|
989 */ |
|
990 |
|
991 function compress_bitfield($bits) |
|
992 { |
|
993 $crc32 = crc32($bits); |
|
994 $bits .= '0'; |
|
995 $start_pos = 0; |
|
996 $current = substr($bits, 1, 1); |
|
997 $last = substr($bits, 0, 1); |
|
998 $chunk_size = 1; |
|
999 $len = strlen($bits); |
|
1000 $crc = $len; |
|
1001 $crcval = 0; |
|
1002 for ( $i = 1; $i < $len; $i++ ) |
|
1003 { |
|
1004 $current = substr($bits, $i, 1); |
|
1005 $last = substr($bits, $i - 1, 1); |
|
1006 $next = substr($bits, $i + 1, 1); |
|
1007 // Are we on the last character? |
|
1008 if($current == $last && $i+1 < $len) |
|
1009 $chunk_size++; |
|
1010 else |
|
1011 { |
|
1012 if($i+1 == $len && $current == $next) |
|
1013 { |
|
1014 // This character completes a chunk |
|
1015 $chunk_size++; |
|
1016 $i++; |
|
1017 $chunk = substr($bits, $start_pos, $chunk_size); |
|
1018 $chunklen = strlen($chunk); |
|
1019 $newchunk = $last . '[' . $chunklen . ']'; |
|
1020 $newlen = strlen($newchunk); |
|
1021 $bits = substr($bits, 0, $start_pos) . $newchunk . substr($bits, $i, $len); |
|
1022 $chunk_size = 1; |
|
1023 $i = $start_pos + $newlen; |
|
1024 $start_pos = $i; |
|
1025 $len = strlen($bits); |
|
1026 $crcval = $crcval + $chunklen; |
|
1027 } |
|
1028 else |
|
1029 { |
|
1030 // Last character completed a chunk |
|
1031 $chunk = substr($bits, $start_pos, $chunk_size); |
|
1032 $chunklen = strlen($chunk); |
|
1033 $newchunk = $last . '[' . $chunklen . '],'; |
|
1034 $newlen = strlen($newchunk); |
|
1035 $bits = substr($bits, 0, $start_pos) . $newchunk . substr($bits, $i, $len); |
|
1036 $chunk_size = 1; |
|
1037 $i = $start_pos + $newlen; |
|
1038 $start_pos = $i; |
|
1039 $len = strlen($bits); |
|
1040 $crcval = $crcval + $chunklen; |
|
1041 } |
|
1042 } |
|
1043 } |
|
1044 if($crc != $crcval) |
|
1045 { |
|
1046 echo __FUNCTION__.'(): ERROR: length check failed, this is a bug in the algorithm<br />Debug info: aiming for a CRC val of '.$crc.', got '.$crcval; |
|
1047 return false; |
|
1048 } |
|
1049 $compressed = 'cbf:len='.$crc.';crc='.dechex($crc32).';data='.$bits.'|end'; |
|
1050 return $compressed; |
|
1051 } |
|
1052 |
|
1053 /** |
|
1054 * Uncompresses a bitfield compressed with compress_bitfield() |
|
1055 * @param string $bits the compressed bitfield |
|
1056 * @return string the uncompressed, original (we hope) bitfield OR bool false on error |
|
1057 */ |
|
1058 |
|
1059 function uncompress_bitfield($bits) |
|
1060 { |
|
1061 if(substr($bits, 0, 4) != 'cbf:') |
|
1062 { |
|
1063 echo __FUNCTION__.'(): ERROR: Invalid stream'; |
|
1064 return false; |
|
1065 } |
|
1066 $len = intval(substr($bits, strpos($bits, 'len=')+4, strpos($bits, ';')-strpos($bits, 'len=')-4)); |
|
1067 $crc = substr($bits, strpos($bits, 'crc=')+4, 8); |
|
1068 $data = substr($bits, strpos($bits, 'data=')+5, strpos($bits, '|end')-strpos($bits, 'data=')-5); |
|
1069 $data = explode(',', $data); |
|
1070 foreach($data as $a => $b) |
|
1071 { |
|
1072 $d =& $data[$a]; |
|
1073 $char = substr($d, 0, 1); |
|
1074 $dlen = intval(substr($d, 2, strlen($d)-1)); |
|
1075 $s = ''; |
|
1076 for($i=0;$i<$dlen;$i++,$s.=$char); |
|
1077 $d = $s; |
|
1078 unset($s, $dlen, $char); |
|
1079 } |
|
1080 $decompressed = implode('', $data); |
|
1081 $decompressed = substr($decompressed, 0, -1); |
|
1082 $dcrc = (string)dechex(crc32($decompressed)); |
|
1083 if($dcrc != $crc) |
|
1084 { |
|
1085 echo __FUNCTION__.'(): ERROR: CRC check failed<br />debug info:<br />original crc: '.$crc.'<br />decomp\'ed crc: '.$dcrc.'<br />'; |
|
1086 return false; |
|
1087 } |
|
1088 return $decompressed; |
|
1089 } |
|
1090 |
|
1091 /** |
|
1092 * Exports a MySQL table into a SQL string. |
|
1093 * @param string $table The name of the table to export |
|
1094 * @param bool $structure If true, include a CREATE TABLE command |
|
1095 * @param bool $data If true, include the contents of the table |
|
1096 * @param bool $compact If true, omits newlines between parts of SQL statements, use in Enano database exporter |
|
1097 * @return string |
|
1098 */ |
|
1099 |
|
1100 function export_table($table, $structure = true, $data = true, $compact = false) |
|
1101 { |
|
1102 global $db, $session, $paths, $template, $plugins; // Common objects |
|
1103 $struct_keys = ''; |
|
1104 $divider = (!$compact) ? "\n" : "\n"; |
|
1105 $spacer1 = (!$compact) ? "\n" : " "; |
|
1106 $spacer2 = (!$compact) ? " " : " "; |
|
1107 $rowspacer = (!$compact) ? "\n " : " "; |
|
1108 $index_list = Array(); |
|
1109 $cols = $db->sql_query('SHOW COLUMNS IN '.$table.';'); |
|
1110 if(!$cols) |
|
1111 { |
|
1112 echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />'; |
|
1113 return false; |
|
1114 } |
|
1115 $col = Array(); |
|
1116 $sqlcol = Array(); |
|
1117 $collist = Array(); |
|
1118 $pri_keys = Array(); |
|
1119 // Using fetchrow_num() here to compensate for MySQL l10n |
|
1120 while( $row = $db->fetchrow_num() ) |
|
1121 { |
|
1122 $field =& $row[0]; |
|
1123 $type =& $row[1]; |
|
1124 $null =& $row[2]; |
|
1125 $key =& $row[3]; |
|
1126 $def =& $row[4]; |
|
1127 $extra =& $row[5]; |
|
1128 $col[] = Array( |
|
1129 'name'=>$field, |
|
1130 'type'=>$type, |
|
1131 'null'=>$null, |
|
1132 'key'=>$key, |
|
1133 'default'=>$def, |
|
1134 'extra'=>$extra, |
|
1135 ); |
|
1136 $collist[] = $field; |
|
1137 } |
|
1138 |
|
1139 if ( $structure ) |
|
1140 { |
|
1141 $db->sql_query('SET SQL_QUOTE_SHOW_CREATE = 0;'); |
|
1142 $struct = $db->sql_query('SHOW CREATE TABLE '.$table.';'); |
|
1143 if ( !$struct ) |
|
1144 $db->_die(); |
|
1145 $row = $db->fetchrow_num(); |
|
1146 $db->free_result(); |
|
1147 $struct = $row[1]; |
|
1148 $struct = preg_replace("/\n\) ENGINE=(.+)$/", "\n);", $struct); |
|
1149 unset($row); |
|
1150 if ( $compact ) |
|
1151 { |
|
1152 $struct_arr = explode("\n", $struct); |
|
1153 foreach ( $struct_arr as $i => $leg ) |
|
1154 { |
|
1155 if ( $i == 0 ) |
|
1156 continue; |
|
1157 $test = trim($leg); |
|
1158 if ( empty($test) ) |
|
1159 { |
|
1160 unset($struct_arr[$i]); |
|
1161 continue; |
|
1162 } |
|
1163 $struct_arr[$i] = preg_replace('/^([\s]*)/', ' ', $leg); |
|
1164 } |
|
1165 $struct = implode("", $struct_arr); |
|
1166 } |
|
1167 } |
|
1168 |
|
1169 // Structuring complete |
|
1170 if($data) |
|
1171 { |
|
1172 $datq = $db->sql_query('SELECT * FROM '.$table.';'); |
|
1173 if(!$datq) |
|
1174 { |
|
1175 echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />'; |
|
1176 return false; |
|
1177 } |
|
1178 if($db->numrows() < 1) |
|
1179 { |
|
1180 if($structure) return $struct; |
|
1181 else return ''; |
|
1182 } |
|
1183 $rowdata = Array(); |
|
1184 $dataqs = Array(); |
|
1185 $insert_strings = Array(); |
|
1186 $z = false; |
|
1187 while($row = $db->fetchrow_num()) |
|
1188 { |
|
1189 $z = false; |
|
1190 foreach($row as $i => $cell) |
|
1191 { |
|
1192 $str = mysql_encode_column($cell, $col[$i]['type']); |
|
1193 $rowdata[] = $str; |
|
1194 } |
|
1195 $dataqs2 = implode(",$rowspacer", $dataqs) . ",$rowspacer" . '( ' . implode(', ', $rowdata) . ' )'; |
|
1196 $ins = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . $dataqs2 . ";"; |
|
1197 if ( strlen( $ins ) > MYSQL_MAX_PACKET_SIZE ) |
|
1198 { |
|
1199 // We've exceeded the maximum allowed packet size for MySQL - separate this into a different query |
|
1200 $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";; |
|
1201 $dataqs = Array('( ' . implode(', ', $rowdata) . ' )'); |
|
1202 $z = true; |
|
1203 } |
|
1204 else |
|
1205 { |
|
1206 $dataqs[] = '( ' . implode(', ', $rowdata) . ' )'; |
|
1207 } |
|
1208 $rowdata = Array(); |
|
1209 } |
|
1210 if ( !$z ) |
|
1211 { |
|
1212 $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";; |
|
1213 $dataqs = Array(); |
|
1214 } |
|
1215 $datstring = implode($divider, $insert_strings); |
|
1216 } |
|
1217 if($structure && !$data) return $struct; |
|
1218 elseif(!$structure && $data) return $datstring; |
|
1219 elseif($structure && $data) return $struct . $divider . $datstring; |
|
1220 elseif(!$structure && !$data) return ''; |
|
1221 } |
|
1222 |
|
1223 /** |
|
1224 * Encodes a string value for use in an INSERT statement for given column type $type. |
|
1225 * @access private |
|
1226 */ |
|
1227 |
|
1228 function mysql_encode_column($input, $type) |
|
1229 { |
|
1230 global $db, $session, $paths, $template, $plugins; // Common objects |
|
1231 // Decide whether to quote the string or not |
|
1232 if(substr($type, 0, 7) == 'varchar' || $type == 'datetime' || $type == 'text' || $type == 'tinytext' || $type == 'smalltext' || $type == 'longtext' || substr($type, 0, 4) == 'char') |
|
1233 { |
|
1234 $str = "'" . $db->escape($input) . "'"; |
|
1235 } |
|
1236 elseif(in_array($type, Array('blob', 'longblob', 'mediumblob', 'smallblob')) || substr($type, 0, 6) == 'binary' || substr($type, 0, 9) == 'varbinary') |
|
1237 { |
|
1238 $str = '0x' . hexencode($input, '', ''); |
|
1239 } |
|
1240 elseif(is_null($input)) |
|
1241 { |
|
1242 $str = 'NULL'; |
|
1243 } |
|
1244 else |
|
1245 { |
|
1246 $str = (string)$input; |
|
1247 } |
|
1248 return $str; |
|
1249 } |
|
1250 |
|
1251 /** |
|
1252 * Creates an associative array defining which file extensions are allowed and which ones aren't |
|
1253 * @return array keyname will be a file extension, value will be true or false |
|
1254 */ |
|
1255 |
|
1256 function fetch_allowed_extensions() |
|
1257 { |
|
1258 global $mime_types; |
|
1259 $bits = getConfig('allowed_mime_types'); |
|
1260 if(!$bits) return Array(false); |
|
1261 $bits = uncompress_bitfield($bits); |
|
1262 if(!$bits) return Array(false); |
|
1263 $bits = enano_str_split($bits, 1); |
|
1264 $ret = Array(); |
|
1265 $mt = array_keys($mime_types); |
|
1266 foreach($bits as $i => $b) |
|
1267 { |
|
1268 $ret[$mt[$i]] = ( $b == '1' ) ? true : false; |
|
1269 } |
|
1270 return $ret; |
|
1271 } |
|
1272 |
|
1273 /** |
|
1274 * Generates a random key suitable for encryption |
|
1275 * @param int $len the length of the key |
|
1276 * @return string a BINARY key |
|
1277 */ |
|
1278 |
|
1279 function randkey($len = 32) |
|
1280 { |
|
1281 $key = ''; |
|
1282 for($i=0;$i<$len;$i++) |
|
1283 { |
|
1284 $key .= chr(mt_rand(0, 255)); |
|
1285 } |
|
1286 return $key; |
|
1287 } |
|
1288 |
|
1289 /** |
|
1290 * Decodes a hex string. |
|
1291 * @param string $hex The hex code to decode |
|
1292 * @return string |
|
1293 */ |
|
1294 |
|
1295 function hexdecode($hex) |
|
1296 { |
|
1297 $hex = enano_str_split($hex, 2); |
|
1298 $bin_key = ''; |
|
1299 foreach($hex as $nibble) |
|
1300 { |
|
1301 $byte = chr(hexdec($nibble)); |
|
1302 $bin_key .= $byte; |
|
1303 } |
|
1304 return $bin_key; |
|
1305 } |
|
1306 |
|
1307 /** |
|
1308 * Enano's own (almost) bulletproof HTML sanitizer. |
|
1309 * @param string $html The input HTML |
|
1310 * @return string cleaned HTML |
|
1311 */ |
|
1312 |
|
1313 function sanitize_html($html, $filter_php = true) |
|
1314 { |
|
1315 |
|
1316 $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>(.*?)</\\1>#is', '<\\1\\2\\3javascript:\\59>\\60</\\1>', $html); |
|
1317 $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>#is', '<\\1\\2\\3javascript:\\59>', $html); |
|
1318 |
|
1319 if($filter_php) |
|
1320 $html = str_replace( |
|
1321 Array('<?php', '<?', '<%', '?>', '%>'), |
|
1322 Array('<?php', '<?', '<%', '?>', '%>'), |
|
1323 $html); |
|
1324 |
|
1325 $tag_whitelist = array_keys ( setupAttributeWhitelist() ); |
|
1326 if ( !$filter_php ) |
|
1327 $tag_whitelist[] = '?php'; |
|
1328 $len = strlen($html); |
|
1329 $in_quote = false; |
|
1330 $quote_char = ''; |
|
1331 $tag_start = 0; |
|
1332 $tag_name = ''; |
|
1333 $in_tag = false; |
|
1334 $trk_name = false; |
|
1335 for ( $i = 0; $i < $len; $i++ ) |
|
1336 { |
|
1337 $chr = $html{$i}; |
|
1338 $prev = ( $i == 0 ) ? '' : $html{ $i - 1 }; |
|
1339 $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 }; |
|
1340 if ( $in_quote && $in_tag ) |
|
1341 { |
|
1342 if ( $quote_char == $chr && $prev != '\\' ) |
|
1343 $in_quote = false; |
|
1344 } |
|
1345 elseif ( ( $chr == '"' || $chr == "'" ) && $prev != '\\' && $in_tag ) |
|
1346 { |
|
1347 $in_quote = true; |
|
1348 $quote_char = $chr; |
|
1349 } |
|
1350 if ( $chr == '<' && !$in_tag && $next != '/' ) |
|
1351 { |
|
1352 // start of a tag |
|
1353 $tag_start = $i; |
|
1354 $in_tag = true; |
|
1355 $trk_name = true; |
|
1356 } |
|
1357 elseif ( !$in_quote && $in_tag && $chr == '>' ) |
|
1358 { |
|
1359 $full_tag = substr($html, $tag_start, ( $i - $tag_start ) + 1 ); |
|
1360 $l = strlen($tag_name) + 2; |
|
1361 $attribs_only = trim( substr($full_tag, $l, ( strlen($full_tag) - $l - 1 ) ) ); |
|
1362 |
|
1363 // Debugging message |
|
1364 // echo htmlspecialchars($full_tag) . '<br />'; |
|
1365 |
|
1366 if ( !in_array($tag_name, $tag_whitelist) ) |
|
1367 { |
|
1368 // Illegal tag |
|
1369 //echo $tag_name . ' '; |
|
1370 |
|
1371 $s = ( empty($attribs_only) ) ? '' : ' '; |
|
1372 |
|
1373 $sanitized = '<' . $tag_name . $s . $attribs_only . '>'; |
|
1374 |
|
1375 $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1); |
|
1376 $html = str_replace('</' . $tag_name . '>', '</' . $tag_name . '>', $html); |
|
1377 $new_i = $tag_start + strlen($sanitized); |
|
1378 |
|
1379 $len = strlen($html); |
|
1380 $i = $new_i; |
|
1381 |
|
1382 $in_tag = false; |
|
1383 $tag_name = ''; |
|
1384 continue; |
|
1385 } |
|
1386 else |
|
1387 { |
|
1388 if ( $tag_name == '?php' && !$filter_php ) |
|
1389 continue; |
|
1390 $f = fixTagAttributes( $attribs_only, $tag_name ); |
|
1391 $s = ( empty($f) ) ? '' : ' '; |
|
1392 |
|
1393 $sanitized = '<' . $tag_name . $f . '>'; |
|
1394 $new_i = $tag_start + strlen($sanitized); |
|
1395 |
|
1396 $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1); |
|
1397 $len = strlen($html); |
|
1398 $i = $new_i; |
|
1399 |
|
1400 $in_tag = false; |
|
1401 $tag_name = ''; |
|
1402 continue; |
|
1403 } |
|
1404 } |
|
1405 elseif ( $in_tag && $trk_name ) |
|
1406 { |
|
1407 $is_alphabetical = ( strtolower($chr) != strtoupper($chr) || in_array($chr, array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) || $chr == '?' ); |
|
1408 if ( $is_alphabetical ) |
|
1409 $tag_name .= $chr; |
|
1410 else |
|
1411 { |
|
1412 $trk_name = false; |
|
1413 } |
|
1414 } |
|
1415 |
|
1416 } |
|
1417 |
|
1418 return $html; |
|
1419 |
|
1420 } |
|
1421 |
|
1422 function htmlalternatives($string) |
|
1423 { |
|
1424 $ret = ''; |
|
1425 for ( $i = 0; $i < strlen($string); $i++ ) |
|
1426 { |
|
1427 $chr = $string{$i}; |
|
1428 $ch1 = ord($chr); |
|
1429 $ch2 = dechex($ch1); |
|
1430 $byte = '(&\\#([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch2 . ';|&\\#x([0]*){0,7}' . $ch2 . ';|%([0]*){0,7}' . $ch2 . '|' . preg_quote($chr) . ')'; |
|
1431 $ret .= $byte; |
|
1432 $ret .= '([\s]){0,2}'; |
|
1433 } |
|
1434 return $ret; |
|
1435 } |
|
1436 |
|
1437 /** |
|
1438 * Paginates (breaks into multiple pages) a MySQL result resource, which is treated as unbuffered. |
|
1439 * @param resource The MySQL result resource. This should preferably be an unbuffered query. |
|
1440 * @param string A template, with variables being named after the column name |
|
1441 * @param int The number of total results. This should be determined by a second query. |
|
1442 * @param string sprintf-style formatting string for URLs for result pages. First parameter will be start offset. |
|
1443 * @param int Optional. Start offset in individual results. Defaults to 0. |
|
1444 * @param int Optional. The number of results per page. Defualts to 10. |
|
1445 * @param int Optional. An associative array of functions to call, with key names being column names, and values being function names. Values can also be an array with key 0 being either an object or a string(class name) and key 1 being a [static] method. |
|
1446 * @param string Optional. The text to be sent before the result list, only if there are any results. Possibly the start of a table. |
|
1447 * @param string Optional. The text to be sent after the result list, only if there are any results. Possibly the end of a table. |
|
1448 * @return string |
|
1449 */ |
|
1450 |
|
1451 function paginate($q, $tpl_text, $num_results, $result_url, $start = 0, $perpage = 10, $callers = Array(), $header = '', $footer = '') |
|
1452 { |
|
1453 global $db, $session, $paths, $template, $plugins; // Common objects |
|
1454 $parser = $template->makeParserText($tpl_text); |
|
1455 $num_pages = ceil ( $num_results / $perpage ); |
|
1456 $out = ''; |
|
1457 $i = 0; |
|
1458 $this_page = ceil ( $start / $perpage ); |
|
1459 |
|
1460 // Build paginator |
|
1461 $begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;"> |
|
1462 <table border="0" cellspacing="1" cellpadding="4"> |
|
1463 <tr><th>Page:</th>'; |
|
1464 $block = '<td class="row1" style="text-align: center;">{LINK}</td>'; |
|
1465 $end = '</tr></table></div>'; |
|
1466 $blk = $template->makeParserText($block); |
|
1467 $inner = ''; |
|
1468 $cls = 'row2'; |
|
1469 if ( $num_pages < 5 ) |
|
1470 { |
|
1471 for ( $i = 0; $i < $num_pages; $i++ ) |
|
1472 { |
|
1473 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1474 $offset = strval($i * $perpage); |
|
1475 $url = sprintf($result_url, $offset); |
|
1476 $j = $i + 1; |
|
1477 $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>"; |
|
1478 $blk->assign_vars(array( |
|
1479 'CLASS'=>$cls, |
|
1480 'LINK'=>$link |
|
1481 )); |
|
1482 $inner .= $blk->run(); |
|
1483 } |
|
1484 } |
|
1485 else |
|
1486 { |
|
1487 if ( $this_page + 5 > $num_pages ) |
|
1488 { |
|
1489 $list = Array(); |
|
1490 $tp = $this_page; |
|
1491 if ( $this_page + 0 == $num_pages ) $tp = $tp - 3; |
|
1492 if ( $this_page + 1 == $num_pages ) $tp = $tp - 2; |
|
1493 if ( $this_page + 2 == $num_pages ) $tp = $tp - 1; |
|
1494 for ( $i = $tp - 1; $i <= $tp + 1; $i++ ) |
|
1495 { |
|
1496 $list[] = $i; |
|
1497 } |
|
1498 } |
|
1499 else |
|
1500 { |
|
1501 $list = Array(); |
|
1502 $current = $this_page; |
|
1503 $lower = ( $current < 3 ) ? 1 : $current - 1; |
|
1504 for ( $i = 0; $i < 3; $i++ ) |
|
1505 { |
|
1506 $list[] = $lower + $i; |
|
1507 } |
|
1508 } |
|
1509 $url = sprintf($result_url, '0'); |
|
1510 $link = ( 0 == $start ) ? "<b>First</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>« First</a>"; |
|
1511 $blk->assign_vars(array( |
|
1512 'CLASS'=>$cls, |
|
1513 'LINK'=>$link |
|
1514 )); |
|
1515 $inner .= $blk->run(); |
|
1516 |
|
1517 // if ( !in_array(1, $list) ) |
|
1518 // { |
|
1519 // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1520 // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...')); |
|
1521 // $inner .= $blk->run(); |
|
1522 // } |
|
1523 |
|
1524 foreach ( $list as $i ) |
|
1525 { |
|
1526 if ( $i == $num_pages ) |
|
1527 break; |
|
1528 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1529 $offset = strval($i * $perpage); |
|
1530 $url = sprintf($result_url, $offset); |
|
1531 $j = $i + 1; |
|
1532 $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>"; |
|
1533 $blk->assign_vars(array( |
|
1534 'CLASS'=>$cls, |
|
1535 'LINK'=>$link |
|
1536 )); |
|
1537 $inner .= $blk->run(); |
|
1538 } |
|
1539 |
|
1540 $total = $num_pages * $perpage - $perpage; |
|
1541 |
|
1542 if ( $this_page < $num_pages ) |
|
1543 { |
|
1544 // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1545 // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...')); |
|
1546 // $inner .= $blk->run(); |
|
1547 |
|
1548 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1549 $offset = strval($total); |
|
1550 $url = sprintf($result_url, $offset); |
|
1551 $j = $i + 1; |
|
1552 $link = ( $offset == strval($start) ) ? "<b>Last</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Last »</a>"; |
|
1553 $blk->assign_vars(array( |
|
1554 'CLASS'=>$cls, |
|
1555 'LINK'=>$link |
|
1556 )); |
|
1557 $inner .= $blk->run(); |
|
1558 } |
|
1559 |
|
1560 } |
|
1561 |
|
1562 $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$this_page.', '.$num_pages.', '.$perpage.', unescape(\'' . rawurlencode($result_url) . '\'));">↓</td>'; |
|
1563 |
|
1564 $paginator = "\n$begin$inner$end\n"; |
|
1565 $out .= $paginator; |
|
1566 |
|
1567 $cls = 'row2'; |
|
1568 |
|
1569 if ( $row = $db->fetchrow($q) ) |
|
1570 { |
|
1571 $i = 0; |
|
1572 $out .= $header; |
|
1573 do { |
|
1574 $i++; |
|
1575 if ( $i <= $start ) |
|
1576 { |
|
1577 continue; |
|
1578 } |
|
1579 if ( ( $i - $start ) > $perpage ) |
|
1580 { |
|
1581 break; |
|
1582 } |
|
1583 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1584 foreach ( $row as $j => $val ) |
|
1585 { |
|
1586 if ( isset($callers[$j]) ) |
|
1587 { |
|
1588 $tmp = ( is_callable($callers[$j]) ) ? @call_user_func($callers[$j], $val, $row) : $v; |
|
1589 |
|
1590 if ( $tmp ) |
|
1591 { |
|
1592 $row[$j] = $tmp; |
|
1593 } |
|
1594 } |
|
1595 } |
|
1596 $parser->assign_vars($row); |
|
1597 $parser->assign_vars(array('_css_class' => $cls)); |
|
1598 $out .= $parser->run(); |
|
1599 } while ( $row = $db->fetchrow($q) ); |
|
1600 $out .= $footer; |
|
1601 } |
|
1602 |
|
1603 $out .= $paginator; |
|
1604 |
|
1605 return $out; |
|
1606 } |
|
1607 |
|
1608 /** |
|
1609 * This is the same as paginate(), but it processes an array instead of a MySQL result resource. |
|
1610 * @param array The results. Each value is simply echoed. |
|
1611 * @param int The number of total results. This should be determined by a second query. |
|
1612 * @param string sprintf-style formatting string for URLs for result pages. First parameter will be start offset. |
|
1613 * @param int Optional. Start offset in individual results. Defaults to 0. |
|
1614 * @param int Optional. The number of results per page. Defualts to 10. |
|
1615 * @param string Optional. The text to be sent before the result list, only if there are any results. Possibly the start of a table. |
|
1616 * @param string Optional. The text to be sent after the result list, only if there are any results. Possibly the end of a table. |
|
1617 * @return string |
|
1618 */ |
|
1619 |
|
1620 function paginate_array($q, $num_results, $result_url, $start = 0, $perpage = 10, $header = '', $footer = '') |
|
1621 { |
|
1622 global $db, $session, $paths, $template, $plugins; // Common objects |
|
1623 $parser = $template->makeParserText($tpl_text); |
|
1624 $num_pages = ceil ( $num_results / $perpage ); |
|
1625 $out = ''; |
|
1626 $i = 0; |
|
1627 $this_page = ceil ( $start / $perpage ); |
|
1628 |
|
1629 // Build paginator |
|
1630 $begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;"> |
|
1631 <table border="0" cellspacing="1" cellpadding="4"> |
|
1632 <tr><th>Page:</th>'; |
|
1633 $block = '<td class="row1" style="text-align: center;">{LINK}</td>'; |
|
1634 $end = '</tr></table></div>'; |
|
1635 $blk = $template->makeParserText($block); |
|
1636 $inner = ''; |
|
1637 $cls = 'row2'; |
|
1638 if ( $start > 0 ) |
|
1639 { |
|
1640 $url = sprintf($result_url, abs($start - $perpage)); |
|
1641 $link = "<a href=".'"'."$url".'"'." style='text-decoration: none;'>« Prev</a>"; |
|
1642 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1643 $blk->assign_vars(array( |
|
1644 'CLASS'=>$cls, |
|
1645 'LINK'=>$link |
|
1646 )); |
|
1647 $inner .= $blk->run(); |
|
1648 } |
|
1649 if ( $num_pages < 5 ) |
|
1650 { |
|
1651 for ( $i = 0; $i < $num_pages; $i++ ) |
|
1652 { |
|
1653 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1654 $offset = strval($i * $perpage); |
|
1655 $url = sprintf($result_url, $offset); |
|
1656 $j = $i + 1; |
|
1657 $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>"; |
|
1658 $blk->assign_vars(array( |
|
1659 'CLASS'=>$cls, |
|
1660 'LINK'=>$link |
|
1661 )); |
|
1662 $inner .= $blk->run(); |
|
1663 } |
|
1664 } |
|
1665 else |
|
1666 { |
|
1667 if ( $this_page + 5 > $num_pages ) |
|
1668 { |
|
1669 $list = Array(); |
|
1670 $tp = $this_page; |
|
1671 if ( $this_page + 0 == $num_pages ) $tp = $tp - 3; |
|
1672 if ( $this_page + 1 == $num_pages ) $tp = $tp - 2; |
|
1673 if ( $this_page + 2 == $num_pages ) $tp = $tp - 1; |
|
1674 for ( $i = $tp - 1; $i <= $tp + 1; $i++ ) |
|
1675 { |
|
1676 $list[] = $i; |
|
1677 } |
|
1678 } |
|
1679 else |
|
1680 { |
|
1681 $list = Array(); |
|
1682 $current = $this_page; |
|
1683 $lower = ( $current < 3 ) ? 1 : $current - 1; |
|
1684 for ( $i = 0; $i < 3; $i++ ) |
|
1685 { |
|
1686 $list[] = $lower + $i; |
|
1687 } |
|
1688 } |
|
1689 $url = sprintf($result_url, '0'); |
|
1690 $link = ( 0 == $start ) ? "<b>First</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>« First</a>"; |
|
1691 $blk->assign_vars(array( |
|
1692 'CLASS'=>$cls, |
|
1693 'LINK'=>$link |
|
1694 )); |
|
1695 $inner .= $blk->run(); |
|
1696 |
|
1697 // if ( !in_array(1, $list) ) |
|
1698 // { |
|
1699 // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1700 // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...')); |
|
1701 // $inner .= $blk->run(); |
|
1702 // } |
|
1703 |
|
1704 foreach ( $list as $i ) |
|
1705 { |
|
1706 if ( $i == $num_pages ) |
|
1707 break; |
|
1708 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1709 $offset = strval($i * $perpage); |
|
1710 $url = sprintf($result_url, $offset); |
|
1711 $j = $i + 1; |
|
1712 $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>"; |
|
1713 $blk->assign_vars(array( |
|
1714 'CLASS'=>$cls, |
|
1715 'LINK'=>$link |
|
1716 )); |
|
1717 $inner .= $blk->run(); |
|
1718 } |
|
1719 |
|
1720 $total = $num_pages * $perpage - $perpage; |
|
1721 |
|
1722 if ( $this_page < $num_pages ) |
|
1723 { |
|
1724 // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1725 // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...')); |
|
1726 // $inner .= $blk->run(); |
|
1727 |
|
1728 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1729 $offset = strval($total); |
|
1730 $url = sprintf($result_url, $offset); |
|
1731 $j = $i + 1; |
|
1732 $link = ( $offset == strval($start) ) ? "<b>Last</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Last »</a>"; |
|
1733 $blk->assign_vars(array( |
|
1734 'CLASS'=>$cls, |
|
1735 'LINK'=>$link |
|
1736 )); |
|
1737 $inner .= $blk->run(); |
|
1738 } |
|
1739 |
|
1740 } |
|
1741 |
|
1742 if ( $start < $total ) |
|
1743 { |
|
1744 $url = sprintf($result_url, abs($start + $perpage)); |
|
1745 $link = "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Next »</a>"; |
|
1746 $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; |
|
1747 $blk->assign_vars(array( |
|
1748 'CLASS'=>$cls, |
|
1749 'LINK'=>$link |
|
1750 )); |
|
1751 $inner .= $blk->run(); |
|
1752 } |
|
1753 |
|
1754 $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$this_page.', '.$num_pages.', '.$perpage.', unescape(\'' . rawurlencode($result_url) . '\'));">↓</td>'; |
|
1755 |
|
1756 $paginator = "\n$begin$inner$end\n"; |
|
1757 if ( $total > 1 ) |
|
1758 $out .= $paginator; |
|
1759 |
|
1760 $cls = 'row2'; |
|
1761 |
|
1762 if ( sizeof($q) > 0 ) |
|
1763 { |
|
1764 $i = 0; |
|
1765 $out .= $header; |
|
1766 foreach ( $q as $val ) { |
|
1767 $i++; |
|
1768 if ( $i <= $start ) |
|
1769 { |
|
1770 continue; |
|
1771 } |
|
1772 if ( ( $i - $start ) > $perpage ) |
|
1773 { |
|
1774 break; |
|
1775 } |
|
1776 $out .= $val; |
|
1777 } |
|
1778 $out .= $footer; |
|
1779 } |
|
1780 |
|
1781 if ( $total > 1 ) |
|
1782 $out .= $paginator; |
|
1783 |
|
1784 return $out; |
|
1785 } |
|
1786 |
|
1787 /** |
|
1788 * Enano version of fputs for debugging |
|
1789 */ |
|
1790 |
|
1791 function enano_fputs($socket, $data) |
|
1792 { |
|
1793 // echo '<pre>' . htmlspecialchars($data) . '</pre>'; |
|
1794 // flush(); |
|
1795 // ob_flush(); |
|
1796 // ob_end_flush(); |
|
1797 return fputs($socket, $data); |
|
1798 } |
|
1799 |
|
1800 /** |
|
1801 * Sanitizes a page URL string so that it can safely be stored in the database. |
|
1802 * @param string Page ID to sanitize |
|
1803 * @return string Cleaned text |
|
1804 */ |
|
1805 |
|
1806 function sanitize_page_id($page_id) |
|
1807 { |
|
1808 |
|
1809 // First, replace spaces with underscores |
|
1810 $page_id = str_replace(' ', '_', $page_id); |
|
1811 |
|
1812 preg_match_all('/\.[A-Fa-f0-9][A-Fa-f0-9]/', $page_id, $matches); |
|
1813 |
|
1814 foreach ( $matches[0] as $id => $char ) |
|
1815 { |
|
1816 $char = substr($char, 1); |
|
1817 $char = strtolower($char); |
|
1818 $char = intval(hexdec($char)); |
|
1819 $char = chr($char); |
|
1820 $page_id = str_replace($matches[0][$id], $char, $page_id); |
|
1821 } |
|
1822 |
|
1823 $pid_clean = preg_replace('/[\w\/:;\(\)@\[\]_-]/', 'X', $page_id); |
|
1824 $pid_dirty = enano_str_split($pid_clean, 1); |
|
1825 |
|
1826 foreach ( $pid_dirty as $id => $char ) |
|
1827 { |
|
1828 if ( $char == 'X' ) |
|
1829 continue; |
|
1830 $cid = ord($char); |
|
1831 $cid = dechex($cid); |
|
1832 $cid = strval($cid); |
|
1833 if ( strlen($cid) < 2 ) |
|
1834 { |
|
1835 $cid = strtoupper("0$cid"); |
|
1836 } |
|
1837 $pid_dirty[$id] = ".$cid"; |
|
1838 } |
|
1839 |
|
1840 $pid_chars = enano_str_split($page_id, 1); |
|
1841 $page_id_cleaned = ''; |
|
1842 |
|
1843 foreach ( $pid_chars as $id => $char ) |
|
1844 { |
|
1845 if ( $pid_dirty[$id] == 'X' ) |
|
1846 $page_id_cleaned .= $char; |
|
1847 else |
|
1848 $page_id_cleaned .= $pid_dirty[$id]; |
|
1849 } |
|
1850 |
|
1851 global $mime_types; |
|
1852 |
|
1853 $exts = array_keys($mime_types); |
|
1854 $exts = '(' . implode('|', $exts) . ')'; |
|
1855 |
|
1856 $page_id_cleaned = preg_replace('/\.2e' . $exts . '$/', '.\\1', $page_id_cleaned); |
|
1857 |
|
1858 return $page_id_cleaned; |
|
1859 } |
|
1860 |
|
1861 /** |
|
1862 * Inserts commas into a number to make it more human-readable. Floating point-safe. |
|
1863 * @param int The number to process |
|
1864 * @return string Input number with commas added |
|
1865 */ |
|
1866 |
|
1867 function commatize($num) |
|
1868 { |
|
1869 $num = (string)$num; |
|
1870 if ( strpos($num, '.') ) |
|
1871 { |
|
1872 $whole = explode('.', $num); |
|
1873 $num = $whole[0]; |
|
1874 $dec = $whole[1]; |
|
1875 } |
|
1876 else |
|
1877 { |
|
1878 $whole = $num; |
|
1879 } |
|
1880 $offset = ( strlen($num) ) % 3; |
|
1881 $len = strlen($num); |
|
1882 $offset = ( $offset == 0 ) |
|
1883 ? 3 |
|
1884 : $offset; |
|
1885 for ( $i = $offset; $i < $len; $i=$i+3 ) |
|
1886 { |
|
1887 $num = substr($num, 0, $i) . ',' . substr($num, $i, $len); |
|
1888 $len = strlen($num); |
|
1889 $i++; |
|
1890 } |
|
1891 if ( isset($dec) ) |
|
1892 { |
|
1893 return $num . '.' . $dec; |
|
1894 } |
|
1895 else |
|
1896 { |
|
1897 return $num; |
|
1898 } |
|
1899 } |
|
1900 |
|
1901 //die('<pre>Original: 01010101010100101010100101010101011010'."\nProcessed: ".uncompress_bitfield(compress_bitfield('01010101010100101010100101010101011010')).'</pre>'); |
|
1902 |
|
1903 ?> |