mirror of
				https://github.com/librenms/librenms.git
				synced 2024-10-07 16:52:45 +00:00 
			
		
		
		
	
		
			
	
	
		
			555 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			555 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
|  | <?php | ||
|  | 
 | ||
|  | /* | ||
|  |  * dbFacile - A Database API that should have existed from the start | ||
|  |  * Version 0.4.3 | ||
|  |  * | ||
|  |  * This code is covered by the MIT license http://en.wikipedia.org/wiki/MIT_License | ||
|  |  * | ||
|  |  * By Alan Szlosek from http://www.greaterscope.net/projects/dbFacile | ||
|  |  * | ||
|  |  * The non-OO version of dbFacile. It's a bit simplistic, but gives you the | ||
|  |  * really useful bits in non-class form. | ||
|  |  * | ||
|  |  * Usage | ||
|  |  * 1. Connect to MySQL as you normally would ... this code uses an existing connection | ||
|  |  * 2. Use dbFacile as you normally would, without the object context | ||
|  |  * 3. Oh, and dbFetchAll() is now dbFetchRows() | ||
|  |  */ | ||
|  | 
 | ||
|  | /* | ||
|  |  * Performs a query using the given string. | ||
|  |  * Used by the other _query functions. | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbQuery($sql, $parameters=array()) { | ||
|  |     global $fullSql, $debug, $sql_debug, $console_color; | ||
|  |     $fullSql = dbMakeQuery($sql, $parameters); | ||
|  |     if ($debug) { | ||
|  |         if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) { | ||
|  |             print $console_color->convert("\nSQL[%y".$fullSql.'%n] '); | ||
|  |         } | ||
|  |         else { | ||
|  |             $sql_debug[] = $fullSql; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /* | ||
|  |         if($this->logFile) | ||
|  |         $time_start = microtime(true); | ||
|  |      */ | ||
|  | 
 | ||
|  |     $result = mysql_query($fullSql); | ||
|  |     // sets $this->result
 | ||
|  |     /* | ||
|  |         if($this->logFile) { | ||
|  |         $time_end = microtime(true); | ||
|  |         fwrite($this->logFile, date('Y-m-d H:i:s') . "\n" . $fullSql . "\n" . number_format($time_end - $time_start, 8) . " seconds\n\n"); | ||
|  |         } | ||
|  |      */ | ||
|  | 
 | ||
|  |     if ($result === false && (error_reporting() & 1)) { | ||
|  |         // aye. this gets triggers on duplicate Contact insert
 | ||
|  |         // trigger_error('QDB - Error in query: ' . $fullSql . ' : ' . mysql_error(), E_USER_WARNING);
 | ||
|  |     } | ||
|  | 
 | ||
|  |     return $result; | ||
|  | 
 | ||
|  | }//end dbQuery()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * Passed an array and a table name, it attempts to insert the data into the table. | ||
|  |  * Check for boolean false to determine whether insert failed | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbInsert($data, $table) { | ||
|  |     global $fullSql; | ||
|  |     global $db_stats; | ||
|  |     // the following block swaps the parameters if they were given in the wrong order.
 | ||
|  |     // it allows the method to work for those that would rather it (or expect it to)
 | ||
|  |     // follow closer with SQL convention:
 | ||
|  |     // insert into the TABLE this DATA
 | ||
|  |     if (is_string($data) && is_array($table)) { | ||
|  |         $tmp   = $data; | ||
|  |         $data  = $table; | ||
|  |         $table = $tmp; | ||
|  |         // trigger_error('QDB - Parameters passed to insert() were in reverse order, but it has been allowed', E_USER_NOTICE);
 | ||
|  |     } | ||
|  | 
 | ||
|  |     $sql = 'INSERT INTO `'.$table.'` (`'.implode('`,`', array_keys($data)).'`)  VALUES ('.implode(',', dbPlaceHolders($data)).')'; | ||
|  | 
 | ||
|  |     $time_start = microtime(true); | ||
|  |     dbBeginTransaction(); | ||
|  |     $result = dbQuery($sql, $data); | ||
|  |     if ($result) { | ||
|  |         $id = mysql_insert_id(); | ||
|  |         dbCommitTransaction(); | ||
|  |         // return $id;
 | ||
|  |     } | ||
|  |     else { | ||
|  |         if ($table != 'Contact') { | ||
|  |             trigger_error('QDB - Insert failed.', E_USER_WARNING); | ||
|  |         } | ||
|  | 
 | ||
|  |         dbRollbackTransaction(); | ||
|  |         // $id = false;
 | ||
|  |     } | ||
|  | 
 | ||
|  |     // logfile($fullSql);
 | ||
|  |     $time_end                = microtime(true); | ||
|  |     $db_stats['insert_sec'] += number_format(($time_end - $time_start), 8); | ||
|  |     $db_stats['insert']++; | ||
|  | 
 | ||
|  |     return $id; | ||
|  | 
 | ||
|  | }//end dbInsert()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * Passed an array and a table name, it attempts to insert the data into the table. | ||
|  |  * $data is an array (rows) of key value pairs.  keys are fields.  Rows need to have same fields. | ||
|  |  * Check for boolean false to determine whether insert failed | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbBulkInsert($data, $table) { | ||
|  |     global $db_stats; | ||
|  |     // the following block swaps the parameters if they were given in the wrong order.
 | ||
|  |     // it allows the method to work for those that would rather it (or expect it to)
 | ||
|  |     // follow closer with SQL convention:
 | ||
|  |     // insert into the TABLE this DATA
 | ||
|  |     if (is_string($data) && is_array($table)) { | ||
|  |         $tmp   = $data; | ||
|  |         $data  = $table; | ||
|  |         $table = $tmp; | ||
|  |     } | ||
|  |     if (count($data) === 0) { | ||
|  |         return false; | ||
|  |     } | ||
|  |     if (count($data[0]) === 0) { | ||
|  |         return false; | ||
|  |     } | ||
|  | 
 | ||
|  |     $sql = 'INSERT INTO `'.$table.'` (`'.implode('`,`', array_keys($data[0])).'`)  VALUES '; | ||
|  |     $values =''; | ||
|  | 
 | ||
|  |     foreach ($data as $row) { | ||
|  |         if ($values != '') { | ||
|  |             $values .= ','; | ||
|  |         } | ||
|  |         $rowvalues=''; | ||
|  |         foreach ($row as $key => $value) { | ||
|  |             if ($rowvalues != '') { | ||
|  |                 $rowvalues .= ','; | ||
|  |             } | ||
|  |             $rowvalues .= "'".mres($value)."'"; | ||
|  |         } | ||
|  |         $values .= "(".$rowvalues.")"; | ||
|  |     } | ||
|  | 
 | ||
|  |     $time_start = microtime(true); | ||
|  |     $result = dbQuery($sql.$values); | ||
|  | 
 | ||
|  |     // logfile($fullSql);
 | ||
|  |     $time_end                = microtime(true); | ||
|  |     $db_stats['insert_sec'] += number_format(($time_end - $time_start), 8); | ||
|  |     $db_stats['insert']++; | ||
|  | 
 | ||
|  |     return $result; | ||
|  | 
 | ||
|  | }//end dbBulkInsert()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * Passed an array, table name, WHERE clause, and placeholder parameters, it attempts to update a record. | ||
|  |  * Returns the number of affected rows | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbUpdate($data, $table, $where=null, $parameters=array()) { | ||
|  |     global $fullSql; | ||
|  |     global $db_stats; | ||
|  |     // the following block swaps the parameters if they were given in the wrong order.
 | ||
|  |     // it allows the method to work for those that would rather it (or expect it to)
 | ||
|  |     // follow closer with SQL convention:
 | ||
|  |     // update the TABLE with this DATA
 | ||
|  |     if (is_string($data) && is_array($table)) { | ||
|  |         $tmp   = $data; | ||
|  |         $data  = $table; | ||
|  |         $table = $tmp; | ||
|  |         // trigger_error('QDB - The first two parameters passed to update() were in reverse order, but it has been allowed', E_USER_NOTICE);
 | ||
|  |     } | ||
|  | 
 | ||
|  |     // need field name and placeholder value
 | ||
|  |     // but how merge these field placeholders with actual $parameters array for the WHERE clause
 | ||
|  |     $sql = 'UPDATE `'.$table.'` set '; | ||
|  |     foreach ($data as $key => $value) { | ||
|  |         $sql .= '`'.$key.'` '.'=:'.$key.','; | ||
|  |     } | ||
|  | 
 | ||
|  |     $sql = substr($sql, 0, -1); | ||
|  |     // strip off last comma
 | ||
|  |     if ($where) { | ||
|  |         $sql .= ' WHERE '.$where; | ||
|  |         $data = array_merge($data, $parameters); | ||
|  |     } | ||
|  | 
 | ||
|  |     $time_start = microtime(true); | ||
|  |     if (dbQuery($sql, $data)) { | ||
|  |         $return = mysql_affected_rows(); | ||
|  |     } | ||
|  |     else { | ||
|  |         // echo("$fullSql");
 | ||
|  |         trigger_error('QDB - Update failed.', E_USER_WARNING); | ||
|  |         $return = false; | ||
|  |     } | ||
|  | 
 | ||
|  |     $time_end                = microtime(true); | ||
|  |     $db_stats['update_sec'] += number_format(($time_end - $time_start), 8); | ||
|  |     $db_stats['update']++; | ||
|  | 
 | ||
|  |     return $return; | ||
|  | 
 | ||
|  | }//end dbUpdate()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbDelete($table, $where=null, $parameters=array()) { | ||
|  |     $sql = 'DELETE FROM `'.$table.'`'; | ||
|  |     if ($where) { | ||
|  |         $sql .= ' WHERE '.$where; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (dbQuery($sql, $parameters)) { | ||
|  |         return mysql_affected_rows(); | ||
|  |     } | ||
|  |     else { | ||
|  |         return false; | ||
|  |     } | ||
|  | 
 | ||
|  | }//end dbDelete()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * Fetches all of the rows (associatively) from the last performed query. | ||
|  |  * Most other retrieval functions build off this | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbFetchRows($sql, $parameters=array()) { | ||
|  |     global $db_stats; | ||
|  | 
 | ||
|  |     $time_start = microtime(true); | ||
|  |     $result         = dbQuery($sql, $parameters); | ||
|  | 
 | ||
|  |     if (mysql_num_rows($result) > 0) { | ||
|  |         $rows = array(); | ||
|  |         while ($row = mysql_fetch_assoc($result)) { | ||
|  |             $rows[] = $row; | ||
|  |         } | ||
|  | 
 | ||
|  |         mysql_free_result($result); | ||
|  |         return $rows; | ||
|  |     } | ||
|  | 
 | ||
|  |     mysql_free_result($result); | ||
|  | 
 | ||
|  |     $time_end                   = microtime(true); | ||
|  |     $db_stats['fetchrows_sec'] += number_format(($time_end - $time_start), 8); | ||
|  |     $db_stats['fetchrows']++; | ||
|  | 
 | ||
|  |     // no records, thus return empty array
 | ||
|  |     // which should evaluate to false, and will prevent foreach notices/warnings
 | ||
|  |     return array(); | ||
|  | 
 | ||
|  | }//end dbFetchRows()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * This is intended to be the method used for large result sets. | ||
|  |  * It is intended to return an iterator, and act upon buffered data. | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbFetch($sql, $parameters=array()) { | ||
|  |     return dbFetchRows($sql, $parameters); | ||
|  |     /* | ||
|  |         // for now, don't do the iterator thing
 | ||
|  |         $result = dbQuery($sql, $parameters); | ||
|  |         if($result) { | ||
|  |         // return new iterator
 | ||
|  |         return new dbIterator($result); | ||
|  |         } else { | ||
|  |         return null; // ??
 | ||
|  |         } | ||
|  |      */ | ||
|  | 
 | ||
|  | }//end dbFetch()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * Like fetch(), accepts any number of arguments | ||
|  |  * The first argument is an sprintf-ready query stringTypes | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbFetchRow($sql=null, $parameters=array()) { | ||
|  |     global $db_stats; | ||
|  | 
 | ||
|  |     $time_start = microtime(true); | ||
|  |     $result         = dbQuery($sql, $parameters); | ||
|  |     if ($result) { | ||
|  |         $row = mysql_fetch_assoc($result); | ||
|  |         mysql_free_result($result); | ||
|  |         $time_end = microtime(true); | ||
|  | 
 | ||
|  |         $db_stats['fetchrow_sec'] += number_format(($time_end - $time_start), 8); | ||
|  |         $db_stats['fetchrow']++; | ||
|  | 
 | ||
|  |         return $row; | ||
|  |     } | ||
|  |     else { | ||
|  |         return null; | ||
|  |     } | ||
|  | 
 | ||
|  |     $time_start = microtime(true); | ||
|  | 
 | ||
|  | }//end dbFetchRow()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * Fetches the first call from the first row returned by the query | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbFetchCell($sql, $parameters=array()) { | ||
|  |     global $db_stats; | ||
|  |     $time_start = microtime(true); | ||
|  |     $row            = dbFetchRow($sql, $parameters); | ||
|  |     if ($row) { | ||
|  |         return array_shift($row); | ||
|  |         // shift first field off first row
 | ||
|  |     } | ||
|  | 
 | ||
|  |     $time_end = microtime(true); | ||
|  | 
 | ||
|  |     $db_stats['fetchcell_sec'] += number_format(($time_end - $time_start), 8); | ||
|  |     $db_stats['fetchcell']++; | ||
|  | 
 | ||
|  |     return null; | ||
|  | 
 | ||
|  | }//end dbFetchCell()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * This method is quite different from fetchCell(), actually | ||
|  |  * It fetches one cell from each row and places all the values in 1 array | ||
|  |  * */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbFetchColumn($sql, $parameters=array()) { | ||
|  |     global $db_stats; | ||
|  |     $time_start = microtime(true); | ||
|  |     $cells          = array(); | ||
|  |     foreach (dbFetch($sql, $parameters) as $row) { | ||
|  |         $cells[] = array_shift($row); | ||
|  |     } | ||
|  | 
 | ||
|  |     $time_end = microtime(true); | ||
|  | 
 | ||
|  |     $db_stats['fetchcol_sec'] += number_format(($time_end - $time_start), 8); | ||
|  |     $db_stats['fetchcol']++; | ||
|  | 
 | ||
|  |     return $cells; | ||
|  | 
 | ||
|  | }//end dbFetchColumn()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * Should be passed a query that fetches two fields | ||
|  |  * The first will become the array key | ||
|  |  * The second the key's value | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbFetchKeyValue($sql, $parameters=array()) { | ||
|  |     $data = array(); | ||
|  |     foreach (dbFetch($sql, $parameters) as $row) { | ||
|  |         $key = array_shift($row); | ||
|  |         if (sizeof($row) == 1) { | ||
|  |             // if there were only 2 fields in the result
 | ||
|  |             // use the second for the value
 | ||
|  |             $data[$key] = array_shift($row); | ||
|  |         } | ||
|  |         else { | ||
|  |             // if more than 2 fields were fetched
 | ||
|  |             // use the array of the rest as the value
 | ||
|  |             $data[$key] = $row; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return $data; | ||
|  | 
 | ||
|  | }//end dbFetchKeyValue()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * This combines a query and parameter array into a final query string for execution | ||
|  |  * PDO drivers don't need to use this | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbMakeQuery($sql, $parameters) { | ||
|  |     // bypass extra logic if we have no parameters
 | ||
|  |     if (sizeof($parameters) == 0) { | ||
|  |         return $sql; | ||
|  |     } | ||
|  | 
 | ||
|  |     $parameters = dbPrepareData($parameters); | ||
|  |     // separate the two types of parameters for easier handling
 | ||
|  |     $questionParams = array(); | ||
|  |     $namedParams    = array(); | ||
|  |     foreach ($parameters as $key => $value) { | ||
|  |         if (is_numeric($key)) { | ||
|  |             $questionParams[] = $value; | ||
|  |         } | ||
|  |         else { | ||
|  |             $namedParams[':'.$key] = $value; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     // sort namedParams in reverse to stop substring squashing
 | ||
|  |     krsort($namedParams); | ||
|  | 
 | ||
|  |     // split on question-mark and named placeholders
 | ||
|  |     $result = preg_split('/(\?|:[a-zA-Z0-9_-]+)/', $sql, -1, (PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)); | ||
|  | 
 | ||
|  |     // every-other item in $result will be the placeholder that was found
 | ||
|  |     $query            = ''; | ||
|  |     $res_size = sizeof($result); | ||
|  |     for ($i = 0; $i < $res_size; $i += 2) { | ||
|  |         $query .= $result[$i]; | ||
|  | 
 | ||
|  |         $j = ($i + 1); | ||
|  |         if (array_key_exists($j, $result)) { | ||
|  |             $test = $result[$j]; | ||
|  |             if ($test == '?') { | ||
|  |                 $query .= array_shift($questionParams); | ||
|  |             } | ||
|  |             else { | ||
|  |                 $query .= $namedParams[$test]; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return $query; | ||
|  | 
 | ||
|  | }//end dbMakeQuery()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbPrepareData($data) { | ||
|  |     $values = array(); | ||
|  | 
 | ||
|  |     foreach ($data as $key => $value) { | ||
|  |         $escape = true; | ||
|  |         // don't quote or esc if value is an array, we treat it
 | ||
|  |         // as a "decorator" that tells us not to escape the
 | ||
|  |         // value contained in the array
 | ||
|  |         if (is_array($value) && !is_object($value)) { | ||
|  |             $escape = false; | ||
|  |             $value  = array_shift($value); | ||
|  |         } | ||
|  | 
 | ||
|  |         // it's not right to worry about invalid fields in this method because we may be operating on fields
 | ||
|  |         // that are aliases, or part of other tables through joins
 | ||
|  |         // if(!in_array($key, $columns)) // skip invalid fields
 | ||
|  |         // continue;
 | ||
|  |         if ($escape) { | ||
|  |             $values[$key] = "'".mysql_real_escape_string($value)."'"; | ||
|  |         } | ||
|  |         else { | ||
|  |             $values[$key] = $value; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return $values; | ||
|  | 
 | ||
|  | }//end dbPrepareData()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |  * Given a data array, this returns an array of placeholders | ||
|  |  * These may be question marks, or ":email" type | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbPlaceHolders($values) { | ||
|  |     $data = array(); | ||
|  |     foreach ($values as $key => $value) { | ||
|  |         if (is_numeric($key)) { | ||
|  |             $data[] = '?'; | ||
|  |         } | ||
|  |         else { | ||
|  |             $data[] = ':'.$key; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return $data; | ||
|  | 
 | ||
|  | }//end dbPlaceHolders()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbBeginTransaction() { | ||
|  |     mysql_query('begin'); | ||
|  | 
 | ||
|  | }//end dbBeginTransaction()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbCommitTransaction() { | ||
|  |     mysql_query('commit'); | ||
|  | 
 | ||
|  | }//end dbCommitTransaction()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | function dbRollbackTransaction() { | ||
|  |     mysql_query('rollback'); | ||
|  | 
 | ||
|  | }//end dbRollbackTransaction()
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  |     class dbIterator implements Iterator { | ||
|  |     private $result; | ||
|  |     private $i; | ||
|  | 
 | ||
|  |     public function __construct($r) { | ||
|  |     $this->result = $r; | ||
|  |     $this->i = 0; | ||
|  |     } | ||
|  |     public function rewind() { | ||
|  |     mysql_data_seek($this->result, 0); | ||
|  |     $this->i = 0; | ||
|  |     } | ||
|  |     public function current() { | ||
|  |     $a = mysql_fetch_assoc($this->result); | ||
|  |     return $a; | ||
|  |     } | ||
|  |     public function key() { | ||
|  |     return $this->i; | ||
|  |     } | ||
|  |     public function next() { | ||
|  |     $this->i++; | ||
|  |     $a = mysql_data_seek($this->result, $this->i); | ||
|  |     if($a === false) { | ||
|  |     $this->i = 0; | ||
|  |     } | ||
|  |     return $a; | ||
|  |     } | ||
|  |     public function valid() { | ||
|  |     return ($this->current() !== false); | ||
|  |     } | ||
|  |     } | ||
|  |  */ |