2009-12-02 18:32:20 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class for managing database connection
|
|
|
|
*
|
|
|
|
* LICENSE:
|
|
|
|
*
|
|
|
|
* Copyright (c) 2009 Yubico. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* o Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* o Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* o The names of the authors may not be used to endorse or promote
|
|
|
|
* products derived from this software without specific prior written
|
|
|
|
* permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @author Olov Danielson <olov.danielson@gmail.com>
|
|
|
|
* @copyright 2009 Yubico
|
|
|
|
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
|
|
|
* @link http://www.yubico.com/
|
|
|
|
* @link http://code.google.com/p/yubikey-timedelta-server-php/
|
|
|
|
*/
|
2010-01-11 13:06:00 +01:00
|
|
|
|
|
|
|
require_once('ykval-log.php');
|
|
|
|
|
2009-12-02 18:32:20 +01:00
|
|
|
class Db
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* @param string $host Database host
|
|
|
|
* @param string $user Database user
|
|
|
|
* @param string $pwd Database password
|
|
|
|
* @param string $name Database table name
|
|
|
|
* @return void
|
|
|
|
*
|
|
|
|
*/
|
2010-01-14 14:45:44 +01:00
|
|
|
public function __construct($db_dsn, $db_username, $db_password, $dp_options, $name='ykval-db')
|
2009-12-02 18:32:20 +01:00
|
|
|
{
|
2010-01-08 17:35:25 +01:00
|
|
|
$this->db_dsn=$db_dsn;
|
|
|
|
$this->db_username=$db_username;
|
|
|
|
$this->db_password=$db_password;
|
|
|
|
$this->db_options=$db_options;
|
2010-01-11 13:06:00 +01:00
|
|
|
|
2010-01-14 14:45:44 +01:00
|
|
|
$this->myLog=new Log($name);
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
2010-01-14 12:58:19 +01:00
|
|
|
|
|
|
|
function addField($name, $value)
|
|
|
|
{
|
|
|
|
$this->myLog->addField($name, $value);
|
|
|
|
}
|
|
|
|
|
2009-12-02 18:32:20 +01:00
|
|
|
/**
|
|
|
|
* function to convert Db timestamps to unixtime(s)
|
|
|
|
*
|
|
|
|
* @param string $updated Database timestamp
|
|
|
|
* @return int Timestamp in unixtime format
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function timestampToTime($updated)
|
|
|
|
{
|
|
|
|
$stamp=strptime($updated, '%F %H:%M:%S');
|
|
|
|
return mktime($stamp[tm_hour], $stamp[tm_min], $stamp[tm_sec], $stamp[tm_mon]+1, $stamp[tm_mday], $stamp[tm_year]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* function to compute delta (s) between 2 Db timestamps
|
|
|
|
*
|
|
|
|
* @param string $first Database timestamp 1
|
|
|
|
* @param string $second Database timestamp 2
|
|
|
|
* @return int Deltatime (s)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function timestampDeltaTime($first, $second)
|
|
|
|
{
|
|
|
|
return Db::timestampToTime($second) - Db::timestampToTime($first);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* function to disconnect from database
|
|
|
|
*
|
|
|
|
* @return boolean True on success, otherwise false.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function disconnect()
|
|
|
|
{
|
2010-01-08 17:35:25 +01:00
|
|
|
$this->dbh=NULL;
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* function to check if database is connected
|
|
|
|
*
|
|
|
|
* @return boolean True if connected, otherwise false.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function isConnected()
|
|
|
|
{
|
2010-01-08 17:35:25 +01:00
|
|
|
if ($this->dbh!=NULL) return True;
|
2009-12-02 18:32:20 +01:00
|
|
|
else return False;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* function to connect to database defined in config.php
|
|
|
|
*
|
|
|
|
* @return boolean True on success, otherwise false.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function connect(){
|
2010-01-08 17:35:25 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
$this->dbh = new PDO($this->db_dsn, $this->db_username, $this->db_password, $this->db_options);
|
|
|
|
} catch (PDOException $e) {
|
2010-01-11 13:06:00 +01:00
|
|
|
$this->myLog->log(LOG_CRIT, "Database error: " . $e->getMessage());
|
2010-01-08 17:35:25 +01:00
|
|
|
$this->dbh=Null;
|
2009-12-02 18:32:20 +01:00
|
|
|
return false;
|
|
|
|
}
|
2010-01-08 17:35:25 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function query($query, $returnresult=false) {
|
|
|
|
if($this->dbh) {
|
2010-01-14 12:50:13 +01:00
|
|
|
$this->myLog->log(LOG_DEBUG, 'DB query is: ' . $query);
|
|
|
|
|
2010-01-10 18:24:17 +01:00
|
|
|
$this->result = $this->dbh->query($query);
|
|
|
|
if (! $this->result){
|
2010-01-12 14:00:28 +01:00
|
|
|
$this->myLog->log(LOG_INFO, 'Database error: ' . print_r($this->dbh->errorInfo(), true));
|
2010-01-08 17:35:25 +01:00
|
|
|
return false;
|
|
|
|
}
|
2010-01-10 18:24:17 +01:00
|
|
|
if ($returnresult) return $this->result;
|
2010-01-08 17:35:25 +01:00
|
|
|
else return true;
|
|
|
|
} else {
|
2010-01-11 13:06:00 +01:00
|
|
|
$this->myLog->log(LOG_CRIT, 'No database connection');
|
2009-12-02 18:32:20 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function truncateTable($name)
|
|
|
|
{
|
2010-01-08 17:35:25 +01:00
|
|
|
$this->query("TRUNCATE TABLE " . $name);
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
2009-12-07 18:21:38 +01:00
|
|
|
|
2009-12-02 18:32:20 +01:00
|
|
|
/**
|
2010-01-08 14:54:33 +01:00
|
|
|
* function to update row in database by a where condition
|
2009-12-02 18:32:20 +01:00
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param int $id Id on row to update
|
|
|
|
* @param array $values Array with key=>values to update
|
|
|
|
* @return boolean True on success, otherwise false.
|
|
|
|
*
|
|
|
|
*/
|
2010-01-08 14:54:33 +01:00
|
|
|
public function updateBy($table, $k, $v, $values)
|
2009-12-02 18:32:20 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
foreach ($values as $key=>$value){
|
2010-01-12 19:05:41 +01:00
|
|
|
if (!is_null($value)) $query .= ' ' . $key . "='" . $value . "',";
|
2010-01-08 14:54:33 +01:00
|
|
|
else $query .= ' ' . $key . '=NULL,';
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
|
|
|
if (! $query) {
|
2010-01-14 12:50:13 +01:00
|
|
|
$this->myLog->log(LOG_DEBUG, "no values to set in query. Not updating DB");
|
2009-12-02 18:32:20 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-01-12 14:00:28 +01:00
|
|
|
$query = rtrim($query, ",") . " WHERE " . $k . " = '" . $v . "'";
|
2009-12-02 18:32:20 +01:00
|
|
|
// Insert UPDATE statement at beginning
|
|
|
|
$query = "UPDATE " . $table . " SET " . $query;
|
2010-01-08 17:35:25 +01:00
|
|
|
|
|
|
|
return $this->query($query, false);
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
2010-01-08 14:54:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* function to update row in database
|
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param int $id Id on row to update
|
|
|
|
* @param array $values Array with key=>values to update
|
|
|
|
* @return boolean True on success, otherwise false.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function update($table, $id, $values)
|
|
|
|
{
|
|
|
|
return $this->updateBy($table, 'id', $id, $values);
|
|
|
|
}
|
2010-01-12 14:00:28 +01:00
|
|
|
|
2009-12-07 18:21:38 +01:00
|
|
|
/**
|
2010-01-12 14:00:28 +01:00
|
|
|
* function to update row in database based on a condition
|
2009-12-07 18:21:38 +01:00
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
2010-01-12 14:00:28 +01:00
|
|
|
* @param string $k Column to select row on
|
|
|
|
* @param string $v Value to select row on
|
2009-12-07 18:21:38 +01:00
|
|
|
* @param array $values Array with key=>values to update
|
|
|
|
* @param string $condition conditional statement
|
|
|
|
* @return boolean True on success, otherwise false.
|
|
|
|
*
|
|
|
|
*/
|
2010-01-12 14:00:28 +01:00
|
|
|
public function conditionalUpdateBy($table, $k, $v, $values, $condition)
|
2009-12-07 18:21:38 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
foreach ($values as $key=>$value){
|
2009-12-15 11:17:51 +01:00
|
|
|
$query = $query . " " . $key . "='" . $value . "',";
|
2009-12-07 18:21:38 +01:00
|
|
|
}
|
|
|
|
if (! $query) {
|
2010-01-14 12:50:13 +01:00
|
|
|
$this->myLog->log(LOG_DEBUG, "no values to set in query. Not updating DB");
|
2009-12-07 18:21:38 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-01-12 14:00:28 +01:00
|
|
|
$query = rtrim($query, ",") . " WHERE " . $k . " = '" . $v . "' and " . $condition;
|
2009-12-07 18:21:38 +01:00
|
|
|
// Insert UPDATE statement at beginning
|
|
|
|
$query = "UPDATE " . $table . " SET " . $query;
|
2010-01-08 17:35:25 +01:00
|
|
|
|
|
|
|
return $this->query($query, false);
|
2009-12-07 18:21:38 +01:00
|
|
|
}
|
2010-01-12 14:00:28 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to update row in database based on a condition.
|
|
|
|
* An ID value is passed to select the appropriate column
|
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param int $id Id on row to update
|
|
|
|
* @param array $values Array with key=>values to update
|
|
|
|
* @param string $condition conditional statement
|
|
|
|
* @return boolean True on success, otherwise false.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function conditionalUpdate($table, $id, $values, $condition)
|
|
|
|
{
|
|
|
|
return $this->conditionalUpdateBy($table, 'id', $id, $values, $condition);
|
|
|
|
}
|
2009-12-07 18:21:38 +01:00
|
|
|
|
2009-12-02 18:32:20 +01:00
|
|
|
/**
|
|
|
|
* function to insert new row in database
|
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param array $values Array with key=>values to update
|
|
|
|
* @return boolean True on success, otherwise false.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function save($table, $values)
|
|
|
|
{
|
|
|
|
$query= 'INSERT INTO ' . $table . " (";
|
|
|
|
foreach ($values as $key=>$value){
|
2010-01-12 19:05:41 +01:00
|
|
|
if (!is_null($value)) $query = $query . $key . ",";
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
|
|
|
$query = rtrim($query, ",") . ') VALUES (';
|
|
|
|
foreach ($values as $key=>$value){
|
2010-01-12 19:05:41 +01:00
|
|
|
if (!is_null($value)) $query = $query . "'" . $value . "',";
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
|
|
|
$query = rtrim($query, ",");
|
|
|
|
$query = $query . ")";
|
2010-01-08 17:35:25 +01:00
|
|
|
return $this->query($query, false);
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* helper function to collect last row[s] in database
|
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param int $nr Number of rows to collect. NULL=>inifinity. DEFAULT=1.
|
|
|
|
* @return mixed Array with values from Db row or 2d-array with multiple rows
|
|
|
|
or false on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function last($table, $nr=1)
|
|
|
|
{
|
|
|
|
return Db::findBy($table, null, null, $nr, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* main function used to get rows from Db table.
|
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param string $key Column to select rows by
|
|
|
|
* @param string $value Value to select rows by
|
|
|
|
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
|
|
|
|
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
|
|
|
|
* @return mixed Array with values from Db row or 2d-array with multiple rows
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function findBy($table, $key, $value, $nr=null, $rev=null)
|
|
|
|
{
|
2010-01-08 14:54:33 +01:00
|
|
|
return $this->findByMultiple($table, array($key=>$value), $nr, $rev);
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* main function used to get rows by multiple key=>value pairs from Db table.
|
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param array $where Array with column=>values to select rows by
|
|
|
|
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
|
|
|
|
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
|
|
|
|
* @param string distinct Select rows with distinct columns, Default=NULL
|
|
|
|
* @return mixed Array with values from Db row or 2d-array with multiple rows
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function findByMultiple($table, $where, $nr=null, $rev=null, $distinct=null)
|
|
|
|
{
|
|
|
|
$query="SELECT";
|
|
|
|
if ($distinct!=null) {
|
|
|
|
$query.= " DISTINCT " . $distinct;
|
|
|
|
} else {
|
|
|
|
$query.= " *";
|
|
|
|
}
|
|
|
|
$query.= " FROM " . $table;
|
|
|
|
if ($where!=null){
|
|
|
|
foreach ($where as $key=>$value) {
|
2010-01-12 19:05:41 +01:00
|
|
|
if ($key!=null) {
|
|
|
|
if ($value!=null) $match.= " ". $key . " = '" . $value . "' and";
|
2010-01-08 14:54:33 +01:00
|
|
|
else $match.= " ". $key . " is NULL and";
|
|
|
|
}
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
2010-01-08 14:54:33 +01:00
|
|
|
if ($match!=null) $query .= " WHERE" . $match;
|
2009-12-02 18:32:20 +01:00
|
|
|
$query=rtrim($query, "and");
|
|
|
|
$query=rtrim($query);
|
|
|
|
}
|
|
|
|
if ($rev==1) $query.= " ORDER BY id DESC";
|
|
|
|
if ($nr!=null) $query.= " LIMIT " . $nr;
|
2010-01-11 13:06:00 +01:00
|
|
|
|
2010-01-08 17:35:25 +01:00
|
|
|
$result = $this->query($query, true);
|
|
|
|
if (!$result) return false;
|
|
|
|
|
2009-12-02 18:32:20 +01:00
|
|
|
if ($nr==1) {
|
2010-01-08 17:35:25 +01:00
|
|
|
$row = $result->fetch(PDO::FETCH_ASSOC);
|
2009-12-02 18:32:20 +01:00
|
|
|
return $row;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$collection=array();
|
2010-01-08 17:35:25 +01:00
|
|
|
while($row = $result->fetch(PDO::FETCH_ASSOC)){
|
2009-12-02 18:32:20 +01:00
|
|
|
$collection[]=$row;
|
|
|
|
}
|
|
|
|
return $collection;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* main function used to delete rows by multiple key=>value pairs from Db table.
|
|
|
|
*
|
|
|
|
* @param string $table Database table to delete row in
|
|
|
|
* @param array $where Array with column=>values to select rows by
|
|
|
|
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=NULL.
|
|
|
|
* @param int $rev rev=1 indicates order should be reversed. Default=NULL.
|
|
|
|
* @param string distinct Select rows with distinct columns, Default=NULL
|
2010-01-08 17:35:25 +01:00
|
|
|
* @return boolean True on success, otherwise false.
|
2009-12-02 18:32:20 +01:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function deleteByMultiple($table, $where, $nr=null, $rev=null)
|
|
|
|
{
|
|
|
|
$query="DELETE";
|
|
|
|
$query.= " FROM " . $table;
|
|
|
|
if ($where!=null){
|
|
|
|
$query.= " WHERE";
|
|
|
|
foreach ($where as $key=>$value) {
|
|
|
|
$query.= " ". $key . " = '" . $value . "' and";
|
|
|
|
}
|
|
|
|
$query=rtrim($query, "and");
|
|
|
|
$query=rtrim($query);
|
|
|
|
}
|
|
|
|
if ($rev==1) $query.= " ORDER BY id DESC";
|
|
|
|
if ($nr!=null) $query.= " LIMIT " . $nr;
|
2010-01-08 17:35:25 +01:00
|
|
|
return $this->query($query, false);
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
|
|
|
|
2010-01-10 18:14:32 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to do a custom query on database connection
|
|
|
|
*
|
|
|
|
* @param string $query Database query
|
|
|
|
* @return mixed
|
|
|
|
*
|
|
|
|
*/
|
2009-12-02 18:32:20 +01:00
|
|
|
public function customQuery($query)
|
|
|
|
{
|
2010-01-08 17:35:25 +01:00
|
|
|
return $this->query($query, true);
|
2009-12-02 18:32:20 +01:00
|
|
|
}
|
2010-01-10 18:14:32 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to do a custom query on database connection
|
|
|
|
*
|
|
|
|
* @return int number of rows affected by last statement or 0 if database connection is not functional.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function rowCount()
|
|
|
|
{
|
2010-01-10 18:24:17 +01:00
|
|
|
if($this->result) return $this->result->rowCount();
|
2010-01-10 18:14:32 +01:00
|
|
|
else return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-02 18:32:20 +01:00
|
|
|
/**
|
|
|
|
* helper function used to get rows from Db table in reversed order.
|
|
|
|
* defaults to obtaining 1 row.
|
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param string $key Column to select rows by
|
|
|
|
* @param string $value Value to select rows by
|
|
|
|
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=1.
|
|
|
|
* @return mixed Array with values from Db row or 2d-array with multiple rows or false on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function lastBy($table, $key, $value, $nr=1)
|
|
|
|
{
|
|
|
|
return Db::findBy($table, $key, $value, $nr, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* helper function used to get rows from Db table in standard order.
|
|
|
|
* defaults to obtaining 1 row.
|
|
|
|
*
|
|
|
|
* @param string $table Database table to update row in
|
|
|
|
* @param string $key Column to select rows by
|
|
|
|
* @param string $value Value to select rows by
|
|
|
|
* @param int $nr Number of rows to collect. NULL=>inifinity. Default=1.
|
|
|
|
* @return mixed Array with values from Db row or 2d-array with multiple rows or false on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function firstBy($table, $key, $value, $nr=1)
|
|
|
|
{
|
|
|
|
return Db::findBy($table, $key, $value, $nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
?>
|