1<?php 2 3/** 4 * Observium 5 * 6 * This file is part of Observium. 7 * 8 * @package observium 9 * @subpackage db 10 * @copyright (C) 2006-2013 Adam Armstrong, (C) 2013-2019 Observium Limited 11 * 12 */ 13 14/* Here common DB functions which uses calls to specific api functions */ 15 16// Initial variables 17$db_stats = array('insert' => 0, 'insert_sec' => 0, 18 'update' => 0, 'update_sec' => 0, 19 'delete' => 0, 'delete_sec' => 0, 20 'fetchcell' => 0, 'fetchcell_sec' => 0, 21 'fetchrow' => 0, 'fetchrow_sec' => 0, 22 'fetchrows' => 0, 'fetchrows_sec' => 0, 23 'fetchcol' => 0, 'fetchcol_sec' => 0); 24 25// Include DB api. Default and recommended mysqli, legacy mysql 26switch (OBS_DB_EXTENSION) 27{ 28 case 'mysql': 29 if (@function_exists('mysql_connect')) 30 { 31 require($config['install_dir'] . '/includes/db/mysql.inc.php'); 32 } else { 33 echo('ERROR. PHP mysql extension not exist. Execution is stopped.' . PHP_EOL); 34 exit(2); 35 } 36 break; 37 case 'mysqli': 38 default: 39 if (@function_exists('mysqli_connect')) 40 { 41 require($config['install_dir'] . '/includes/db/mysqli.inc.php'); 42 } else { 43 echo('ERROR. PHP mysqli extension not exist. Execution is stopped.' . PHP_EOL); 44 exit(2); 45 } 46} 47 48/** 49 * Provides server status information 50 * 51 * @param string $scope GLOBAL or SESSION variable scope modifier 52 * @return array Array with server status variables 53 */ 54function dbShowStatus($scope = 'SESSION') 55{ 56 switch ($scope) 57 { 58 case 'GLOBAL': 59 $sql = 'SHOW GLOBAL STATUS;'; 60 break; 61 default: 62 $sql = 'SHOW STATUS;'; 63 } 64 65 $rows = array(); 66 foreach (dbFetchRows($sql) as $row) 67 { 68 $rows[$row['Variable_name']] = $row['Value']; 69 } 70 71 return $rows; 72} 73 74/** 75 * Shows the values of MySQL system variables 76 * 77 * @param string $scope GLOBAL or SESSION variable scope modifier 78 * @param string $where WHERE or LIKE clause 79 * @return array Array with variables 80 */ 81function dbShowVariables($scope = 'SESSION', $where = '') 82{ 83 switch ($scope) 84 { 85 case 'GLOBAL': 86 $sql = 'SHOW GLOBAL VARIABLES'; 87 break; 88 default: 89 $sql = 'SHOW VARIABLES'; 90 } 91 if (strlen($where)) 92 { 93 $sql .= ' ' . $where; 94 } 95 96 $rows = array(); 97 foreach (dbFetchRows($sql) as $row) 98 { 99 $rows[$row['Variable_name']] = $row['Value']; 100 } 101 102 return $rows; 103} 104 105/** 106 * Provides table index list 107 * 108 * @param string $table Table name 109 * @param string $index_name Index name (if empty get all indexes) 110 * @return array Array with table indexes: array()->$key_name->$column_name 111 */ 112function dbShowIndexes($table, $index_name = NULL) 113{ 114 $table = dbEscape($table); 115 $params = array(); 116 if ($index_name) 117 { 118 $sql = 'SHOW INDEX FROM `'.$table.'` WHERE `Key_name` = ?;'; 119 $params[] = $index_name; 120 } else { 121 $sql = 'SHOW INDEX FROM `'.$table.'`;'; 122 } 123 124 $rows = array(); 125 foreach (dbFetchRows($sql, $params) as $row) 126 { 127 $rows[$row['Key_name']][$row['Column_name']] = $row; 128 } 129 130 return $rows; 131} 132 133/* 134 * Performs a query using the given string. 135 * Used by the other _query functions. 136 * */ 137function dbQuery($sql, $parameters = array(), $print_query = FALSE) 138{ 139 global $fullSql; 140 141 $fullSql = dbMakeQuery($sql, $parameters); 142 143 if (OBS_DEBUG > 0 || $print_query) 144 { 145 // Pre query debug output 146 if (is_cli()) 147 { 148 $debug_sql = explode(PHP_EOL, $fullSql); 149 print_message(PHP_EOL.'SQL[%y' . implode('%n'.PHP_EOL.'%y', $debug_sql) . '%n]', 'console', FALSE); 150 } else { 151 print_sql($fullSql); 152 } 153 } 154 155 if (OBS_DEBUG > 0 || $GLOBALS['config']['profile_sql']) 156 { 157 $time_start = microtime(true); 158 } 159 160 $result = dbCallQuery($fullSql); // sets $this->result 161 162 if (OBS_DEBUG > 0 || $GLOBALS['config']['profile_sql']) 163 { 164 $runtime = number_format(microtime(true) - $time_start, 8); 165 $debug_msg .= 'SQL RUNTIME['.($runtime > 0.05 ? '%r' : '%g').$runtime.'s%n]'; 166 if ($GLOBALS['config']['profile_sql']) 167 { 168 #fwrite($this->logFile, date('Y-m-d H:i:s') . "\n" . $fullSql . "\n" . number_format($time_end - $time_start, 8) . " seconds\n\n"); 169 $GLOBALS['sql_profile'][] = array('sql' => $fullSql, 'time' => $runtime); 170 } 171 } 172 173 if (OBS_DEBUG > 0) 174 { 175 if ($result === FALSE && (error_reporting() & 1)) 176 { 177 $error_msg = 'Error in query: (' . dbError() . ') ' . dbErrorNo(); 178 $debug_msg .= PHP_EOL . 'SQL ERROR[%r'.$error_msg.'%n]'; 179 } 180 if ($warnings = dbWarnings()) 181 { 182 $debug_msg .= PHP_EOL . "SQL WARNINGS[\n %m" . implode("%n\n %m", $warnings) . "%n\n]"; 183 } 184 185 if (is_cli()) 186 { 187 if (OBS_DEBUG > 1) 188 { 189 $rows = dbAffectedRows(); 190 $debug_msg = 'ROWS['.($rows < 1 ? '%r' : '%g').$rows.'%n]'.PHP_EOL.$debug_msg; 191 } 192 // After query debug output for cli 193 print_message($debug_msg, 'console', FALSE); 194 } else { 195 print_error($error_msg); 196 } 197 } 198 199 if ($result === FALSE && isset($GLOBALS['config']['db']['debug']) && $GLOBALS['config']['db']['debug']) 200 { 201 logfile('db.log', 'Failed dbQuery (#' . dbErrorNo() . ' - ' . dbError() . '), Query: ' . $fullSql); 202 } 203 204 return $result; 205} 206 207/* 208 * This is intended to be the method used for large result sets. 209 * It is intended to return an iterator, and act upon buffered data. 210 * */ 211function dbFetch($sql, $parameters = array(), $print_query = FALSE) 212{ 213 return dbFetchRows($sql, $parameters, $print_query); 214} 215 216/* 217 * This method is quite different from fetchCell(), actually 218 * It fetches one cell from each row and places all the values in 1 array 219 * */ 220function dbFetchColumn($sql, $parameters = array(), $print_query = FALSE) 221{ 222 $time_start = microtime(true); 223 $cells = array(); 224 foreach (dbFetchRows($sql, $parameters, $print_query) as $row) 225 { 226 $cells[] = array_shift($row); 227 } 228 $time_end = microtime(true); 229 230 $GLOBALS['db_stats']['fetchcol_sec'] += number_format($time_end - $time_start, 8); 231 $GLOBALS['db_stats']['fetchcol']++; 232 233 return $cells; 234} 235 236/* 237 * Should be passed a query that fetches two fields 238 * The first will become the array key 239 * The second the key's value 240 */ 241function dbFetchKeyValue($sql, $parameters = array(), $print_query) 242{ 243 $data = array(); 244 foreach (dbFetchRows($sql, $parameters, $print_query) as $row) 245 { 246 $key = array_shift($row); 247 if (sizeof($row) == 1) 248 { // if there were only 2 fields in the result 249 // use the second for the value 250 $data[$key] = array_shift($row); 251 } else { // if more than 2 fields were fetched 252 // use the array of the rest as the value 253 $data[$key] = $row; 254 } 255 } 256 257 return $data; 258} 259 260/* 261 * Passed an array and a table name, it attempts to insert the data into the table. 262 * Check for boolean false to determine whether insert failed 263 * */ 264function dbInsert($data, $table, $print_query = FALSE) 265{ 266 global $fullSql; 267 268 // the following block swaps the parameters if they were given in the wrong order. 269 // it allows the method to work for those that would rather it (or expect it to) 270 // follow closer with SQL convention: 271 // insert into the TABLE this DATA 272 if (is_string($data) && is_array($table)) 273 { 274 $tmp = $data; 275 $data = $table; 276 $table = $tmp; 277 278 print_debug('Parameters passed to dbInsert() were in reverse order.'); 279 } 280 281 $sql = 'INSERT INTO `' . $table . '` (`' . implode('`,`', array_keys($data)) . '`) VALUES (' . implode(',', dbPlaceHolders($data)) . ')'; 282 283 $time_start = microtime(true); 284 //dbBeginTransaction(); 285 $result = dbQuery($sql, $data, $print_query); 286 if ($result) 287 { 288 // This should return true if insert succeeded, but no ID was generated 289 $id = dbLastID(); 290 //dbCommitTransaction(); 291 } else { 292 //dbRollbackTransaction(); 293 $id = FALSE; 294 } 295 296 $time_end = microtime(true); 297 $GLOBALS['db_stats']['insert_sec'] += number_format($time_end - $time_start, 8); 298 $GLOBALS['db_stats']['insert']++; 299 300 return $id; 301} 302 303/** 304 * Passed an array and a table name, it attempts to insert the data into the table. 305 * Check for boolean false to determine whether insert failed 306 */ 307function dbInsertMulti($data, $table, $columns = NULL, $print_query = FALSE) 308{ 309 global $fullSql; 310 311 // the following block swaps the parameters if they were given in the wrong order. 312 // it allows the method to work for those that would rather it (or expect it to) 313 // follow closer with SQL convention: 314 // insert into the TABLE this DATA 315 if (is_string($data) && is_array($table)) 316 { 317 $tmp = $data; 318 $data = $table; 319 $table = $tmp; 320 321 print_debug('Parameters passed to dbInsertMulti() were in reverse order.'); 322 } 323 324 // Detect if data is multiarray 325 $first_data = reset($data); 326 if (!is_array($first_data)) 327 { 328 $first_data = $data; 329 $data = array($data); 330 } 331 332 // Columns, if not passed use keys from first element 333 if (empty($columns)) 334 { 335 $columns = array_keys($first_data); 336 } 337 338 $values = array(); 339 // Multiarray data 340 foreach ($data as $entry) 341 { 342 $entry = dbPrepareData($entry); // Escape data 343 344 // Keep same columns order as in first entry 345 $entries = array(); 346 foreach ($columns as $column) 347 { 348 $entries[$column] = $entry[$column]; 349 } 350 351 $values[] = '(' . implode(',', $entries) . ')'; 352 } 353 354 $sql = 'INSERT INTO `' . $table . '` (`' . implode('`,`', $columns) . '`) VALUES ' . implode(',', $values); 355 356 $time_start = microtime(true); 357 //dbBeginTransaction(); 358 $result = dbQuery($sql, NULL, $print_query); 359 if ($result) 360 { 361 // This should return true if insert succeeded, but no ID was generated 362 $id = dbLastID(); 363 //dbCommitTransaction(); 364 } else { 365 //dbRollbackTransaction(); 366 $id = FALSE; 367 } 368 369 $time_end = microtime(true); 370 $GLOBALS['db_stats']['insert_sec'] += number_format($time_end - $time_start, 8); 371 $GLOBALS['db_stats']['insert']++; 372 373 return $id; 374} 375 376/* 377 * Passed an array, table name, WHERE clause, and placeholder parameters, it attempts to update a record. 378 * Returns the number of affected rows 379 * */ 380function dbUpdate($data, $table, $where = NULL, $parameters = array(), $print_query = FALSE) 381{ 382 global $fullSql; 383 384 // the following block swaps the parameters if they were given in the wrong order. 385 // it allows the method to work for those that would rather it (or expect it to) 386 // follow closer with SQL convention: 387 // update the TABLE with this DATA 388 if (is_string($data) && is_array($table)) 389 { 390 $tmp = $data; 391 $data = $table; 392 $table = $tmp; 393 //trigger_error('QDB - The first two parameters passed to update() were in reverse order, but it has been allowed', E_USER_NOTICE); 394 } 395 396 // need field name and placeholder value 397 // but how merge these field placeholders with actual $parameters array for the WHERE clause 398 $sql = 'UPDATE `' . $table . '` set '; 399 foreach ($data as $key => $value) 400 { 401 $sql .= "`".$key."` ". '=:' . $key . ','; 402 } 403 $sql = substr($sql, 0, -1); // strip off last comma 404 405 if ($where) 406 { 407 // Remove WHERE clause at the beginning and ; at end 408 $where = preg_replace(array('/^\s*WHERE\s+/i', '/\s*;\s*$/'), '', $where); 409 $sql .= ' WHERE ' . $where; 410 $data = array_merge($data, $parameters); 411 } 412 413 $time_start = microtime(true); 414 if (dbQuery($sql, $data, $print_query)) 415 { 416 $return = dbAffectedRows(); 417 } else { 418 $return = FALSE; 419 } 420 $time_end = microtime(true); 421 $GLOBALS['db_stats']['update_sec'] += number_format($time_end - $time_start, 8); 422 $GLOBALS['db_stats']['update']++; 423 424 return $return; 425} 426 427/** 428 * Passed an array and a table name, it attempts to update the data in the table. 429 * Check for boolean false to determine whether update failed 430 * This is really INSERT with ODKU update 431 * For key really better use only ID field! 432 * https://stackoverflow.com/questions/25674737/mysql-update-multiple-rows-with-different-values-in-one-query/25674827 433 */ 434function dbUpdateMulti($data, $table, $columns = NULL, $print_query = FALSE) 435{ 436 global $fullSql; 437 438 // the following block swaps the parameters if they were given in the wrong order. 439 // it allows the method to work for those that would rather it (or expect it to) 440 // follow closer with SQL convention: 441 // insert into the TABLE this DATA 442 if (is_string($data) && is_array($table)) 443 { 444 $tmp = $data; 445 $data = $table; 446 $table = $tmp; 447 448 print_debug('Parameters passed to dbUpdateMulti() were in reverse order.'); 449 } 450 451 // Detect if data is multiarray 452 $first_data = reset($data); 453 if (!is_array($first_data)) 454 { 455 $first_data = $data; 456 $data = array($data); 457 } 458 459 // Columns, if not passed use keys from first element 460 $all_columns = array_keys($first_data); // All columns data and UNIQUE indexes 461 if (!empty($columns)) 462 { 463 // Update only passed columns from param 464 $update_columns = $columns; 465 } else { 466 // Fallbak for all columns (also indexes), 467 // this is normal, UNIQUE indexes not updated anyway 468 $update_columns = $all_columns; 469 } 470 471 // Columns which will updated 472 foreach ($update_columns as $key) 473 { 474 $update_keys[] = '`'.$key.'`=VALUES(`'.$key.'`)'; 475 } 476 477 $values = array(); 478 // Multiarray data 479 foreach ($data as $entry) 480 { 481 $entry = dbPrepareData($entry); // Escape data 482 483 // Keep same columns order as in first entry 484 $entries = array(); 485 foreach ($all_columns as $column) 486 { 487 $entries[$column] = $entry[$column]; 488 } 489 490 $values[] = '(' . implode(',', $entries) . ')'; 491 } 492 493 $sql = 'INSERT INTO `' . $table . '` (`' . implode('`,`', $all_columns) . '`) VALUES ' . implode(',', $values); 494 495 // This is only way for update multiple rows at once 496 $sql .= ' ON DUPLICATE KEY UPDATE ' . implode(',', $update_keys); 497 498 $time_start = microtime(true); 499 //dbBeginTransaction(); 500 if (dbQuery($sql, NULL, $print_query)) 501 { 502 $return = dbAffectedRows(); // This value should be divided into two for innodb 503 } else { 504 $return = FALSE; 505 } 506 507 $time_end = microtime(true); 508 $GLOBALS['db_stats']['update_sec'] += number_format($time_end - $time_start, 8); 509 $GLOBALS['db_stats']['update']++; 510 511 return $return; 512} 513 514function dbExist($table, $where = NULL, $parameters = array(), $print_query = FALSE) 515{ 516 $sql = 'SELECT EXISTS (SELECT 1 FROM `' . $table . '`'; 517 if ($where) 518 { 519 // Remove WHERE clause at the beginning and ; at end 520 $where = preg_replace(array('/^\s*WHERE\s+/i', '/\s*;\s*$/'), '', $where); 521 $sql .= ' WHERE ' . $where; 522 } 523 $sql .= ')'; 524 525 $return = dbFetchCell($sql, $parameters, $print_query); 526 //print_vars($return); 527 528 return (bool)$return; 529} 530 531function dbDelete($table, $where = NULL, $parameters = array(), $print_query = FALSE) 532{ 533 $sql = 'DELETE FROM `' . $table.'`'; 534 if ($where) 535 { 536 // Remove WHERE clause at the beginning and ; at end 537 $where = preg_replace(array('/^\s*WHERE\s+/i', '/\s*;\s*$/'), '', $where); 538 $sql .= ' WHERE ' . $where; 539 } 540 541 $time_start = microtime(true); 542 if (dbQuery($sql, $parameters, $print_query)) 543 { 544 $return = dbAffectedRows(); 545 } else { 546 $return = FALSE; 547 } 548 $time_end = microtime(true); 549 $GLOBALS['db_stats']['delete_sec'] += number_format($time_end - $time_start, 8); 550 $GLOBALS['db_stats']['delete']++; 551 552 return $return; 553} 554 555/* 556 * This combines a query and parameter array into a final query string for execution 557 * PDO drivers don't need to use this 558 */ 559function dbMakeQuery($sql, $parameters) 560{ 561 // bypass extra logic if we have no parameters 562 563 if (sizeof($parameters) == 0) 564 { 565 return $sql; 566 } 567 568 $parameters = dbPrepareData($parameters); 569 // separate the two types of parameters for easier handling 570 $questionParams = array(); 571 $namedParams = array(); 572 foreach ($parameters as $key => $value) 573 { 574 if (is_numeric($key)) 575 { 576 $questionParams[] = $value; 577 } else { 578 $namedParams[':' . $key] = $value; 579 } 580 } 581 582 if (count($namedParams) == 0) 583 { 584 // use simple pattern if named params not used (this broke some queries) 585 $pattern = '/(\?)/'; 586 } else { 587 // sort namedParams in reverse to stop substring squashing 588 krsort($namedParams); 589 // full pattern 590 $pattern = '/(\?|:[a-zA-Z0-9_-]+)/'; 591 } 592 593 // split on question-mark and named placeholders 594 $result = preg_split($pattern, $sql, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE); 595 596 // every-other item in $result will be the placeholder that was found 597 598 $query = ''; 599 for ($i = 0; $i < sizeof($result); $i+=2) 600 { 601 $query .= $result[$i]; 602 603 $j = $i+1; 604 if (array_key_exists($j, $result)) 605 { 606 $test = $result[$j]; 607 if ($test == '?') 608 { 609 $query .= array_shift($questionParams); 610 } else { 611 $query .= $namedParams[$test]; 612 } 613 } 614 } 615 616 return $query; 617} 618 619function dbPrepareData($data) 620{ 621 $values = array(); 622 623 foreach ($data as $key=>$value) 624 { 625 $escape = true; 626 // don't quote or esc if value is an array, we treat it 627 // as a "decorator" that tells us not to escape the 628 // value contained in the array IF there is one item in the array 629 if (is_array($value) && !is_object($value)) 630 { 631 if (count($value) == 1) 632 { 633 $escape = false; 634 $value = array_shift($value); 635 } else { 636 // if this is a multi-value array, implode this as it's probably 637 // (hopefully) used in an IN statement. 638 $escape = false; // we'll escape on our own, thanks. 639 // escape each entry by itself, unfortunately requires an extra array 640 // but implode() can't first escape each string, of course. 641 foreach ($value as $entry) 642 { 643 $escaped[] = "'" . dbEscape($entry) . "'"; 644 } 645 $value = implode(",", $escaped); 646 } 647 } 648 649 // it's not right to worry about invalid fields in this method because we may be operating on fields 650 // that are aliases, or part of other tables through joins 651 //if (!in_array($key, $columns)) // skip invalid fields 652 // continue; 653 if ($escape) 654 { 655 $values[$key] = "'" . dbEscape($value) . "'"; 656 } else { 657 $values[$key] = $value; 658 } 659 } 660 661 return $values; 662} 663 664/* 665 * Given a data array, this returns an array of placeholders 666 * These may be question marks, or ":email" type 667 */ 668function dbPlaceHolders($values) 669{ 670 $data = array(); 671 foreach ($values as $key => $value) 672 { 673 if (is_numeric($key)) 674 { 675 $data[] = '?'; 676 } else { 677 $data[] = ':' . $key; 678 } 679 } 680 return $data; 681} 682 683/** 684 * This function generates WHERE condition string from array with values 685 * NOTE, value should be exploded by comma before use generate_query_values(), for example in get_vars() 686 * 687 * @param mixed $value Values 688 * @param string $column Table column name 689 * @param string $condition Compare condition, known: =, !=, NOT, NULL, NOT NULL, LIKE (and variants %LIKE%, %LIKE, LIKE%) 690 * @param bool $leading_and Add leading AND to result query 691 * @return string Generated query 692 */ 693function generate_query_values($value, $column, $condition = NULL, $leading_and = TRUE) 694{ 695 //if (!is_array($value)) { $value = explode(',', $value); } 696 if (!is_array($value)) { $value = array((string)$value); } 697 $column = '`' . str_replace(array('`', '.'), array('', '`.`'), $column) . '`'; // I.column -> `I`.`column` 698 $condition = ($condition === TRUE ? 'LIKE' : strtoupper(trim($condition))); 699 if (str_contains($condition, ['NOT', '!='])) 700 { 701 $negative = TRUE; 702 $condition = str_replace(array('NOT', '!=', ' '), '', $condition); 703 } else { 704 $negative = FALSE; 705 } 706 707 $search = array('%', '_'); 708 $replace = array('\%', '\_'); 709 $values = array(); 710 switch ($condition) 711 { 712 // Use LIKE condition 713 case 'LIKE': 714 // Replace (* by %) and (? by _) only for LIKE condition 715 $search[] = '*'; // any string 716 $replace[] = '%'; 717 $search[] = '?'; // any single char 718 $replace[] = '_'; 719 case '%LIKE%': 720 case '%LIKE': 721 case 'LIKE%': 722 if ($negative) { $implode = ' AND '; $like = ' NOT LIKE '; } 723 else { $implode = ' OR '; $like = ' LIKE '; } 724 foreach ($value as $v) 725 { 726 if ($v === '*') 727 { 728 $values = array("ISNULL($column, 1)" . $like . "'%'"); 729 break; 730 } 731 else if ($v === '') 732 { 733 $values[] = "ISNULL($column, '')" . $like . "''"; 734 } else { 735 $v = dbEscape($v); // Escape BEFORE replace! 736 $v = str_replace($search, $replace, $v); 737 $v = str_replace('LIKE', $v, $condition); 738 $values[] = $column . $like . "'" . $v . "'"; 739 } 740 } 741 $values = array_unique($values); // Removes duplicate values 742 if (count($values)) 743 { 744 $where = ' AND (' . implode($implode, $values) . ')'; 745 } else { 746 // Empty values 747 $where = ' AND '; 748 $where .= $negative ? '1' : '0'; 749 } 750 break; 751 // Use NULL condition 752 case 'NULL': 753 $value = array_shift($value); 754 $value = ($negative) ? !$value : (bool)$value; // When required negative null condition (NOT NULL), reverse $value sign 755 //r($value); 756 if ($value) { 757 $where = ' AND ' . $column . ' IS NULL'; 758 } else { 759 $where = ' AND ' . $column . ' IS NOT NULL'; 760 } 761 break; 762 // Use IN condition 763 default: 764 $where = ''; 765 foreach ($value as $v) 766 { 767 if ($v == OBS_VAR_UNSET || $v === '') 768 { 769 $add_null = TRUE; // Add check NULL values at end 770 $values[] = "''"; 771 } else { 772 $values[] = "'" . dbEscape($v) . "'"; 773 } 774 } 775 $count = count($values); 776 if ($count == 1) 777 { 778 $where .= $column . ($negative ? ' != ' : ' = ') . $values[0]; 779 } 780 else if ($count) 781 { 782 $values = array_unique($values); // Removes duplicate values 783 $where .= $column . ($negative ? ' NOT IN (' : ' IN (') . implode(',', $values) . ')'; 784 } else { 785 // Empty values 786 $where = $negative ? '1' : '0'; 787 } 788 if ($add_null) 789 { 790 // Add search for empty values 791 if ($negative) 792 { 793 $where .= " AND $column IS NOT NULL"; 794 } else { 795 $where .= " OR $column IS NULL"; 796 } 797 $where = " AND ($where)"; 798 } else { 799 $where = " AND " . $where; 800 } 801 break; 802 } 803 if(!$leading_and) { $where = preg_replace('/^(\ )+AND/', '', $where); } 804 805 return $where; 806} 807 808// EOF 809