1
+ − 1
<?php
+ − 2
+ − 3
/*
+ − 4
* Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
142
ca9118d9c0f2
Rebrand as 1.0.2 (Coblynau); internal links are now parsed by RenderMan::parse_internal_links()
Dan
diff
changeset
+ − 5
* Version 1.0.2 (Coblynau)
1
+ − 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 db_error_handler($errno, $errstr, $errfile = false, $errline = false, $errcontext = Array() )
+ − 16
{
+ − 17
if ( !defined('ENANO_DEBUG') )
+ − 18
return;
+ − 19
$e = error_reporting(0);
+ − 20
error_reporting($e);
+ − 21
if ( $e < $errno )
+ − 22
return;
+ − 23
$errtype = 'Notice';
+ − 24
switch ( $errno )
+ − 25
{
+ − 26
case E_ERROR: case E_USER_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: $errtype = 'Error'; break;
+ − 27
case E_WARNING: case E_USER_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: $errtype = 'Warning'; break;
+ − 28
}
+ − 29
$debug = debug_backtrace();
+ − 30
$debug = $debug[2]['file'] . ', line ' . $debug[2]['line'];
+ − 31
echo "<b>$errtype:</b> $errstr<br />Error source:<pre>$debug</pre>";
+ − 32
}
+ − 33
+ − 34
class mysql {
+ − 35
var $num_queries, $query_backtrace, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values;
+ − 36
var $row = array();
+ − 37
var $rowset = array();
+ − 38
var $errhandler;
+ − 39
+ − 40
function enable_errorhandler()
+ − 41
{
+ − 42
if ( function_exists('debug_backtrace') )
+ − 43
{
+ − 44
$this->errhandler = set_error_handler('db_error_handler');
+ − 45
}
+ − 46
}
+ − 47
+ − 48
function disable_errorhandler()
+ − 49
{
+ − 50
if ( $this->errhandler )
+ − 51
{
+ − 52
set_error_handler($this->errhandler);
+ − 53
}
+ − 54
else
+ − 55
{
+ − 56
restore_error_handler();
+ − 57
}
+ − 58
}
+ − 59
+ − 60
function sql_backtrace() {
+ − 61
$qb = explode("\n", $this->query_backtrace);
+ − 62
$bt = '';
+ − 63
//for($i=sizeof($qb)-1;$i>=0;$i--) {
+ − 64
for($i=0;$i<sizeof($qb);$i++) {
+ − 65
$bt .= $qb[$i]."\n";
+ − 66
}
+ − 67
return $bt;
+ − 68
}
+ − 69
+ − 70
function ensure_connection()
+ − 71
{
+ − 72
if(!$this->_conn)
+ − 73
{
+ − 74
$this->connect();
+ − 75
}
+ − 76
}
+ − 77
+ − 78
function _die($t = '') {
+ − 79
if(defined('ENANO_HEADERS_SENT')) {
+ − 80
ob_clean();
+ − 81
}
+ − 82
header('HTTP/1.1 500 Internal Server Error');
15
ad5986a53197
Fixed complicated SQL injection vulnerability in URL handler, updated license info for Tigra Tree Menu, and killed one XSS vulnerability
Dan
diff
changeset
+ − 83
$bt = $this->latest_query; // $this->sql_backtrace();
1
+ − 84
$e = htmlspecialchars(mysql_error());
+ − 85
if($e=='') $e='<none>';
91
+ − 86
$t = ( !empty($t) ) ? $t : '<No error description provided>';
+ − 87
global $email;
+ − 88
$email_info = ( defined('ENANO_CONFIG_FETCHED') && is_object($email) ) ? ', at <' . $email->jscode() . $email->encryptEmail(getConfig('contact_email')) . '>' : '';
+ − 89
$internal_text = '<h3>The site was unable to finish serving your request.</h3>
+ − 90
<p>We apologize for the inconveience, but an error occurred in the Enano database layer. Please report the full text of this page to the administrator of this site' . $email_info . '.</p>
+ − 91
<p>Description or location of error: '.$t.'<br />
+ − 92
Error returned by MySQL extension: ' . $e . '<br />
+ − 93
Most recent SQL query:</p>
+ − 94
<pre>'.$bt.'</pre>';
+ − 95
if(defined('ENANO_CONFIG_FETCHED')) die_semicritical('Database error', $internal_text);
+ − 96
else grinding_halt('Database error', $internal_text);
1
+ − 97
exit;
+ − 98
}
+ − 99
+ − 100
function die_json()
+ − 101
{
+ − 102
$e = addslashes(htmlspecialchars(mysql_error()));
+ − 103
$q = addslashes($this->latest_query);
+ − 104
$t = "{'mode':'error','error':'An error occurred during database query.\nQuery was:\n $q\n\nError returned by MySQL: $e'}";
+ − 105
die($t);
+ − 106
}
+ − 107
+ − 108
function get_error($t = '') {
+ − 109
header('HTTP/1.1 500 Internal Server Error');
+ − 110
$bt = $this->sql_backtrace();
+ − 111
$e = htmlspecialchars(mysql_error());
+ − 112
if($e=='') $e='<none>';
91
+ − 113
global $email;
+ − 114
$email_info = ( defined('ENANO_CONFIG_FETCHED') && is_object($email) ) ? ', at <' . $email->jscode() . $email->encryptEmail(getConfig('contact_email')) . '>' : '';
+ − 115
$internal_text = '<h3>The site was unable to finish serving your request.</h3>
+ − 116
<p>We apologize for the inconveience, but an error occurred in the Enano database layer. Please report the full text of this page to the administrator of this site' . $email_info . '.</p>
+ − 117
<p>Description or location of error: '.$t.'<br />
+ − 118
Error returned by MySQL extension: ' . $e . '<br />
+ − 119
Most recent SQL query:</p>
+ − 120
<pre>'.$bt.'</pre>';
+ − 121
return $internal_text;
1
+ − 122
}
+ − 123
+ − 124
function connect() {
+ − 125
$this->enable_errorhandler();
+ − 126
dc_here('dbal: trying to connect....');
+ − 127
@include(ENANO_ROOT.'/config.php');
+ − 128
if(isset($crypto_key))
+ − 129
unset($crypto_key); // Get this sucker out of memory fast
+ − 130
if(!defined('ENANO_INSTALLED') && !defined('MIDGET_INSTALLED') && !defined('IN_ENANO_INSTALL') )
+ − 131
{
+ − 132
dc_here('dbal: oops, looks like Enano isn\'t set up. Constants ENANO_INSTALLED, MIDGET_INSTALLED, and IN_ENANO_INSTALL are all undefined.');
+ − 133
header('Location: install.php');
+ − 134
exit;
+ − 135
}
+ − 136
$this->_conn = @mysql_connect($dbhost, $dbuser, $dbpasswd);
+ − 137
unset($dbuser);
+ − 138
unset($dbpasswd); // Security
+ − 139
if(!$this->_conn) { dc_here('dbal: uhoh!<br />'.mysql_error()); grinding_halt('Enano is having a problem', '<p>Error: couldn\'t connect to MySQL.<br />'.mysql_error().'</p>'); }
+ − 140
$this->query_backtrace = '';
+ − 141
$this->num_queries = 0;
+ − 142
dc_here('dbal: we\'re in, selecting database...');
203
acb9d021b860
Database name can now contain dashes (as per requested at http://forum.enanocms.org/viewtopic.php?f=5&t=14); corrected some installer behavior issues with connecting as root and setting up permissions resulting in logs not being flushed, configs not being inserted, and what have you.
Dan
diff
changeset
+ − 143
$q = $this->sql_query('USE `'.$dbname.'`;');
1
+ − 144
if(!$q) $this->_die('The database could not be selected.');
+ − 145
dc_here('dbal: connected to MySQL');
+ − 146
$this->disable_errorhandler();
+ − 147
}
+ − 148
+ − 149
function sql_query($q) {
+ − 150
$this->enable_errorhandler();
+ − 151
$this->num_queries++;
+ − 152
$this->query_backtrace .= $q."\n";
+ − 153
$this->latest_query = $q;
+ − 154
dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
+ − 155
if(!$this->_conn) $this->_die('A database connection has not yet been established.');
+ − 156
if(!$this->check_query($q))
+ − 157
{
+ − 158
$this->report_query($q);
+ − 159
grinding_halt('SQL Injection attempt', '<p>Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.</p><p>Query was:</p><pre>'.htmlspecialchars($q).'</pre>');
+ − 160
}
+ − 161
$r = mysql_query($q, $this->_conn);
+ − 162
$this->latest_result = $r;
+ − 163
$this->disable_errorhandler();
+ − 164
return $r;
+ − 165
}
+ − 166
+ − 167
function sql_unbuffered_query($q) {
+ − 168
$this->enable_errorhandler();
+ − 169
$this->num_queries++;
+ − 170
$this->query_backtrace .= '(UNBUFFERED) ' . $q."\n";
+ − 171
$this->latest_query = $q;
+ − 172
dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
+ − 173
if(!$this->_conn) $this->_die('A database connection has not yet been established.');
+ − 174
if(!$this->check_query($q))
+ − 175
{
+ − 176
$this->report_query($q);
+ − 177
grinding_halt('SQL Injection attempt', '<p>Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.</p><p>Query was:</p><pre>'.htmlspecialchars($q).'</pre>');
+ − 178
}
+ − 179
$r = mysql_unbuffered_query($q, $this->_conn);
+ − 180
$this->latest_result = $r;
+ − 181
$this->disable_errorhandler();
+ − 182
return $r;
+ − 183
}
+ − 184
+ − 185
/**
+ − 186
* Checks a SQL query for possible signs of injection attempts
+ − 187
* @param string $q the query to check
+ − 188
* @return bool true if query passed check, otherwise false
+ − 189
*/
+ − 190
+ − 191
function check_query($q, $debug = false)
+ − 192
{
+ − 193
if($debug) echo "\$db->check_query(): checking query: ".htmlspecialchars($q).'<br />'."\n";
+ − 194
$sz = strlen($q);
+ − 195
$quotechar = false;
+ − 196
$quotepos = 0;
+ − 197
$prev_is_quote = false;
+ − 198
$just_started = false;
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 199
for ( $i = 0; $i < strlen($q); $i++, $c = substr($q, $i, 1) )
1
+ − 200
{
+ − 201
$next = substr($q, $i+1, 1);
+ − 202
$next2 = substr($q, $i+2, 1);
+ − 203
$prev = substr($q, $i-1, 1);
+ − 204
$prev2 = substr($q, $i-2, 1);
+ − 205
if(isset($c) && in_array($c, Array('"', "'", '`')))
+ − 206
{
+ − 207
if($quotechar)
+ − 208
{
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 209
if (
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 210
( $quotechar == $c && $quotechar != $next && ( $quotechar != $prev || $just_started ) && $prev != '\\') ||
1
+ − 211
( $prev2 == '\\' && $prev == $quotechar && $quotechar == $c )
+ − 212
)
+ − 213
{
+ − 214
$quotechar = false;
+ − 215
if($debug) echo('$db->check_query(): just finishing a quote section, quoted string: '.htmlspecialchars(substr($q, $quotepos, $i - $quotepos + 1)) . '<br />');
+ − 216
$q = substr($q, 0, $quotepos) . 'SAFE_QUOTE' . substr($q, $i + 1, strlen($q));
+ − 217
if($debug) echo('$db->check_query(): Filtered query: '.$q.'<br />');
+ − 218
$i = $quotepos;
+ − 219
}
+ − 220
}
+ − 221
else
+ − 222
{
+ − 223
$quotechar = $c;
+ − 224
$quotepos = $i;
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 225
$just_started = true;
1
+ − 226
}
+ − 227
if($debug) echo '$db->check_query(): found quote char as pos: '.$i.'<br />';
+ − 228
continue;
+ − 229
}
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 230
$just_started = false;
1
+ − 231
}
+ − 232
if(substr(trim($q), strlen(trim($q))-1, 1) == ';') $q = substr(trim($q), 0, strlen(trim($q))-1);
+ − 233
for($i=0;$i<strlen($q);$i++,$c=substr($q, $i, 1))
+ − 234
{
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 235
if (
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 236
( ( $c == ';' && $i != $sz-1 ) || $c . substr($q, $i+1, 1) == '--' )
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 237
|| ( in_array($c, Array('"', "'", '`')) )
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 238
) // Don't permit semicolons in mid-query, and never allow comments
1
+ − 239
{
+ − 240
// Injection attempt!
+ − 241
if($debug)
+ − 242
{
+ − 243
$e = '';
+ − 244
for($j=$i-5;$j<$i+5;$j++)
+ − 245
{
+ − 246
if($j == $i) $e .= '<span style="color: red; text-decoration: underline;">' . $c . '</span>';
+ − 247
else $e .= $c;
+ − 248
}
+ − 249
echo 'Injection attempt caught at pos: '.$i.'<br />';
+ − 250
}
+ − 251
return false;
+ − 252
}
+ − 253
}
128
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 254
if ( preg_match('/[\s]+(SAFE_QUOTE|[\S]+)=\\1($|[\s]+)/', $q, $match) )
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 255
{
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 256
if ( $debug ) echo 'Found always-true test in query, injection attempt caught, match:<br />' . '<pre>' . print_r($match, true) . '</pre>';
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 257
return false;
01955bf53f96
Improved ban control page and allowed multiple entries/IP ranges; changed some parameters on jBox; user level changes are logged now
Dan
diff
changeset
+ − 258
}
1
+ − 259
return true;
+ − 260
}
+ − 261
+ − 262
/**
+ − 263
* Set the internal result pointer to X
+ − 264
* @param int $pos The number of the row
+ − 265
* @param resource $result The MySQL result resource - if not given, the latest cached query is assumed
+ − 266
* @return true on success, false on failure
+ − 267
*/
+ − 268
+ − 269
function sql_data_seek($pos, $result = false)
+ − 270
{
+ − 271
$this->enable_errorhandler();
+ − 272
if(!$result)
+ − 273
$result = $this->latest_result;
+ − 274
if(!$result)
+ − 275
{
+ − 276
$this->disable_errorhandler();
+ − 277
return false;
+ − 278
}
+ − 279
if(mysql_data_seek($result, $pos))
+ − 280
{
+ − 281
$this->disable_errorhandler();
+ − 282
return true;
+ − 283
}
+ − 284
else
+ − 285
{
+ − 286
$this->disable_errorhandler();
+ − 287
return false;
+ − 288
}
+ − 289
}
+ − 290
+ − 291
/**
+ − 292
* Reports a bad query to the admin
+ − 293
* @param string $query the naughty query
+ − 294
* @access private
+ − 295
*/
+ − 296
+ − 297
function report_query($query)
+ − 298
{
+ − 299
global $session;
+ − 300
if(is_object($session) && defined('ENANO_MAINSTREAM'))
+ − 301
$username = $session->username;
+ − 302
else
+ − 303
$username = 'Unavailable';
+ − 304
$query = $this->escape($query);
+ − 305
$q = $this->sql_query('INSERT INTO '.table_prefix.'logs(log_type, action, time_id, date_string, page_text, author, edit_summary)
+ − 306
VALUES(\'security\', \'sql_inject\', '.time().', \'\', \''.$query.'\', \''.$username.'\', \''.$_SERVER['REMOTE_ADDR'].'\');');
+ − 307
}
+ − 308
73
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 309
/**
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 310
* Returns the ID of the row last inserted.
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 311
* @return int
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 312
*/
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 313
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 314
function insert_id()
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 315
{
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 316
return @mysql_insert_id();
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 317
}
0a74676a2f2f
Made the move to Loch Ness, and got some basic page grouping functionality working. TODO: fix some UI issues in Javascript ACL editor and change non-JS ACL editor to work with page groups too
Dan
diff
changeset
+ − 318
1
+ − 319
function fetchrow($r = false) {
+ − 320
$this->enable_errorhandler();
+ − 321
if(!$this->_conn) return false;
+ − 322
if(!$r) $r = $this->latest_result;
+ − 323
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 324
$row = mysql_fetch_assoc($r);
+ − 325
$this->disable_errorhandler();
+ − 326
return $row;
+ − 327
}
+ − 328
+ − 329
function fetchrow_num($r = false) {
+ − 330
$this->enable_errorhandler();
+ − 331
if(!$r) $r = $this->latest_result;
+ − 332
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 333
$row = mysql_fetch_row($r);
+ − 334
$this->disable_errorhandler();
+ − 335
return $row;
+ − 336
}
+ − 337
+ − 338
function numrows($r = false) {
+ − 339
$this->enable_errorhandler();
+ − 340
if(!$r) $r = $this->latest_result;
+ − 341
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 342
$n = mysql_num_rows($r);
+ − 343
$this->disable_errorhandler();
+ − 344
return $n;
+ − 345
}
+ − 346
+ − 347
function escape($str)
+ − 348
{
+ − 349
$this->enable_errorhandler();
+ − 350
$str = mysql_real_escape_string($str);
+ − 351
$this->disable_errorhandler();
+ − 352
return $str;
+ − 353
}
+ − 354
+ − 355
function free_result($result = false)
+ − 356
{
+ − 357
$this->enable_errorhandler();
+ − 358
if(!$result)
+ − 359
$result = $this->latest_result;
+ − 360
if(!$result)
+ − 361
{
+ − 362
$this->disable_errorhandler();
+ − 363
return null;
+ − 364
}
+ − 365
mysql_free_result($result);
+ − 366
$this->disable_errorhandler();
+ − 367
return null;
+ − 368
}
+ − 369
+ − 370
function close() {
+ − 371
dc_here('dbal: closing MySQL connection');
+ − 372
mysql_close($this->_conn);
+ − 373
unset($this->_conn);
+ − 374
}
+ − 375
+ − 376
// phpBB DBAL compatibility
+ − 377
function sql_fetchrow($r = false)
+ − 378
{
+ − 379
return $this->fetchrow($r);
+ − 380
}
+ − 381
function sql_freeresult($r = false)
+ − 382
{
+ − 383
if(!$this->_conn) return false;
+ − 384
if(!$r) $r = $this->latest_result;
+ − 385
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 386
mysql_free_result($r);
+ − 387
}
+ − 388
function sql_numrows($r = false)
+ − 389
{
+ − 390
if(!$this->_conn) return false;
+ − 391
if(!$r) $r = $this->latest_result;
+ − 392
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 393
return mysql_num_rows($r);
+ − 394
}
+ − 395
function sql_affectedrows($r = false, $f, $n)
+ − 396
{
+ − 397
if(!$this->_conn) return false;
+ − 398
if(!$r) $r = $this->latest_result;
+ − 399
if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+ − 400
return mysql_affected_rows();
+ − 401
}
+ − 402
+ − 403
function sql_type_cast(&$value)
+ − 404
{
+ − 405
if ( is_float($value) )
+ − 406
{
+ − 407
return doubleval($value);
+ − 408
}
+ − 409
if ( is_integer($value) || is_bool($value) )
+ − 410
{
+ − 411
return intval($value);
+ − 412
}
+ − 413
if ( is_string($value) || empty($value) )
+ − 414
{
+ − 415
return '\'' . $this->sql_escape_string($value) . '\'';
+ − 416
}
+ − 417
// uncastable var : let's do a basic protection on it to prevent sql injection attempt
+ − 418
return '\'' . $this->sql_escape_string(htmlspecialchars($value)) . '\'';
+ − 419
}
+ − 420
+ − 421
function sql_statement(&$fields, $fields_inc='')
+ − 422
{
+ − 423
// init result
+ − 424
$this->sql_fields = $this->sql_values = $this->sql_update = '';
+ − 425
if ( empty($fields) && empty($fields_inc) )
+ − 426
{
+ − 427
return;
+ − 428
}
+ − 429
+ − 430
// process
+ − 431
if ( !empty($fields) )
+ − 432
{
+ − 433
$first = true;
+ − 434
foreach ( $fields as $field => $value )
+ − 435
{
+ − 436
// field must contain a field name
+ − 437
if ( !empty($field) && is_string($field) )
+ − 438
{
+ − 439
$value = $this->sql_type_cast($value);
+ − 440
$this->sql_fields .= ( $first ? '' : ', ' ) . $field;
+ − 441
$this->sql_values .= ( $first ? '' : ', ' ) . $value;
+ − 442
$this->sql_update .= ( $first ? '' : ', ' ) . $field . ' = ' . $value;
+ − 443
$first = false;
+ − 444
}
+ − 445
}
+ − 446
}
+ − 447
if ( !empty($fields_inc) )
+ − 448
{
+ − 449
foreach ( $fields_inc as $field => $indent )
+ − 450
{
+ − 451
if ( $indent != 0 )
+ − 452
{
+ − 453
$this->sql_update .= (empty($this->sql_update) ? '' : ', ') . $field . ' = ' . $field . ($indent < 0 ? ' - ' : ' + ') . abs($indent);
+ − 454
}
+ − 455
}
+ − 456
}
+ − 457
}
+ − 458
+ − 459
function sql_stack_reset($id='')
+ − 460
{
+ − 461
if ( empty($id) )
+ − 462
{
+ − 463
$this->sql_stack_fields = array();
+ − 464
$this->sql_stack_values = array();
+ − 465
}
+ − 466
else
+ − 467
{
+ − 468
$this->sql_stack_fields[$id] = array();
+ − 469
$this->sql_stack_values[$id] = array();
+ − 470
}
+ − 471
}
+ − 472
+ − 473
function sql_stack_statement(&$fields, $id='')
+ − 474
{
+ − 475
$this->sql_statement($fields);
+ − 476
if ( empty($id) )
+ − 477
{
+ − 478
$this->sql_stack_fields = $this->sql_fields;
+ − 479
$this->sql_stack_values[] = '(' . $this->sql_values . ')';
+ − 480
}
+ − 481
else
+ − 482
{
+ − 483
$this->sql_stack_fields[$id] = $this->sql_fields;
+ − 484
$this->sql_stack_values[$id][] = '(' . $this->sql_values . ')';
+ − 485
}
+ − 486
}
+ − 487
+ − 488
function sql_stack_insert($table, $transaction=false, $line='', $file='', $break_on_error=true, $id='')
+ − 489
{
+ − 490
if ( (empty($id) && empty($this->sql_stack_values)) || (!empty($id) && empty($this->sql_stack_values[$id])) )
+ − 491
{
+ − 492
return false;
+ − 493
}
+ − 494
switch( SQL_LAYER )
+ − 495
{
+ − 496
case 'mysql':
+ − 497
case 'mysql4':
+ − 498
if ( empty($id) )
+ − 499
{
+ − 500
$sql = 'INSERT INTO ' . $table . '
+ − 501
(' . $this->sql_stack_fields . ') VALUES ' . implode(",\n", $this->sql_stack_values);
+ − 502
}
+ − 503
else
+ − 504
{
+ − 505
$sql = 'INSERT INTO ' . $table . '
+ − 506
(' . $this->sql_stack_fields[$id] . ') VALUES ' . implode(",\n", $this->sql_stack_values[$id]);
+ − 507
}
+ − 508
$this->sql_stack_reset($id);
+ − 509
return $this->sql_query($sql, $transaction, $line, $file, $break_on_error);
+ − 510
break;
+ − 511
default:
+ − 512
$count_sql_stack_values = empty($id) ? count($this->sql_stack_values) : count($this->sql_stack_values[$id]);
+ − 513
$result = !empty($count_sql_stack_values);
+ − 514
for ( $i = 0; $i < $count_sql_stack_values; $i++ )
+ − 515
{
+ − 516
if ( empty($id) )
+ − 517
{
+ − 518
$sql = 'INSERT INTO ' . $table . '
+ − 519
(' . $this->sql_stack_fields . ') VALUES ' . $this->sql_stack_values[$i];
+ − 520
}
+ − 521
else
+ − 522
{
+ − 523
$sql = 'INSERT INTO ' . $table . '
+ − 524
(' . $this->sql_stack_fields[$id] . ') VALUES ' . $this->sql_stack_values[$id][$i];
+ − 525
}
+ − 526
$result &= $this->sql_query($sql, $transaction, $line, $file, $break_on_error);
+ − 527
}
+ − 528
$this->sql_stack_reset($id);
+ − 529
return $result;
+ − 530
break;
+ − 531
}
+ − 532
}
+ − 533
+ − 534
function sql_subquery($field, $sql, $line='', $file='', $break_on_error=true, $type=TYPE_INT)
+ − 535
{
+ − 536
// sub-queries doable
+ − 537
$this->sql_get_version();
+ − 538
if ( !in_array(SQL_LAYER, array('mysql', 'mysql4')) || (($this->sql_version[0] + ($this->sql_version[1] / 100)) >= 4.01) )
+ − 539
{
+ − 540
return $sql;
+ − 541
}
+ − 542
+ − 543
// no sub-queries
+ − 544
$ids = array();
+ − 545
$result = $this->sql_query(trim($sql), false, $line, $file, $break_on_error);
+ − 546
while ( $row = $this->sql_fetchrow($result) )
+ − 547
{
+ − 548
$ids[] = $type == TYPE_INT ? intval($row[$field]) : '\'' . $this->sql_escape_string($row[$field]) . '\'';
+ − 549
}
+ − 550
$this->sql_freeresult($result);
+ − 551
return empty($ids) ? 'NULL' : implode(', ', $ids);
+ − 552
}
+ − 553
+ − 554
function sql_col_id($expr, $alias)
+ − 555
{
+ − 556
$this->sql_get_version();
+ − 557
return in_array(SQL_LAYER, array('mysql', 'mysql4')) && (($this->sql_version[0] + ($this->sql_version[1] / 100)) <= 4.01) ? $alias : $expr;
+ − 558
}
+ − 559
+ − 560
function sql_get_version()
+ − 561
{
+ − 562
if ( empty($this->sql_version) )
+ − 563
{
+ − 564
$this->sql_version = array(0, 0, 0);
+ − 565
switch ( SQL_LAYER )
+ − 566
{
+ − 567
case 'mysql':
+ − 568
case 'mysql4':
+ − 569
if ( function_exists('mysql_get_server_info') )
+ − 570
{
+ − 571
$lo_version = explode('-', mysql_get_server_info());
+ − 572
$this->sql_version = explode('.', $lo_version[0]);
+ − 573
$this->sql_version = array(intval($this->sql_version[0]), intval($this->sql_version[1]), intval($this->sql_version[2]), $lo_version[1]);
+ − 574
}
+ − 575
break;
+ − 576
+ − 577
case 'postgresql':
+ − 578
case 'mssql':
+ − 579
case 'mssql-odbc':
+ − 580
default:
+ − 581
break;
+ − 582
}
+ − 583
}
+ − 584
return $this->sql_version;
+ − 585
}
+ − 586
+ − 587
function sql_error()
+ − 588
{
+ − 589
if ( $this->_conn )
+ − 590
{
+ − 591
return mysql_error();
+ − 592
}
+ − 593
else
+ − 594
{
+ − 595
return array();
+ − 596
}
+ − 597
}
+ − 598
function sql_escape_string($t)
+ − 599
{
+ − 600
return mysql_real_escape_string($t);
+ − 601
}
+ − 602
function sql_close()
+ − 603
{
+ − 604
$this->close();
+ − 605
}
+ − 606
function sql_fetchrowset($query_id = 0)
+ − 607
{
+ − 608
if( !$query_id )
+ − 609
{
+ − 610
$query_id = $this->query_result;
+ − 611
}
+ − 612
+ − 613
if( $query_id )
+ − 614
{
+ − 615
unset($this->rowset[$query_id]);
+ − 616
unset($this->row[$query_id]);
+ − 617
+ − 618
while($this->rowset[$query_id] = mysql_fetch_array($query_id, MYSQL_ASSOC))
+ − 619
{
+ − 620
$result[] = $this->rowset[$query_id];
+ − 621
}
+ − 622
+ − 623
return $result;
+ − 624
}
+ − 625
else
+ − 626
{
+ − 627
return false;
+ − 628
}
+ − 629
}
+ − 630
}
+ − 631
+ − 632
?>