Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php/*** ADOdb Library main include file.** This file is part of ADOdb, a Database Abstraction Layer library for PHP.** @package ADOdb* @link https://adodb.org Project's web site and documentation* @link https://github.com/ADOdb/ADOdb Source code and issue tracker** The ADOdb Library is dual-licensed, released under both the BSD 3-Clause* and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,* any later version. This means you can use it in proprietary products.* See the LICENSE.md file distributed with this source code for details.* @license BSD-3-Clause* @license LGPL-2.1-or-later** @copyright 2000-2013 John Lim* @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community*/if (!defined('_ADODB_LAYER')) {define('_ADODB_LAYER',1);// The ADOdb extension is no longer maintained and effectively unsupported// since v5.04. The library will not function properly if it is present.if(defined('ADODB_EXTENSION')) {$msg = "Unsupported ADOdb Extension (v" . ADODB_EXTENSION . ") detected! ". "Disable it to use ADOdb";$errorfn = defined('ADODB_ERROR_HANDLER') ? ADODB_ERROR_HANDLER : false;if ($errorfn) {$conn = false;$errorfn('ADOdb', basename(__FILE__), -9999, $msg, null, null, $conn);} else {die($msg . PHP_EOL);}}//==============================================================================================// CONSTANT DEFINITIONS//==============================================================================================/*** Set ADODB_DIR to the directory where this file resides...* This constant was formerly called $ADODB_RootPath*/if (!defined('ADODB_DIR')) {define('ADODB_DIR',dirname(__FILE__));}//==============================================================================================// GLOBAL VARIABLES//==============================================================================================GLOBAL$ADODB_vers, // database version$ADODB_COUNTRECS, // count number of records returned - slows down query$ADODB_CACHE_DIR, // directory to cache recordsets$ADODB_CACHE,$ADODB_CACHE_CLASS,$ADODB_COMPAT_FETCH, // If $ADODB_COUNTRECS and this is true, $rs->fields is available on EOF$ADODB_FETCH_MODE, // DEFAULT, NUM, ASSOC or BOTH. Default follows native driver default...$ADODB_GETONE_EOF,$ADODB_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql.//==============================================================================================// GLOBAL SETUP//==============================================================================================/********************************************************** Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).* Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi* @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:adodb_force_type** 0 = ignore empty fields. All empty fields in array are ignored.* 1 = force null. All empty, php null and string 'null' fields are* changed to sql NULL values.* 2 = force empty. All empty, php null and string 'null' fields are* changed to sql empty '' or 0 values.* 3 = force value. Value is left as it is. Php null and string 'null'* are set to sql NULL values and empty fields '' are set to empty '' sql values.* 4 = force value. Like 1 but numeric empty fields are set to zero.*/define('ADODB_FORCE_IGNORE',0);define('ADODB_FORCE_NULL',1);define('ADODB_FORCE_EMPTY',2);define('ADODB_FORCE_VALUE',3);define('ADODB_FORCE_NULL_AND_ZERO',4);// ********************************************************/*** Constants for returned values from the charMax and textMax methods.* If not specifically defined in the driver, methods return the NOTSET value.*/define ('ADODB_STRINGMAX_NOTSET', -1);define ('ADODB_STRINGMAX_NOLIMIT',-2);/** Defines the the default meta type returned* when ADOdb encounters a type that it is not* defined in the metaTypes.*/if (!defined('ADODB_DEFAULT_METATYPE'))define ('ADODB_DEFAULT_METATYPE','N');define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');// allow [ ] @ ` " and . in table namesdefine('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');// prefetching used by oracleif (!defined('ADODB_PREFETCH_ROWS')) {define('ADODB_PREFETCH_ROWS',10);}/*** Fetch mode** Set global variable $ADODB_FETCH_MODE to one of these constants or use* the SetFetchMode() method to control how recordset fields are returned* when fetching data.** - NUM: array()* - ASSOC: array('id' => 456, 'name' => 'john')* - BOTH: array(0 => 456, 'id' => 456, 1 => 'john', 'name' => 'john')* - DEFAULT: driver-dependent*/define('ADODB_FETCH_DEFAULT', 0);define('ADODB_FETCH_NUM', 1);define('ADODB_FETCH_ASSOC', 2);define('ADODB_FETCH_BOTH', 3);/*** Associative array case constants** By defining the ADODB_ASSOC_CASE constant to one of these values, it is* possible to control the case of field names (associative array's keys)* when operating in ADODB_FETCH_ASSOC fetch mode.* - LOWER: $rs->fields['orderid']* - UPPER: $rs->fields['ORDERID']* - NATIVE: $rs->fields['OrderID'] (or whatever the RDBMS will return)** The default is to use native case-names.** NOTE: This functionality is not implemented everywhere, it currently* works only with: mssql, odbc, oci8 and ibase derived drivers*/define('ADODB_ASSOC_CASE_LOWER', 0);define('ADODB_ASSOC_CASE_UPPER', 1);define('ADODB_ASSOC_CASE_NATIVE', 2);if (!defined('TIMESTAMP_FIRST_YEAR')) {define('TIMESTAMP_FIRST_YEAR',100);}/*** AutoExecute constants* (moved from adodb-pear.inc.php since they are only used in here)*/define('DB_AUTOQUERY_INSERT', 1);define('DB_AUTOQUERY_UPDATE', 2);function ADODB_Setup() {GLOBAL$ADODB_vers, // database version$ADODB_COUNTRECS, // count number of records returned - slows down query$ADODB_CACHE_DIR, // directory to cache recordsets$ADODB_FETCH_MODE,$ADODB_CACHE,$ADODB_CACHE_CLASS,$ADODB_FORCE_TYPE,$ADODB_GETONE_EOF,$ADODB_QUOTE_FIELDNAMES;if (empty($ADODB_CACHE_CLASS)) {$ADODB_CACHE_CLASS = 'ADODB_Cache_File' ;}$ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;$ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;$ADODB_GETONE_EOF = null;if (!isset($ADODB_CACHE_DIR)) {$ADODB_CACHE_DIR = '/tmp'; //(isset($_ENV['TMP'])) ? $_ENV['TMP'] : '/tmp';} else {// do not accept url based paths, eg. http:/ or ftp:/if (strpos($ADODB_CACHE_DIR,'://') !== false) {die("Illegal path http:// or ftp://");}}/*** ADODB version as a string.*/$ADODB_vers = 'v5.22.7 2023-11-04';/*** Determines whether recordset->RecordCount() is used.* Set to false for highest performance -- RecordCount() will always return -1 then* for databases that provide "virtual" recordcounts...*/if (!isset($ADODB_COUNTRECS)) {$ADODB_COUNTRECS = true;}}//==============================================================================================// CHANGE NOTHING BELOW UNLESS YOU ARE DESIGNING ADODB//==============================================================================================ADODB_Setup();//==============================================================================================// CLASS ADOFieldObject//==============================================================================================/*** Helper class for FetchFields -- holds info on a column.** Note: Dynamic properties are required here, as some drivers may require* the object to hold database-specific field metadata.*/#[\AllowDynamicProperties]class ADOFieldObject {var $name = '';var $max_length=0;var $type="";/*// additional fields by dannym... (danny_milo@yahoo.com)var $not_null = false;// actually, this has already been built-in in the postgres, fbsql AND mysql module? ^-^// so we can as well make not_null standard (leaving it at "false" does not harm anyways)var $has_default = false; // this one I have done only in mysql and postgres for now ...// others to come (dannym)var $default_value; // default, if any, and supported. Check has_default first.*/}/*** Parse date string to prevent injection attack.** @param string $s** @return string*/function _adodb_safedate($s) {return str_replace(array("'", '\\'), '', $s);}/*** Parse date string to prevent injection attack.* Date string will have one quote at beginning e.g. '3434343'** @param string $s** @return string*/function _adodb_safedateq($s) {$len = strlen($s);if ($s[0] !== "'") {$s2 = "'".$s[0];} else {$s2 = "'";}for($i=1; $i<$len; $i++) {$ch = $s[$i];if ($ch === '\\') {$s2 .= "'";break;} elseif ($ch === "'") {$s2 .= $ch;break;}$s2 .= $ch;}return strlen($s2) == 0 ? 'null' : $s2;}/*** For transaction handling.** @param $dbms* @param $fn* @param $errno* @param $errmsg* @param $p1* @param $p2* @param $thisConnection*/function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection) {//print "Errorno ($fn errno=$errno m=$errmsg) ";$thisConnection->_transOK = false;if ($thisConnection->_oldRaiseFn) {$errfn = $thisConnection->_oldRaiseFn;$errfn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);}}/*** Class ADODB_Cache_File*/class ADODB_Cache_File {var $createdir = true; // requires creation of temp dirsfunction __construct() {global $ADODB_INCLUDED_CSV;if (empty($ADODB_INCLUDED_CSV)) {include_once(ADODB_DIR.'/adodb-csvlib.inc.php');}}/*** Write serialised RecordSet to cache item/file.** @param $filename* @param $contents* @param $debug* @param $secs2cache** @return bool|int*/function writecache($filename, $contents, $debug, $secs2cache) {return adodb_write_file($filename, $contents,$debug);}/*** load serialised RecordSet and unserialise it** @param $filename* @param $err* @param $secs2cache* @param $rsClass** @return ADORecordSet*/function &readcache($filename, &$err, $secs2cache, $rsClass) {$rs = csv2rs($filename,$err,$secs2cache,$rsClass);return $rs;}/*** Flush all items in cache.** @param bool $debug** @return bool|void*/function flushall($debug=false) {global $ADODB_CACHE_DIR;$rez = false;if (strlen($ADODB_CACHE_DIR) > 1) {$rez = $this->_dirFlush($ADODB_CACHE_DIR);if ($debug) {ADOConnection::outp( "flushall: $ADODB_CACHE_DIR<br><pre>\n". $rez."</pre>");}}return $rez;}/*** Flush one file in cache.** @param string $f* @param bool $debug*/function flushcache($f, $debug=false) {if (!@unlink($f)) {if ($debug) {ADOConnection::outp( "flushcache: failed for $f");}}}/*** @param string $hash** @return string*/function getdirname($hash) {global $ADODB_CACHE_DIR;return $ADODB_CACHE_DIR . '/' . substr($hash, 0, 2);}/*** Create temp directories.** @param string $hash* @param bool $debug** @return string*/function createdir($hash, $debug) {global $ADODB_CACHE_PERMS;$dir = $this->getdirname($hash);if (!file_exists($dir)) {$oldu = umask(0);if (!@mkdir($dir, empty($ADODB_CACHE_PERMS) ? 0771 : $ADODB_CACHE_PERMS)) {if(!is_dir($dir) && $debug) {ADOConnection::outp("Cannot create $dir");}}umask($oldu);}return $dir;}/*** Private function to erase all of the files and subdirectories in a directory.** Just specify the directory, and tell it if you want to delete the directory or just clear it out.* Note: $kill_top_level is used internally in the function to flush subdirectories.*/function _dirFlush($dir, $kill_top_level = false) {if(!$dh = @opendir($dir)) return;while (($obj = readdir($dh))) {if($obj=='.' || $obj=='..') continue;$f = $dir.'/'.$obj;if (strpos($obj,'.cache')) {@unlink($f);}if (is_dir($f)) {$this->_dirFlush($f, true);}}if ($kill_top_level === true) {@rmdir($dir);}return true;}}//==============================================================================================// CLASS ADOConnection//==============================================================================================/*** Connection object. For connecting to databases, and executing queries.*/abstract class ADOConnection {//// PUBLIC VARS//var $dataProvider = 'native';var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql/*** @var string Current database name.** This used to be stored in the $databaseName property, which was marked* as deprecated in 4.66 and removed in 5.22.5.*/public $database = '';/*** @var string If the driver is PDO, then the dsnType is e.g. sqlsrv, otherwise empty*/public $dsnType = '';var $host = ''; /// The hostname of the database servervar $port = ''; /// The port of the database servervar $user = ''; /// The username which is used to connect to the database server.var $password = ''; /// Password for the username. For security, we no longer store it.var $debug = false; /// if set to true will output sql statementsvar $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxprovar $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbasevar $substr = 'substr'; /// substring operatorvar $length = 'length'; /// string length ofperatorvar $random = 'rand()'; /// random functionvar $upperCase = 'upper'; /// uppercase functionvar $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the databasevar $fmtTimeStamp = "'Y-m-d, h:i:s A'"; /// used by DBTimeStamp as the default timestamp fmt.var $true = '1'; /// string that represents TRUE for a databasevar $false = '0'; /// string that represents FALSE for a databasevar $replaceQuote = "\\'"; /// string to use to replace quotesvar $nameQuote = '"'; /// string to use to quote identifiers and namesvar $leftBracket = '['; /// left square bracked for t-sql styled column namesvar $rightBracket = ']'; /// right square bracked for t-sql styled column namesvar $charSet=false; /// character set to use - only for interbase, postgres and oci8/** @var string SQL statement to get databases */var $metaDatabasesSQL = '';/** @var string SQL statement to get database tables */var $metaTablesSQL = '';/** @var string SQL statement to get table columns. */var $metaColumnsSQL;/*** SQL statement to get the last IDENTITY value inserted into an IDENTITY* column in the same scope.* @see https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql* @var string*/var $identitySQL;/** @var string SQL statement to create a Sequence . */var $_genSeqSQL;/** @var string SQL statement to drop a Sequence. */var $_dropSeqSQL;/** @var string SQL statement to generate a Sequence ID. */var $_genIDSQL;var $uniqueOrderBy = false; /// All order by columns have to be uniquevar $emptyDate = ' ';var $emptyTimeStamp = ' ';var $lastInsID = false;//--var $hasInsertID = false; /// supports autoincrement ID?var $hasAffectedRows = false; /// supports affected rows for update/delete?var $hasTop = false; /// support mssql/access SELECT TOP 10 * FROM TABLEvar $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10var $readOnly = false; /// this is a readonly database - used by phpLensvar $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwardsvar $hasGenID = false; /// can generate sequences using GenID();var $hasTransactions = true; /// has transactions//--var $genID = 0; /// sequence id used by GenID();/** @var bool|callable Error function to call */var $raiseErrorFn = false;var $isoDates = false; /// accepts dates in ISO formatvar $cacheSecs = 3600; /// cache for 1 hour/****************************************** memcached server options******************************************//*** Use memCache library instead of caching in files.* @var bool $memCache*/public $memCache = false;/*** The memcache server(s) to connect to. Can be defined as:* - a single host name/ip address* - a list of hosts/ip addresses* - an array of server connection data (weighted server groups).* @link https://adodb.org/dokuwiki/doku.php?id=v5:userguide:memcached* @var string|array $memCacheHost*/public $memCacheHost;/*** Default port number.* The default port can be overridden if memcache server connection data* is provided as an array {@see $memCacheHost}.* @var int $memCachePort*/public $memCachePort = 11211;/*** Enable compression of stored items.* @var bool $memCacheCompress*/public $memCacheCompress = false;/*** An array of memcached options.* Only used with memcached; memcache ignores this setting.* @link https://www.php.net/manual/en/memcached.constants.php* @var array $memCacheOptions*/public $memCacheOptions = array();var $sysDate = false; /// name of function that returns the current datevar $sysTimeStamp = false; /// name of function that returns the current timestampvar $sysUTimeStamp = false; // name of function that returns the current timestamp accurate to the microsecond or nearest fractionvar $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsetsvar $noNullStrings = false; /// oracle specific stuff - if true ensures that '' is converted to ' 'var $numCacheHits = 0;var $numCacheMisses = 0;var $pageExecuteCountRows = true;var $uniqueSort = false; /// indicates that all fields in order by must be uniquevar $leftOuter = false; /// operator to use for left outer join in WHERE clausevar $rightOuter = false; /// operator to use for right outer join in WHERE clausevar $ansiOuter = false; /// whether ansi outer join syntax supportedvar $autoRollback = false; // autoRollback on PConnect().var $poorAffectedRows = false; // affectedRows not working or unreliable/** @var bool|callable Execute function to call */var $fnExecute = false;/** @var bool|callable Cache execution function to call */var $fnCacheExecute = false;var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to charvar $rsPrefix = "ADORecordSet_";var $autoCommit = true; /// do not modify this yourself - actually privatevar $transOff = 0; /// temporarily disable transactionsvar $transCnt = 0; /// count of nested transactionsvar $fetchMode=false;var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a nullvar $bulkBind = false; // enable 2D Execute array/** @var string SQL statement executed by some drivers after successful connection. */public $connectStmt = '';//// PRIVATE VARS//var $_oldRaiseFn = false;var $_transOK = null;/** @var resource Identifier for the native database connection */var $_connectionID = false;/*** Stores the last returned error message.* @see ADOConnection::errorMsg()* @var string|false*/var $_errorMsg = false;/*** Stores the last returned error code.* Not guaranteed to be used. Only some drivers actually populate it.* @var int|false*/var $_errorCode = false;var $_queryID = false; /// This variable keeps the last created result link identifiervar $_isPersistentConnection = false; /// A boolean variable to state whether its a persistent connection or normal connection. */var $_bindInputArray = false; /// set to true if ADOConnection.Execute() permits binding of array parameters./*** Eval string used to filter data.* Only used in the deprecated Text driver.* @see https://adodb.org/dokuwiki/doku.php?id=v5:database:text#workaround* @var string*/var $evalAll = false;var $_affected = false;var $_logsql = false;var $_transmode = ''; // transaction mode/*** Additional parameters that may be passed to drivers in the connect string.** Data is stored as an array of arrays and not a simple associative array,* because some drivers (e.g. mysql) allow multiple parameters with the same* key to be set.* @link https://github.com/ADOdb/ADOdb/issues/187** @see setConnectionParameter()** @var array $connectionParameters Set of ParameterName => Value pairs*/protected $connectionParameters = array();/** A simple associative array of user-defined custom actual/meta types*/public $customActualTypes = array();/** An array of user-defined custom meta/actual types.* $this->customMetaTypes[$meta] = array(* 'actual'=>'',* 'dictionary'=>'',* 'handler'=>'',* 'callback'=>''* );*/public $customMetaTypes = array();/** @var ADORecordSet Recordset used to retrieve MetaType information */var $_metars;/** @var string a specified locale. */var $locale;/*** Default Constructor.* We define it even though it does not actually do anything. This avoids* getting a PHP Fatal error: Cannot call constructor if a subclass tries* to call its parent constructor.*/public function __construct(){}/*** Adds a parameter to the connection string.** Parameters must be added before the connection is established;* they are then passed on to the connect statement, which will.* process them if the driver supports this feature.** Example usage:* - mssqlnative: setConnectionParameter('CharacterSet','UTF-8');* - mysqli: setConnectionParameter(MYSQLI_SET_CHARSET_NAME,'utf8mb4');** If used in a portable environment, parameters set in this manner should* be predicated on the database provider, as unexpected results may occur* if applied to the wrong database.** @param string $parameter The name of the parameter to set* @param string $value The value of the parameter** @return bool True if success, false otherwise (e.g. parameter is not valid)*/public function setConnectionParameter($parameter, $value) {$this->connectionParameters[] = array($parameter=>$value);return true;}/*** ADOdb version.** @return string*/static function Version() {global $ADODB_vers;// Semantic Version number matching regex$regex = '^[vV]?(\d+\.\d+\.\d+' // Version number (X.Y.Z) with optional 'V'. '(?:-(?:' // Optional preprod version: a '-'. 'dev|' // followed by 'dev'. '(?:(?:alpha|beta|rc)(?:\.\d+))' // or a preprod suffix and version number. '))?)(?:\s|$)'; // Whitespace or end of stringif (!preg_match("/$regex/", $ADODB_vers, $matches)) {// This should normally not happen... Return whatever is between the start// of the string and the first whitespace (or the end of the string).self::outp("Invalid version number: '$ADODB_vers'", 'Version');$regex = '^[vV]?(.*?)(?:\s|$)';preg_match("/$regex/", $ADODB_vers, $matches);}return $matches[1];}/*** Set a custom meta type with a corresponding actual** @param string $metaType The Custom ADOdb metatype* @param string $dictionaryType The database dictionary type* @param string $actualType The database actual type* @param bool $handleAsType handle like an existing Metatype* @param mixed $callBack A pre-processing function** @return bool success if the actual exists*/final public function setCustomMetaType($metaType,$dictionaryType,$actualType,$handleAsType=false,$callback=false){$this->customMetaTypes[strtoupper($metaType)] = array('actual'=>$actualType,'dictionary'=>strtoupper($dictionaryType),'handler'=>$handleAsType,'callback'=>$callback);/** Create a reverse lookup for the actualType*/$this->customActualTypes[$actualType] = $metaType;return true;}/*** Get a list of custom meta types.** @return string[]*/final public function getCustomMetaTypes(){return $this->customMetaTypes;}/*** Get server version info.** @return string[] Array with 2 string elements: version and description*/function ServerInfo() {return array('description' => '', 'version' => '');}/*** Return true if connected to the database.** @return bool*/function IsConnected() {return !empty($this->_connectionID);}/*** Find version string.** @param string $str** @return string*/function _findvers($str) {if (preg_match('/([0-9]+\.([0-9\.])+)/',$str, $arr)) {return $arr[1];} else {return '';}}/*** All error messages go through this bottleneck function.** You can define your own handler by defining the function name in ADODB_OUTP.** @param string $msg Message to print* @param bool $newline True to add a newline after printing $msg*/static function outp($msg,$newline=true) {global $ADODB_FLUSH,$ADODB_OUTP;if (defined('ADODB_OUTP')) {$fn = ADODB_OUTP;$fn($msg,$newline);return;} else if (isset($ADODB_OUTP)) {call_user_func($ADODB_OUTP,$msg,$newline);return;}if ($newline) {$msg .= "<br>\n";}if (isset($_SERVER['HTTP_USER_AGENT']) || !$newline) {echo $msg;} else {echo strip_tags($msg);}if (!empty($ADODB_FLUSH) && ob_get_length() !== false) {flush(); // do not flush if output buffering enabled - useless - thx to Jesse Mullan}}/*** Return the database server's current date and time.* @return int|false*/function Time() {$rs = $this->_Execute("select $this->sysTimeStamp");if ($rs && !$rs->EOF) {return $this->UnixTimeStamp(reset($rs->fields));}return false;}/*** Parses the hostname to extract the port.* Overwrites $this->host and $this->port, only if a port is specified.* The Hostname can be fully or partially qualified,* ie: "db.mydomain.com:5432" or "ldaps://ldap.mydomain.com:636"* Any specified scheme such as ldap:// or ldaps:// is maintained.*/protected function parseHostNameAndPort() {$parsed_url = parse_url($this->host);if (is_array($parsed_url) && isset($parsed_url['host']) && isset($parsed_url['port'])) {if ( isset($parsed_url['scheme']) ) {// If scheme is specified (ie: ldap:// or ldaps://, make sure we retain that.$this->host = $parsed_url['scheme'] . "://" . $parsed_url['host'];} else {$this->host = $parsed_url['host'];}$this->port = $parsed_url['port'];}}/*** Connect to database.** @param string $argHostname Host to connect to* @param string $argUsername Userid to login* @param string $argPassword Associated password* @param string $argDatabaseName Database name* @param bool $forceNew Force new connection** @return bool*/function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false) {if ($argHostname != "") {$this->host = $argHostname;}// Overwrites $this->host and $this->port if a port is specified.$this->parseHostNameAndPort();if ($argUsername != "") {$this->user = $argUsername;}if ($argPassword != "") {$this->password = 'not stored'; // not stored for security reasons}if ($argDatabaseName != "") {$this->database = $argDatabaseName;}$this->_isPersistentConnection = false;if ($forceNew) {if ($rez=$this->_nconnect($this->host, $this->user, $argPassword, $this->database)) {return true;}} else {if ($rez=$this->_connect($this->host, $this->user, $argPassword, $this->database)) {return true;}}if (isset($rez)) {$err = $this->ErrorMsg();$errno = $this->ErrorNo();if (empty($err)) {$err = "Connection error to server '$argHostname' with user '$argUsername'";}} else {$err = "Missing extension for ".$this->dataProvider;$errno = 0;}if ($fn = $this->raiseErrorFn) {$fn($this->databaseType, 'CONNECT', $errno, $err, $this->host, $this->database, $this);}$this->_connectionID = false;if ($this->debug) {ADOConnection::outp( $this->host.': '.$err);}return false;}/*** Always force a new connection to database.** @param string $argHostname Host to connect to* @param string $argUsername Userid to login* @param string $argPassword Associated password* @param string $argDatabaseName Database name** @return bool*/function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) {return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);}/*** Always force a new connection to database.** Currently this only works with Oracle.** @param string $argHostname Host to connect to* @param string $argUsername Userid to login* @param string $argPassword Associated password* @param string $argDatabaseName Database name** @return bool*/function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);}/*** Establish persistent connection to database.** @param string $argHostname Host to connect to* @param string $argUsername Userid to login* @param string $argPassword Associated password* @param string $argDatabaseName Database name** @return bool*/function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") {if (defined('ADODB_NEVER_PERSIST')) {return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);}if ($argHostname != "") {$this->host = $argHostname;}// Overwrites $this->host and $this->port if a port is specified.$this->parseHostNameAndPort();if ($argUsername != "") {$this->user = $argUsername;}if ($argPassword != "") {$this->password = 'not stored';}if ($argDatabaseName != "") {$this->database = $argDatabaseName;}$this->_isPersistentConnection = true;if ($rez = $this->_pconnect($this->host, $this->user, $argPassword, $this->database)) {return true;}if (isset($rez)) {$err = $this->ErrorMsg();if (empty($err)) {$err = "Connection error to server '$argHostname' with user '$argUsername'";}$ret = false;} else {$err = "Missing extension for ".$this->dataProvider;$ret = false;}if ($fn = $this->raiseErrorFn) {$fn($this->databaseType,'PCONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);}$this->_connectionID = false;if ($this->debug) {ADOConnection::outp( $this->host.': '.$err);}return $ret;}/*** Throw an exception if the handler is defined or prints the message if not.* @param string $msg Message* @param string $src the name of the calling function (in uppercase)* @param string $sql Optional offending SQL statement*/function outp_throw($msg, $src='WARN', $sql='') {if (defined('ADODB_ERROR_HANDLER') && ADODB_ERROR_HANDLER == 'adodb_throw') {adodb_throw($this->databaseType,$src,-9999,$msg,$sql,false,$this);return;}ADOConnection::outp($msg);}/*** Create cache class.** Code is backwards-compatible with old memcache implementation.*/function _CreateCache() {global $ADODB_CACHE, $ADODB_CACHE_CLASS;if ($this->memCache) {global $ADODB_INCLUDED_MEMCACHE;if (empty($ADODB_INCLUDED_MEMCACHE)) {include_once(ADODB_DIR.'/adodb-memcache.lib.inc.php');}$ADODB_CACHE = new ADODB_Cache_MemCache($this);} else {$ADODB_CACHE = new $ADODB_CACHE_CLASS($this);}}/*** Format date column in sql string.** See https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:sqldate* for documentation on supported formats.** @param string $fmt Format string* @param string $col Date column; use system date if not specified.** @return string*/function SQLDate($fmt, $col = '') {if (!$col) {$col = $this->sysDate;}return $col; // child class implement}/*** Prepare an SQL statement and return the statement resource.** For databases that do not support prepared statements, we return the* provided SQL statement as-is, to ensure compatibility:** $stmt = $db->prepare("insert into table (id, name) values (?,?)");* $db->execute($stmt, array(1,'Jill')) or die('insert failed');* $db->execute($stmt, array(2,'Joe')) or die('insert failed');** @param string $sql SQL to send to database** @return mixed|false The prepared statement, or the original sql if the* database does not support prepare.*/function Prepare($sql) {return $sql;}/*** Releases a previously prepared statement.** @param mixed $stmt Statement resource, as returned by {@see prepare()}** @return bool*/function releaseStatement(&$stmt) {return true;}/*** Prepare a Stored Procedure and return the statement resource.** Some databases, eg. mssql require a different function for preparing* stored procedures. So we cannot use Prepare().** For databases that do not support this, we return the $sql.** @param string $sql SQL to send to database* @param bool $param** @return mixed|false The prepared statement, or the original sql if the* database does not support prepare.*/function PrepareSP($sql,$param=true) {return $this->Prepare($sql,$param);}/*** PEAR DB Compat - alias for qStr.* @param $s* @return string*/function Quote($s) {return $this->qstr($s);}/*** Quotes a string so that all strings are escaped.* Wrapper for qstr with magic_quotes = false.** @param string &$s*/function q(&$s) {//if (!empty($this->qNull && $s == 'null') {// return $s;//}$s = $this->qstr($s);}/*** PEAR DB Compat - do not use internally.* @return int*/function ErrorNative() {return $this->ErrorNo();}/*** PEAR DB Compat - do not use internally.* @param string $seq_name* @return int*/function nextId($seq_name) {return $this->GenID($seq_name);}/*** Lock a row.* Will escalate and lock the table if row locking is not supported.* Will normally free the lock at the end of the transaction.** @param string $table name of table to lock* @param string $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock* @param string $col** @return bool*/function RowLock($table,$where,$col='1 as adodbignore') {return false;}/*** @param string $table* @return true*/function CommitLock($table) {return $this->CommitTrans();}/*** @param string $table* @return true*/function RollbackLock($table) {return $this->RollbackTrans();}/*** PEAR DB Compat - do not use internally.** The fetch modes for NUMERIC and ASSOC for PEAR DB and ADODB are identical* for easy porting :-)** @param int $mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM** @return int Previous fetch mode*/function SetFetchMode($mode) {$old = $this->fetchMode;$this->fetchMode = $mode;if ($old === false) {global $ADODB_FETCH_MODE;return $ADODB_FETCH_MODE;}return $old;}/*** PEAR DB Compat - do not use internally.** @param string $sql* @param array|bool $inputarr** @return ADORecordSet|bool*/function Query($sql, $inputarr=false) {$rs = $this->Execute($sql, $inputarr);if (!$rs && defined('ADODB_PEAR')) {return ADODB_PEAR_Error();}return $rs;}/*** PEAR DB Compat - do not use internally*/function LimitQuery($sql, $offset, $count, $params=false) {$rs = $this->SelectLimit($sql, $count, $offset, $params);if (!$rs && defined('ADODB_PEAR')) {return ADODB_PEAR_Error();}return $rs;}/*** PEAR DB Compat - do not use internally*/function Disconnect() {return $this->Close();}/*** Returns a placeholder for query parameters.** e.g. $DB->Param('a') will return* - '?' for most databases* - ':a' for Oracle* - '$1', '$2', etc. for PostgreSQL** @param mixed $name parameter's name.* For databases that require positioned params (e.g. PostgreSQL),* a "falsy" value can be used to force resetting the placeholder* count; using boolean 'false' will reset it without actually* returning a placeholder. ADOdb will also automatically reset* the count when executing a query.* @param string $type (unused)* @return string query parameter placeholder*/function Param($name,$type='C') {return '?';}/*** Self-documenting version of Parameter().** @param $stmt* @param &$var* @param $name* @param int $maxLen* @param bool $type** @return bool*/function InParameter(&$stmt, &$var, $name, $maxLen=4000, $type=false) {return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);}/*** Self-documenting version of Parameter().** @param $stmt* @param $var* @param $name* @param int $maxLen* @param bool $type** @return bool*/function OutParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) {return $this->Parameter($stmt,$var,$name,true,$maxLen,$type);}/**** Usage in oracle* $stmt = $db->Prepare('select * from table where id =:myid and group=:group');* $db->Parameter($stmt,$id,'myid');* $db->Parameter($stmt,$group,'group',64);* $db->Execute();** @param mixed &$stmt Statement returned by Prepare() or PrepareSP().* @param mixed &$var PHP variable to bind to* @param string $name Name of stored procedure variable name to bind to.* @param int|bool $isOutput Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.* @param int $maxLen Holds an maximum length of the variable.* @param mixed $type The data type of $var. Legal values depend on driver.** @return bool*/function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) {return false;}function IgnoreErrors($saveErrs=false) {if (!$saveErrs) {$saveErrs = array($this->raiseErrorFn,$this->_transOK);$this->raiseErrorFn = false;return $saveErrs;} else {$this->raiseErrorFn = $saveErrs[0];$this->_transOK = $saveErrs[1];}}/*** Improved method of initiating a transaction. Used together with CompleteTrans().* Advantages include:** a. StartTrans/CompleteTrans is nestable, unlike BeginTrans/CommitTrans/RollbackTrans.* Only the outermost block is treated as a transaction.<br>* b. CompleteTrans auto-detects SQL errors, and will rollback on errors, commit otherwise.<br>* c. All BeginTrans/CommitTrans/RollbackTrans inside a StartTrans/CompleteTrans block* are disabled, making it backward compatible.*/function StartTrans($errfn = 'ADODB_TransMonitor') {if ($this->transOff > 0) {$this->transOff += 1;return true;}$this->_oldRaiseFn = $this->raiseErrorFn;$this->raiseErrorFn = $errfn;$this->_transOK = true;if ($this->debug && $this->transCnt > 0) {ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");}$ok = $this->BeginTrans();$this->transOff = 1;return $ok;}/*** Complete a transation.** Used together with StartTrans() to end a transaction. Monitors connection* for sql errors, and will commit or rollback as appropriate.** @param bool autoComplete if true, monitor sql errors and commit and* rollback as appropriate, and if set to false* force rollback even if no SQL error detected.* @returns true on commit, false on rollback.*/function CompleteTrans($autoComplete = true) {if ($this->transOff > 1) {$this->transOff -= 1;return true;}$this->raiseErrorFn = $this->_oldRaiseFn;$this->transOff = 0;if ($this->_transOK && $autoComplete) {if (!$this->CommitTrans()) {$this->_transOK = false;if ($this->debug) {ADOConnection::outp("Smart Commit failed");}} else {if ($this->debug) {ADOConnection::outp("Smart Commit occurred");}}} else {$this->_transOK = false;$this->RollbackTrans();if ($this->debug) {ADOConnection::outp("Smart Rollback occurred");}}return $this->_transOK;}/*** At the end of a StartTrans/CompleteTrans block, perform a rollback.*/function FailTrans() {if ($this->debug)if ($this->transOff == 0) {ADOConnection::outp("FailTrans outside StartTrans/CompleteTrans");} else {ADOConnection::outp("FailTrans was called");adodb_backtrace();}$this->_transOK = false;}/*** Check if transaction has failed, only for Smart Transactions.*/function HasFailedTrans() {if ($this->transOff > 0) {return $this->_transOK == false;}return false;}/*** Execute SQL** @param string $sql SQL statement to execute, or possibly an array* holding prepared statement ($sql[0] will hold sql text)* @param array|bool $inputarr holds the input data to bind to.* Null elements will be set to null.** @return ADORecordSet|false*/public function Execute($sql, $inputarr = false) {if ($this->fnExecute) {$fn = $this->fnExecute;$ret = $fn($this,$sql,$inputarr);if (isset($ret)) {return $ret;}}if ($inputarr !== false) {if (!is_array($inputarr)) {$inputarr = array($inputarr);}$element0 = reset($inputarr);# is_object check because oci8 descriptors can be passed in$array_2d = $this->bulkBind && is_array($element0) && !is_object(reset($element0));//remove extra memory copy of input -mikefedykunset($element0);if (!is_array($sql) && !$this->_bindInputArray) {// @TODO this would consider a '?' within a string as a parameter...$sqlarr = explode('?',$sql);$nparams = sizeof($sqlarr)-1;if (!$array_2d) {// When not Bind Bulk - convert to array of arguments list$inputarr = array($inputarr);} else {// Bulk bind - Make sure all list of params have the same number of elements$countElements = array_map('count', $inputarr);if (1 != count(array_unique($countElements))) {$this->outp_throw("[bulk execute] Input array has different number of params [" . print_r($countElements, true) . "].",'Execute');return false;}unset($countElements);}// Make sure the number of parameters provided in the input// array matches what the query expects$element0 = reset($inputarr);if ($nparams != count($element0)) {$this->outp_throw("Input array has " . count($element0) ." params, does not match query: '" . htmlspecialchars($sql) . "'",'Execute');return false;}// clean memoryunset($element0);foreach($inputarr as $arr) {$sql = ''; $i = 0;foreach ($arr as $v) {$sql .= $sqlarr[$i];// from Ron Baldwin <ron.baldwin#sourceprose.com>// Only quote string types$typ = gettype($v);if ($typ == 'string') {//New memory copy of input created here -mikefedyk$sql .= $this->qstr($v);} else if ($typ == 'double') {$sql .= str_replace(',','.',$v); // locales fix so 1.1 does not get converted to 1,1} else if ($typ == 'boolean') {$sql .= $v ? $this->true : $this->false;} else if ($typ == 'object') {if (method_exists($v, '__toString')) {$sql .= $this->qstr($v->__toString());} else {$sql .= $this->qstr((string) $v);}} else if ($v === null) {$sql .= 'NULL';} else {$sql .= $v;}$i += 1;if ($i == $nparams) {break;}} // whileif (isset($sqlarr[$i])) {$sql .= $sqlarr[$i];if ($i+1 != sizeof($sqlarr)) {$this->outp_throw( "Input Array does not match ?: ".htmlspecialchars($sql),'Execute');}} else if ($i != sizeof($sqlarr)) {$this->outp_throw( "Input array does not match ?: ".htmlspecialchars($sql),'Execute');}$ret = $this->_Execute($sql);if (!$ret) {return $ret;}}} else {if ($array_2d) {if (is_string($sql)) {$stmt = $this->Prepare($sql);} else {$stmt = $sql;}foreach($inputarr as $arr) {$ret = $this->_Execute($stmt,$arr);if (!$ret) {return $ret;}}} else {$ret = $this->_Execute($sql,$inputarr);}}} else {$ret = $this->_Execute($sql,false);}return $ret;}function _Execute($sql,$inputarr=false) {// ExecuteCursor() may send non-string queries (such as arrays),// so we need to ignore those.if( is_string($sql) ) {// Strips keyword used to help generate SELECT COUNT(*) queries// from SQL if it exists.// TODO: obsoleted by #715 - kept for backwards-compatibility$sql = str_replace( '_ADODB_COUNT', '', $sql );}if ($this->debug) {global $ADODB_INCLUDED_LIB;if (empty($ADODB_INCLUDED_LIB)) {include_once(ADODB_DIR.'/adodb-lib.inc.php');}$this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);} else {$this->_queryID = @$this->_query($sql,$inputarr);}// ************************// OK, query executed// ************************// error handling if query failsif ($this->_queryID === false) {$fn = $this->raiseErrorFn;if ($fn) {$fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);}return false;}// return simplified recordset for inserts/updates/deletes with lower overheadif ($this->_queryID === true) {$rsclass = $this->rsPrefix.'empty';$rs = (class_exists($rsclass)) ? new $rsclass(): new ADORecordSet_empty();return $rs;}if ($this->dataProvider == 'pdo' && $this->databaseType != 'pdo') {// PDO uses a slightly different naming convention for the// recordset class if the database type is changed, so we must// treat it specifically. The mysql driver leaves the// databaseType as pdo$rsclass = $this->rsPrefix . 'pdo_' . $this->databaseType;} else {$rsclass = $this->rsPrefix . $this->databaseType;}// return real recordset from select statement$rs = new $rsclass($this->_queryID,$this->fetchMode);$rs->connection = $this; // Pablo suggestion$rs->Init();if (is_array($sql)) {$rs->sql = $sql[0];} else {$rs->sql = $sql;}if ($rs->_numOfRows <= 0) {global $ADODB_COUNTRECS;if ($ADODB_COUNTRECS) {if (!$rs->EOF) {$rs = $this->_rs2rs($rs,-1,-1,!is_array($sql));$rs->_queryID = $this->_queryID;} else$rs->_numOfRows = 0;}}return $rs;}/*** Execute a query.** @param string|array $sql Query to execute.* @param array $inputarr An optional array of parameters.** @return mixed|bool Query identifier or true if execution successful, false if failed.*/function _query($sql, $inputarr = false) {return false;}function CreateSequence($seqname='adodbseq',$startID=1) {if (empty($this->_genSeqSQL)) {return false;}return $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));}function DropSequence($seqname='adodbseq') {if (empty($this->_dropSeqSQL)) {return false;}return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));}/*** Generates a sequence id and stores it in $this->genID.** GenID is only available if $this->hasGenID = true;** @param string $seqname Name of sequence to use* @param int $startID If sequence does not exist, start at this ID** @return int Sequence id, 0 if not supported*/function GenID($seqname='adodbseq',$startID=1) {if (!$this->hasGenID) {return 0; // formerly returns false pre 1.60}$getnext = sprintf($this->_genIDSQL,$seqname);$holdtransOK = $this->_transOK;$save_handler = $this->raiseErrorFn;$this->raiseErrorFn = '';@($rs = $this->Execute($getnext));$this->raiseErrorFn = $save_handler;if (!$rs) {$this->_transOK = $holdtransOK; //if the status was ok before reset$createseq = $this->Execute(sprintf($this->_genSeqSQL,$seqname,$startID));$rs = $this->Execute($getnext);}if ($rs && !$rs->EOF) {$this->genID = reset($rs->fields);} else {$this->genID = 0; // false}if ($rs) {$rs->Close();}return $this->genID;}/*** Returns the last inserted ID.** Not all databases support this feature. Some do not require to specify* table or column name (e.g. MySQL).** @param string $table Table name, default ''* @param string $column Column name, default ''** @return int The last inserted ID.*/function Insert_ID($table='',$column='') {if ($this->_logsql && $this->lastInsID) {return $this->lastInsID;}if ($this->hasInsertID) {return $this->_insertID($table,$column);}if ($this->debug) {ADOConnection::outp( '<p>Insert_ID error</p>');adodb_backtrace();}return false;}/*** Enable or disable the Last Insert Id functionality.** If the Driver supports it, this function allows setting {@see $hasInsertID}.** @param bool $enable False to disable*/public function enableLastInsertID($enable = true) {}/*** Return the id of the last row that has been inserted in a table.** @param string $table* @param string $column** @return int|false*/protected function _insertID($table = '', $column = ''){return false;}/*** Portable Insert ID. Pablo Roca <pabloroca#mvps.org>** @param string $table* @param string $id* @return mixed The last inserted ID. All databases support this, but be* aware of possible problems in multiuser environments.* Heavily test this before deploying.*/function PO_Insert_ID($table="", $id="") {if ($this->hasInsertID){return $this->Insert_ID($table,$id);} else {return $this->GetOne("SELECT MAX($id) FROM $table");}}/*** @return int|false Number of rows affected by UPDATE/DELETE*/function Affected_Rows() {if ($this->hasAffectedRows) {if ($this->fnExecute === 'adodb_log_sql') {if ($this->_logsql && $this->_affected !== false) {return $this->_affected;}}$val = $this->_affectedrows();return ($val < 0) ? false : $val;}if ($this->debug) {ADOConnection::outp( '<p>Affected_Rows error</p>',false);}return false;}/*** @return string the last error message*/function ErrorMsg() {if ($this->_errorMsg) {return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;} else {return '';}}/*** @return int the last error number. Normally 0 means no error.*/function ErrorNo() {return ($this->_errorMsg) ? -1 : 0;}function MetaError($err=false) {include_once(ADODB_DIR."/adodb-error.inc.php");if ($err === false) {$err = $this->ErrorNo();}return adodb_error($this->dataProvider,$this->databaseType,$err);}function MetaErrorMsg($errno) {include_once(ADODB_DIR."/adodb-error.inc.php");return adodb_errormsg($errno);}/*** @returns an array with the primary key columns in it.*/function MetaPrimaryKeys($table, $owner=false) {// owner not used in base class - see oci8$p = array();$objs = $this->MetaColumns($table);if ($objs) {foreach($objs as $v) {if (!empty($v->primary_key)) {$p[] = $v->name;}}}if (sizeof($p)) {return $p;}if (function_exists('ADODB_VIEW_PRIMARYKEYS')) {return ADODB_VIEW_PRIMARYKEYS($this->databaseType, $this->database, $table, $owner);}return false;}/*** Returns a list of Foreign Keys associated with a specific table.** If there are no foreign keys then the function returns false.** @param string $table The name of the table to get the foreign keys for.* @param string $owner Table owner/schema.* @param bool $upper If true, only matches the table with the uppercase name.* @param bool $associative Returns the result in associative mode;* if ADODB_FETCH_MODE is already associative, then* this parameter is discarded.** @return string[]|false An array where keys are tables, and values are foreign keys;* false if no foreign keys could be found.*/function metaForeignKeys($table, $owner = '', $upper = false, $associative = false) {return false;}/*** Choose a database to connect to. Many databases do not support this.** @param string $dbName the name of the database to select* @return bool*/function SelectDB($dbName) {return false;}/*** Select a limited number of rows.** Will select, getting rows from $offset (1-based), for $nrows.* This simulates the MySQL "select * from table limit $offset,$nrows" , and* the PostgreSQL "select * from table limit $nrows offset $offset". Note that* MySQL and PostgreSQL parameter ordering is the opposite of the other.* eg.* SelectLimit('select * from table',3); will return rows 1 to 3 (1-based)* SelectLimit('select * from table',3,2); will return rows 3 to 5 (1-based)** Uses SELECT TOP for Microsoft databases (when $this->hasTop is set)* BUG: Currently SelectLimit fails with $sql with LIMIT or TOP clause already set** @param string $sql* @param int $offset Row to start calculations from (1-based)* @param int $nrows Number of rows to get* @param array|bool $inputarr Array of bind variables* @param int $secs2cache Private parameter only used by jlim** @return ADORecordSet The recordset ($rs->databaseType == 'array')*/function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) {$nrows = (int)$nrows;$offset = (int)$offset;if ($this->hasTop && $nrows > 0) {// suggested by Reinhard Balling. Access requires top after distinct// Informix requires first before distinct - F Riosa$ismssql = (strpos($this->databaseType,'mssql') !== false);if ($ismssql) {$isaccess = false;} else {$isaccess = (strpos($this->databaseType,'access') !== false);}if ($offset <= 0) {// access includes ties in resultif ($isaccess) {$sql = preg_replace('/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);if ($secs2cache != 0) {$ret = $this->CacheExecute($secs2cache, $sql,$inputarr);} else {$ret = $this->Execute($sql,$inputarr);}return $ret; // PHP5 fix} else if ($ismssql){$sql = preg_replace('/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);} else {$sql = preg_replace('/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nrows.' ',$sql);}} else {$nn = $nrows + $offset;if ($isaccess || $ismssql) {$sql = preg_replace('/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);} else {$sql = preg_replace('/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.$nn.' ',$sql);}}}// if $offset>0, we want to skip rows, and $ADODB_COUNTRECS is set, we buffer rows// 0 to offset-1 which will be discarded anyway. So we disable $ADODB_COUNTRECS.global $ADODB_COUNTRECS;try {$savec = $ADODB_COUNTRECS;$ADODB_COUNTRECS = false;if ($secs2cache != 0) {$rs = $this->CacheExecute($secs2cache, $sql, $inputarr);} else {$rs = $this->Execute($sql, $inputarr);}} finally {$ADODB_COUNTRECS = $savec;}if ($rs && !$rs->EOF) {$rs = $this->_rs2rs($rs,$nrows,$offset);}//print_r($rs);return $rs;}/*** Create serializable recordset. Breaks rs link to connection.** @param ADORecordSet $rs the recordset to serialize** @return ADORecordSet_array|bool the new recordset*/function SerializableRS(&$rs) {$rs2 = $this->_rs2rs($rs);$ignore = false;$rs2->connection = $ignore;return $rs2;}/*** Convert a database recordset to an array recordset.** Input recordset's cursor should be at beginning, and old $rs will be closed.** @param ADORecordSet $rs the recordset to copy* @param int $nrows number of rows to retrieve (optional)* @param int $offset offset by number of rows (optional)* @param bool $close** @return ADORecordSet_array|ADORecordSet|bool the new recordset*/function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true) {if (! $rs) {$ret = false;return $ret;}$dbtype = $rs->databaseType;if (!$dbtype) {$rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1 -- why ?return $rs;}if (($dbtype == 'array' || $dbtype == 'csv') && $nrows == -1 && $offset == -1) {$rs->MoveFirst();$rs = $rs; // required to prevent crashing in 4.2.1, but does not happen in 4.3.1-- why ?return $rs;}$flds = array();for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {$flds[] = $rs->FetchField($i);}$arr = $rs->GetArrayLimit($nrows,$offset);//print_r($arr);if ($close) {$rs->Close();}$arrayClass = $this->arrayClass;$rs2 = new $arrayClass($fakeQueryId=1);$rs2->connection = $this;$rs2->sql = $rs->sql;$rs2->dataProvider = $this->dataProvider;$rs2->InitArrayFields($arr,$flds);$rs2->fetchMode = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;return $rs2;}/*** Return all rows.** Compat with PEAR DB.** @param string $sql SQL statement* @param array|bool $inputarr Input bind array** @return array|false*/function GetAll($sql, $inputarr=false) {return $this->GetArray($sql,$inputarr);}/*** Execute statement and return rows in an array.** The function executes a statement and returns all of the returned rows in* an array, or false if the statement execution fails or if only 1 column* is requested in the SQL statement.* If no records match the provided SQL statement, an empty array is returned.** @param string $sql SQL statement* @param array|bool $inputarr input bind array* @param bool $force_array* @param bool $first2cols** @return array|bool*/public function GetAssoc($sql, $inputarr = false, $force_array = false, $first2cols = false) {$rs = $this->Execute($sql, $inputarr);if (!$rs) {/** Execution failure*/return false;}return $rs->GetAssoc($force_array, $first2cols);}/*** Search for the results of an executed query in the cache.** @param int $secs2cache* @param string|bool $sql SQL statement* @param array|bool $inputarr input bind array* @param bool $force_array* @param bool $first2cols** @return false|array*/public function CacheGetAssoc($secs2cache, $sql = false, $inputarr = false,$force_array = false, $first2cols = false) {if (!is_numeric($secs2cache)) {$first2cols = $force_array;$force_array = $inputarr;}$rs = $this->CacheExecute($secs2cache, $sql, $inputarr);if (!$rs) {return false;}return $rs->GetAssoc($force_array, $first2cols);}/*** Return first element of first row of sql statement. Recordset is disposed* for you.** @param string $sql SQL statement* @param array|bool $inputarr input bind array* @return mixed*/public function GetOne($sql, $inputarr=false) {global $ADODB_COUNTRECS,$ADODB_GETONE_EOF;try {$crecs = $ADODB_COUNTRECS;$ADODB_COUNTRECS = false;$rs = $this->Execute($sql, $inputarr);} finally {$ADODB_COUNTRECS = $crecs;}$ret = false;if ($rs) {if ($rs->EOF) {$ret = $ADODB_GETONE_EOF;} else {$ret = reset($rs->fields);}$rs->Close();}return $ret;}// $where should include 'WHERE fld=value'function GetMedian($table, $field,$where = '') {$total = $this->GetOne("select count(*) from $table $where");if (!$total) {return false;}$midrow = (integer) ($total/2);$rs = $this->SelectLimit("select $field from $table $where order by 1",1,$midrow);if ($rs && !$rs->EOF) {return reset($rs->fields);}return false;}function CacheGetOne($secs2cache,$sql=false,$inputarr=false) {global $ADODB_GETONE_EOF;$ret = false;$rs = $this->CacheExecute($secs2cache,$sql,$inputarr);if ($rs) {if ($rs->EOF) {$ret = $ADODB_GETONE_EOF;} else {$ret = reset($rs->fields);}$rs->Close();}return $ret;}/*** Executes a statement and returns each row's first column in an array.** @param string $sql SQL statement* @param array|bool $inputarr input bind array* @param bool $trim enables space trimming of the returned value.* This is only relevant if the returned string* is coming from a CHAR type field.** @return array|bool 1D array containning the first row of the query*/function GetCol($sql, $inputarr = false, $trim = false) {$rs = $this->Execute($sql, $inputarr);if ($rs) {$rv = array();if ($trim) {while (!$rs->EOF) {$rv[] = trim(reset($rs->fields));$rs->MoveNext();}} else {while (!$rs->EOF) {$rv[] = reset($rs->fields);$rs->MoveNext();}}$rs->Close();} else {$rv = false;}return $rv;}function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false) {$rs = $this->CacheExecute($secs, $sql, $inputarr);if ($rs) {$rv = array();if ($trim) {while (!$rs->EOF) {$rv[] = trim(reset($rs->fields));$rs->MoveNext();}} else {while (!$rs->EOF) {$rv[] = reset($rs->fields);$rs->MoveNext();}}$rs->Close();} else$rv = false;return $rv;}/*** Calculate the offset of a date for a particular database* and generate appropriate SQL.** Useful for calculating future/past dates and storing in a database.** @param double $dayFraction 1.5 means 1.5 days from now, 1.0/24 for 1 hour* @param string|false $date Reference date, false for system time** @return string*/function OffsetDate($dayFraction,$date=false) {if (!$date) {$date = $this->sysDate;}return '('.$date.'+'.$dayFraction.')';}/*** Executes a statement and returns a the entire recordset in an array.** @param string $sql SQL statement* @param array|bool $inputarr input bind array** @return array|false*/function GetArray($sql,$inputarr=false) {global $ADODB_COUNTRECS;try {$savec = $ADODB_COUNTRECS;$ADODB_COUNTRECS = false;$rs = $this->Execute($sql, $inputarr);} finally {$ADODB_COUNTRECS = $savec;}if (!$rs)if (defined('ADODB_PEAR')) {return ADODB_PEAR_Error();} else {return false;}$arr = $rs->GetArray();$rs->Close();return $arr;}function CacheGetAll($secs2cache,$sql=false,$inputarr=false) {return $this->CacheGetArray($secs2cache,$sql,$inputarr);}function CacheGetArray($secs2cache,$sql=false,$inputarr=false) {global $ADODB_COUNTRECS;try {$savec = $ADODB_COUNTRECS;$ADODB_COUNTRECS = false;$rs = $this->CacheExecute($secs2cache, $sql, $inputarr);} finally {$ADODB_COUNTRECS = $savec;}if (!$rs)if (defined('ADODB_PEAR')) {return ADODB_PEAR_Error();} else {return false;}$arr = $rs->GetArray();$rs->Close();return $arr;}function GetRandRow($sql, $arr= false) {$rezarr = $this->GetAll($sql, $arr);$sz = sizeof($rezarr);return $rezarr[abs(rand()) % $sz];}/*** Return one row of sql statement. Recordset is disposed for you.* Note that SelectLimit should not be called.** @param string $sql SQL statement* @param array|bool $inputarr input bind array** @return array|false Array containing the first row of the query*/function GetRow($sql,$inputarr=false) {global $ADODB_COUNTRECS;try {$crecs = $ADODB_COUNTRECS;$ADODB_COUNTRECS = false;$rs = $this->Execute($sql, $inputarr);} finally {$ADODB_COUNTRECS = $crecs;}if ($rs) {if (!$rs->EOF) {$arr = $rs->fields;} else {$arr = array();}$rs->Close();return $arr;}return false;}/*** @param int $secs2cache* @param string|false $sql* @param mixed[]|bool $inputarr* @return mixed[]|bool*/function CacheGetRow($secs2cache,$sql=false,$inputarr=false) {$rs = $this->CacheExecute($secs2cache,$sql,$inputarr);if ($rs) {if (!$rs->EOF) {$arr = $rs->fields;} else {$arr = array();}$rs->Close();return $arr;}return false;}/*** Insert or replace a single record. Note: this is not the same as MySQL's replace.* ADOdb's Replace() uses update-insert semantics, not insert-delete-duplicates of MySQL.* Also note that no table locking is done currently, so it is possible that the* record be inserted twice by two programs...** $this->Replace('products', array('prodname' =>"'Nails'","price" => 3.99), 'prodname');** $table table name* $fieldArray associative array of data (you must quote strings yourself).* $keyCol the primary key field name or if compound key, array of field names* autoQuote set to true to use a heuristic to quote strings. Works with nulls and numbers* but does not work with dates nor SQL functions.* has_autoinc the primary key is an auto-inc field, so skip in insert.** Currently blob replace not supported** returns 0 = fail, 1 = update, 2 = insert*/function Replace($table, $fieldArray, $keyCol, $autoQuote=false, $has_autoinc=false) {global $ADODB_INCLUDED_LIB;if (empty($ADODB_INCLUDED_LIB)) {include_once(ADODB_DIR.'/adodb-lib.inc.php');}return _adodb_replace($this, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc);}/*** Will select, getting rows from $offset (1-based), for $nrows.* This simulates the MySQL "select * from table limit $offset,$nrows" , and* the PostgreSQL "select * from table limit $nrows offset $offset". Note that* MySQL and PostgreSQL parameter ordering is the opposite of the other.* eg.* CacheSelectLimit(15,'select * from table',3); will return rows 1 to 3 (1-based)* CacheSelectLimit(15,'select * from table',3,2); will return rows 3 to 5 (1-based)** BUG: Currently CacheSelectLimit fails with $sql with LIMIT or TOP clause already set** @param int $secs2cache Seconds to cache data, set to 0 to force query. This is optional* @param string $sql* @param int $offset Row to start calculations from (1-based)* @param int $nrows Number of rows to get* @param array $inputarr Array of bind variables** @return ADORecordSet The recordset ($rs->databaseType == 'array')*/function CacheSelectLimit($secs2cache,$sql,$nrows=-1,$offset=-1,$inputarr=false) {if (!is_numeric($secs2cache)) {if ($sql === false) {$sql = -1;}if ($offset == -1) {$offset = false;}// sql, nrows, offset,inputarr$rs = $this->SelectLimit($secs2cache,$sql,$nrows,$offset,$this->cacheSecs);} else {if ($sql === false) {$this->outp_throw("Warning: \$sql missing from CacheSelectLimit()",'CacheSelectLimit');}$rs = $this->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);}return $rs;}/*** Flush cached recordsets that match a particular $sql statement.* If $sql == false, then we purge all files in the cache.*/function CacheFlush($sql=false,$inputarr=false) {global $ADODB_CACHE_DIR, $ADODB_CACHE;# Create cache if it does not existif (empty($ADODB_CACHE)) {$this->_CreateCache();}if (!$sql) {$ADODB_CACHE->flushall($this->debug);return;}$f = $this->_gencachename($sql.serialize($inputarr),false);return $ADODB_CACHE->flushcache($f, $this->debug);}/*** Private function to generate filename for caching.* Filename is generated based on:** - sql statement* - database type (oci8, ibase, ifx, etc)* - database name* - userid* - setFetchMode (adodb 4.23)** We create 256 sub-directories in the cache directory ($ADODB_CACHE_DIR).* Assuming that we can have 50,000 files per directory with good performance,* then we can scale to 12.8 million unique cached recordsets. Wow!*/function _gencachename($sql,$createdir) {global $ADODB_CACHE, $ADODB_CACHE_DIR;if ($this->fetchMode === false) {global $ADODB_FETCH_MODE;$mode = $ADODB_FETCH_MODE;} else {$mode = $this->fetchMode;}$m = md5($sql.$this->databaseType.$this->database.$this->user.$mode);if (!$ADODB_CACHE->createdir) {return $m;}if (!$createdir) {$dir = $ADODB_CACHE->getdirname($m);} else {$dir = $ADODB_CACHE->createdir($m, $this->debug);}return $dir.'/adodb_'.$m.'.cache';}/*** Execute SQL, caching recordsets.** @param int $secs2cache Seconds to cache data, set to 0 to force query.* This is an optional parameter.* @param string|bool $sql SQL statement to execute* @param array|bool $inputarr Holds the input data to bind** @return ADORecordSet RecordSet or false*/function CacheExecute($secs2cache,$sql=false,$inputarr=false) {global $ADODB_CACHE;if (empty($ADODB_CACHE)) {$this->_CreateCache();}if (!is_numeric($secs2cache)) {$inputarr = $sql;$sql = $secs2cache;$secs2cache = $this->cacheSecs;}if (is_array($sql)) {$sqlparam = $sql;$sql = $sql[0];} else$sqlparam = $sql;$md5file = $this->_gencachename($sql.serialize($inputarr),true);$err = '';if ($secs2cache > 0){$rs = $ADODB_CACHE->readcache($md5file,$err,$secs2cache,$this->arrayClass);$this->numCacheHits += 1;} else {$err='Timeout 1';$rs = false;$this->numCacheMisses += 1;}if (!$rs) {// no cached rs foundif ($this->debug) {if ($this->debug !== -1) {ADOConnection::outp( " $md5file cache failure: $err (this is a notice and not an error)");}}$rs = $this->Execute($sqlparam,$inputarr);if ($rs) {$eof = $rs->EOF;$rs = $this->_rs2rs($rs); // read entire recordset into memory immediately$rs->timeCreated = time(); // used by caching$txt = _rs2serialize($rs,false,$sql); // serialize$ok = $ADODB_CACHE->writecache($md5file,$txt,$this->debug, $secs2cache);if (!$ok) {if ($ok === false) {$em = 'Cache write error';$en = -32000;if ($fn = $this->raiseErrorFn) {$fn($this->databaseType,'CacheExecute', $en, $em, $md5file,$sql,$this);}} else {$em = 'Cache file locked warning';$en = -32001;// do not call error handling for just a warning}if ($this->debug) {ADOConnection::outp( " ".$em);}}if ($rs->EOF && !$eof) {$rs->MoveFirst();//$rs = csv2rs($md5file,$err);$rs->connection = $this; // Pablo suggestion}} else if (!$this->memCache) {$ADODB_CACHE->flushcache($md5file);}} else {$this->_errorMsg = '';$this->_errorCode = 0;if ($this->fnCacheExecute) {$fn = $this->fnCacheExecute;$fn($this, $secs2cache, $sql, $inputarr);}// ok, set cached object found$rs->connection = $this; // Pablo suggestionif ($this->debug){if ($this->debug == 99) {adodb_backtrace();}$inBrowser = isset($_SERVER['HTTP_USER_AGENT']);$ttl = $rs->timeCreated + $secs2cache - time();$s = is_array($sql) ? $sql[0] : $sql;if ($inBrowser) {$s = '<i>'.htmlspecialchars($s).'</i>';}ADOConnection::outp( " $md5file reloaded, ttl=$ttl [ $s ]");}}return $rs;}/*** Simple interface to insert and update records.** Automatically generate and execute INSERT and UPDATE statements* on a given table, similar to PEAR DB's autoExecute().** @param string $table Name of the table to process.* @param array $fields_values Associative array of field names => values.* @param string|int $mode Execution mode: 'INSERT' (default), 'UPDATE' or* one of the DB_AUTOQUERY_xx constants.* @param string $where SQL where clause (mandatory in UPDATE mode as a safety measure)* @param bool $forceUpdate If true, update all provided fields, even if they have not changed;* otherwise only modified fields are updated.* @param bool $magic_quotes This param is not used since 5.21.0.* It remains for backwards compatibility.** @return bool** @noinspection PhpUnusedParameterInspection*/function autoExecute($table, $fields_values, $mode = 'INSERT', $where = '', $forceUpdate = true, $magic_quotes = false) {if (empty($fields_values)) {$this->outp_throw('AutoExecute: Empty fields array', 'AutoExecute');return false;}if (empty($where) && ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */)) {$this->outp_throw('AutoExecute: Illegal mode=UPDATE with empty WHERE clause', 'AutoExecute');return false;}$sql = "SELECT * FROM $table";$rs = $this->SelectLimit($sql, 1);if (!$rs) {return false; // table does not exist}$rs->tableName = $table;if (!empty($where)) {$sql .= " WHERE $where";}$rs->sql = $sql;switch($mode) {case 'UPDATE':case DB_AUTOQUERY_UPDATE:$sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate);break;case 'INSERT':case DB_AUTOQUERY_INSERT:$sql = $this->GetInsertSQL($rs, $fields_values);break;default:$this->outp_throw("AutoExecute: Unknown mode=$mode", 'AutoExecute');return false;}return $sql && $this->Execute($sql);}/*** Generates an Update Query based on an existing recordset.** $arrFields is an associative array of fields with the value* that should be assigned.** Note: This function should only be used on a recordset* that is run against a single table and sql should only* be a simple select stmt with no groupby/orderby/limit* @author "Jonathan Younger" <jyounger@unilab.com>** @param $rs* @param $arrFields* @param bool $forceUpdate* @param bool $magic_quotes This param is not used since 5.21.0.* It remains for backwards compatibility.* @param null $force** @return false|string** @noinspection PhpUnusedParameterInspection*/function GetUpdateSQL(&$rs, $arrFields, $forceUpdate=false, $magic_quotes=false, $force=null) {global $ADODB_INCLUDED_LIB;// ********************************************************// This is here to maintain compatibility// with older adodb versions. Sets force type to force nulls if $forcenulls is set.if (!isset($force)) {global $ADODB_FORCE_TYPE;$force = $ADODB_FORCE_TYPE;}// ********************************************************if (empty($ADODB_INCLUDED_LIB)) {include_once(ADODB_DIR.'/adodb-lib.inc.php');}return _adodb_getupdatesql($this, $rs, $arrFields, $forceUpdate, $force);}/*** Generates an Insert Query based on an existing recordset.** $arrFields is an associative array of fields with the value* that should be assigned.** Note: This function should only be used on a recordset* that is run against a single table.** @param $rs* @param $arrFields* @param bool $magic_quotes This param is not used since 5.21.0.* It remains for backwards compatibility.* @param null $force** @return false|string** @noinspection PhpUnusedParameterInspection*/function GetInsertSQL(&$rs, $arrFields, $magic_quotes=false, $force=null) {global $ADODB_INCLUDED_LIB;if (!isset($force)) {global $ADODB_FORCE_TYPE;$force = $ADODB_FORCE_TYPE;}if (empty($ADODB_INCLUDED_LIB)) {include_once(ADODB_DIR.'/adodb-lib.inc.php');}return _adodb_getinsertsql($this, $rs, $arrFields, $force);}/*** Update a BLOB column, given a where clause.** There are more sophisticated blob handling functions that we could have* implemented, but all require a very complex API. Instead we have chosen* something that is extremely simple to understand and use.** Sample usage:* - update a BLOB in field table.blob_col with value $blobValue, for a* record having primary key id=1* $conn->updateBlob('table', 'blob_col', $blobValue, 'id=1');* - insert example:* $conn->execute('INSERT INTO table (id, blob_col) VALUES (1, null)');* $conn->updateBlob('table', 'blob_col', $blobValue, 'id=1');** @param string $table* @param string $column* @param string $val Filename containing blob data* @param mixed $where {@see updateBlob()}* @param string $blobtype supports 'BLOB' (default) and 'CLOB'** @return bool success*/function updateBlob($table, $column, $val, $where, $blobtype='BLOB') {return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;}/*** Update a BLOB from a file.** Usage example:* $conn->updateBlobFile('table', 'blob_col', '/path/to/file', 'id=1');** @param string $table* @param string $column* @param string $path Filename containing blob data* @param mixed $where {@see updateBlob()}* @param string $blobtype supports 'BLOB' and 'CLOB'** @return bool success*/function updateBlobFile($table, $column, $path, $where, $blobtype='BLOB') {$fd = fopen($path,'rb');if ($fd === false) {return false;}$val = fread($fd,filesize($path));fclose($fd);return $this->UpdateBlob($table,$column,$val,$where,$blobtype);}function BlobDecode($blob) {return $blob;}function BlobEncode($blob) {return $blob;}/*** Retrieve the client connection's current character set.** @return string|false The character set, or false if it can't be determined.*/function getCharSet() {return $this->charSet;}/*** Sets the client-side character set.** This is only supported for some databases.* @see https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:setcharset** @param string $charset The character set to switch to.** @return bool True if the character set was changed successfully, false otherwise.*/function setCharSet($charset) {$this->charSet = $charset;return true;}function IfNull( $field, $ifNull ) {return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";}function LogSQL($enable=true) {include_once(ADODB_DIR.'/adodb-perf.inc.php');if ($enable) {$this->fnExecute = 'adodb_log_sql';} else {$this->fnExecute = false;}$old = $this->_logsql;$this->_logsql = $enable;if ($enable && !$old) {$this->_affected = false;}return $old;}/*** Usage:* UpdateClob('TABLE', 'COLUMN', $var, 'ID=1', 'CLOB');** $conn->Execute('INSERT INTO clobtable (id, clobcol) VALUES (1, null)');* $conn->UpdateClob('clobtable','clobcol',$clob,'id=1');*/function UpdateClob($table,$column,$val,$where) {return $this->UpdateBlob($table,$column,$val,$where,'CLOB');}// not the fastest implementation - quick and dirty - jlim// for best performance, use the actual $rs->MetaType().function MetaType($t,$len=-1,$fieldobj=false) {if (empty($this->_metars)) {$rsclass = $this->rsPrefix.$this->databaseType;$this->_metars = new $rsclass(false,$this->fetchMode);$this->_metars->connection = $this;}return $this->_metars->MetaType($t,$len,$fieldobj);}/*** Change the SQL connection locale to a specified locale.* This is used to get the date formats written depending on the client locale.*/function SetDateLocale($locale = 'En') {$this->locale = $locale;switch (strtoupper($locale)){case 'EN':$this->fmtDate="'Y-m-d'";$this->fmtTimeStamp = "'Y-m-d H:i:s'";break;case 'US':$this->fmtDate = "'m-d-Y'";$this->fmtTimeStamp = "'m-d-Y H:i:s'";break;case 'PT_BR':case 'NL':case 'FR':case 'RO':case 'IT':$this->fmtDate="'d-m-Y'";$this->fmtTimeStamp = "'d-m-Y H:i:s'";break;case 'GE':$this->fmtDate="'d.m.Y'";$this->fmtTimeStamp = "'d.m.Y H:i:s'";break;default:$this->fmtDate="'Y-m-d'";$this->fmtTimeStamp = "'Y-m-d H:i:s'";break;}}/*** GetActiveRecordsClass Performs an 'ALL' query** @param mixed $class This string represents the class of the current active record* @param mixed $table Table used by the active record object* @param mixed $whereOrderBy Where, order, by clauses* @param mixed $bindarr* @param mixed $primkeyArr* @param array $extra Query extras: limit, offset...* @param mixed $relations Associative array: table's foreign name, "hasMany", "belongsTo"* @access public* @return void*/function GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false,$extra=array(),$relations=array()){global $_ADODB_ACTIVE_DBS;## reduce overhead of adodb.inc.php -- moved to adodb-active-record.inc.php## if adodb-active-recordx is loaded -- should be no issue as they will probably use Find()if (!isset($_ADODB_ACTIVE_DBS)) {include_once(ADODB_DIR.'/adodb-active-record.inc.php');}return adodb_GetActiveRecordsClass($this, $class, $table, $whereOrderBy, $bindarr, $primkeyArr, $extra, $relations);}function GetActiveRecords($table,$where=false,$bindarr=false,$primkeyArr=false) {$arr = $this->GetActiveRecordsClass('ADODB_Active_Record', $table, $where, $bindarr, $primkeyArr);return $arr;}/*** Close Connection*/function Close() {$rez = $this->_close();$this->_queryID = false;$this->_connectionID = false;return $rez;}/*** Begin a Transaction.** Must be followed by CommitTrans() or RollbackTrans().** @return bool true if succeeded or false if database does not support transactions*/function BeginTrans() {if ($this->debug) {ADOConnection::outp("BeginTrans: Transactions not supported for this driver");}return false;}/* set transaction mode */function SetTransactionMode( $transaction_mode ) {$transaction_mode = $this->MetaTransaction($transaction_mode, $this->dataProvider);$this->_transmode = $transaction_mode;}/*http://msdn2.microsoft.com/en-US/ms173763.aspxhttp://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.htmlhttp://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.htmlhttp://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/statements_10005.htm*/function MetaTransaction($mode,$db) {$mode = strtoupper($mode);$mode = str_replace('ISOLATION LEVEL ','',$mode);switch($mode) {case 'READ UNCOMMITTED':switch($db) {case 'oci8':case 'oracle':return 'ISOLATION LEVEL READ COMMITTED';default:return 'ISOLATION LEVEL READ UNCOMMITTED';}break;case 'READ COMMITTED':return 'ISOLATION LEVEL READ COMMITTED';break;case 'REPEATABLE READ':switch($db) {case 'oci8':case 'oracle':return 'ISOLATION LEVEL SERIALIZABLE';default:return 'ISOLATION LEVEL REPEATABLE READ';}break;case 'SERIALIZABLE':return 'ISOLATION LEVEL SERIALIZABLE';break;default:return $mode;}}/*** Commits a transaction.** If database does not support transactions, return true as data is* always committed.** @param bool $ok True to commit, false to rollback the transaction.** @return bool true if successful*/function CommitTrans($ok=true) {return true;}/*** Rolls back a transaction.** If database does not support transactions, return false as rollbacks* always fail.** @return bool true if successful*/function RollbackTrans() {return false;}/*** return the databases that the driver can connect to.* Some databases will return an empty array.** @return array|bool an array of database names.*/function MetaDatabases() {global $ADODB_FETCH_MODE;if ($this->metaDatabasesSQL) {$save = $ADODB_FETCH_MODE;$ADODB_FETCH_MODE = ADODB_FETCH_NUM;if ($this->fetchMode !== false) {$savem = $this->SetFetchMode(false);}$arr = $this->GetCol($this->metaDatabasesSQL);if (isset($savem)) {$this->SetFetchMode($savem);}$ADODB_FETCH_MODE = $save;return $arr;}return false;}/*** List procedures or functions in an array.* @param procedureNamePattern a procedure name pattern; must match the procedure name as it is stored in the database* @param catalog a catalog name; must match the catalog name as it is stored in the database;* @param schemaPattern a schema name pattern;** @return array of procedures on current database.** Array(* [name_of_procedure] => Array(* [type] => PROCEDURE or FUNCTION* [catalog] => Catalog_name* [schema] => Schema_name* [remarks] => explanatory comment on the procedure* )* )*/function MetaProcedures($procedureNamePattern = null, $catalog = null, $schemaPattern = null) {return false;}/*** @param ttype can either be 'VIEW' or 'TABLE' or false.* If false, both views and tables are returned.* "VIEW" returns only views* "TABLE" returns only tables* @param showSchema returns the schema/user with the table name, eg. USER.TABLE* @param mask is the input mask - only supported by oci8 and postgresql** @return array of tables for current database.*/function MetaTables($ttype=false,$showSchema=false,$mask=false) {global $ADODB_FETCH_MODE;if ($mask) {return false;}if ($this->metaTablesSQL) {$save = $ADODB_FETCH_MODE;$ADODB_FETCH_MODE = ADODB_FETCH_NUM;if ($this->fetchMode !== false) {$savem = $this->SetFetchMode(false);}$rs = $this->Execute($this->metaTablesSQL);if (isset($savem)) {$this->SetFetchMode($savem);}$ADODB_FETCH_MODE = $save;if ($rs === false) {return false;}$arr = $rs->GetArray();$arr2 = array();if ($hast = ($ttype && isset($arr[0][1]))) {$showt = strncmp($ttype,'T',1);}for ($i=0; $i < sizeof($arr); $i++) {if ($hast) {if ($showt == 0) {if (strncmp($arr[$i][1],'T',1) == 0) {$arr2[] = trim($arr[$i][0]);}} else {if (strncmp($arr[$i][1],'V',1) == 0) {$arr2[] = trim($arr[$i][0]);}}} else$arr2[] = trim($arr[$i][0]);}$rs->Close();return $arr2;}return false;}function _findschema(&$table,&$schema) {if (!$schema && ($at = strpos($table,'.')) !== false) {$schema = substr($table,0,$at);$table = substr($table,$at+1);}}/*** List columns in a database as an array of ADOFieldObjects.* See top of file for definition of object.** @param $table table name to query* @param $normalize makes table name case-insensitive (required by some databases)* @schema is optional database schema to use - not supported by all databases.** @return array of ADOFieldObjects for current table.*/function MetaColumns($table,$normalize=true) {global $ADODB_FETCH_MODE;if (!empty($this->metaColumnsSQL)) {$schema = false;$this->_findschema($table,$schema);$save = $ADODB_FETCH_MODE;$ADODB_FETCH_MODE = ADODB_FETCH_NUM;if ($this->fetchMode !== false) {$savem = $this->SetFetchMode(false);}$rs = $this->Execute(sprintf($this->metaColumnsSQL,($normalize)?strtoupper($table):$table));if (isset($savem)) {$this->SetFetchMode($savem);}$ADODB_FETCH_MODE = $save;if ($rs === false || $rs->EOF) {return false;}$retarr = array();while (!$rs->EOF) { //print_r($rs->fields);$fld = new ADOFieldObject();$fld->name = $rs->fields[0];$fld->type = $rs->fields[1];if (isset($rs->fields[3]) && $rs->fields[3]) {if ($rs->fields[3]>0) {$fld->max_length = $rs->fields[3];}$fld->scale = $rs->fields[4];if ($fld->scale>0) {$fld->max_length += 1;}} else {$fld->max_length = $rs->fields[2];}if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) {$retarr[] = $fld;} else {$retarr[strtoupper($fld->name)] = $fld;}$rs->MoveNext();}$rs->Close();return $retarr;}return false;}/*** List indexes on a table as an array.* @param table table name to query* @param primary true to only show primary keys. Not actually used for most databases** @return array of indexes on current table. Each element represents an index, and is itself an associative array.** Array(* [name_of_index] => Array(* [unique] => true or false* [columns] => Array(* [0] => firstname* [1] => lastname* )* )* )*/function MetaIndexes($table, $primary = false, $owner = false) {return false;}/*** List columns names in a table as an array.* @param table table name to query** @return array of column names for current table.*/function MetaColumnNames($table, $numIndexes=false,$useattnum=false /* only for postgres */) {$objarr = $this->MetaColumns($table);if (!is_array($objarr)) {return false;}$arr = array();if ($numIndexes) {$i = 0;if ($useattnum) {foreach($objarr as $v)$arr[$v->attnum] = $v->name;} elseforeach($objarr as $v) $arr[$i++] = $v->name;} elseforeach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;return $arr;}/*** Concatenate strings.** Different SQL databases used different methods to combine strings together.* This function provides a wrapper.** Usage: $db->Concat($str1,$str2);** @param string $s Variable number of string parameters** @return string concatenated string*/function Concat() {$arr = func_get_args();return implode($this->concat_operator, $arr);}/*** Converts a date "d" to a string that the database can understand.** @param mixed $d a date in Unix date time format.** @return string date string in database date format*/function DBDate($d, $isfld=false) {if (empty($d) && $d !== 0) {return 'null';}if ($isfld) {return $d;}if (is_object($d)) {return $d->format($this->fmtDate);}if (is_string($d) && !is_numeric($d)) {if ($d === 'null') {return $d;}if (strncmp($d,"'",1) === 0) {$d = _adodb_safedateq($d);return $d;}if ($this->isoDates) {return "'$d'";}$d = ADOConnection::UnixDate($d);}return adodb_date($this->fmtDate,$d);}function BindDate($d) {$d = $this->DBDate($d);if (strncmp($d,"'",1)) {return $d;}return substr($d,1,strlen($d)-2);}function BindTimeStamp($d) {$d = $this->DBTimeStamp($d);if (strncmp($d,"'",1)) {return $d;}return substr($d,1,strlen($d)-2);}/*** Converts a timestamp "ts" to a string that the database can understand.** @param int|object $ts A timestamp in Unix date time format.** @return string $timestamp string in database timestamp format*/function DBTimeStamp($ts,$isfld=false) {if (empty($ts) && $ts !== 0) {return 'null';}if ($isfld) {return $ts;}if (is_object($ts)) {return $ts->format($this->fmtTimeStamp);}# strlen(14) allows YYYYMMDDHHMMSS formatif (!is_string($ts) || (is_numeric($ts) && strlen($ts)<14)) {return adodb_date($this->fmtTimeStamp,$ts);}if ($ts === 'null') {return $ts;}if ($this->isoDates && strlen($ts) !== 14) {$ts = _adodb_safedate($ts);return "'$ts'";}$ts = ADOConnection::UnixTimeStamp($ts);return adodb_date($this->fmtTimeStamp,$ts);}/*** Also in ADORecordSet.* @param mixed $v is a date string in YYYY-MM-DD format** @return int|false Date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format*/static function UnixDate($v) {if (is_object($v)) {// odbtp support//( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);}if (is_numeric($v) && strlen($v) !== 8) {return $v;}if (!preg_match( "|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})|", $v, $rr)) {return false;}if ($rr[1] <= TIMESTAMP_FIRST_YEAR) {return 0;}// h-m-s-MM-DD-YYreturn @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);}/*** Also in ADORecordSet.* @param string|object $v is a timestamp string in YYYY-MM-DD HH-NN-SS format** @return int|false Date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format*/static function UnixTimeStamp($v) {if (is_object($v)) {// odbtp support//( [year] => 2004 [month] => 9 [day] => 4 [hour] => 12 [minute] => 44 [second] => 8 [fraction] => 0 )return adodb_mktime($v->hour,$v->minute,$v->second,$v->month,$v->day, $v->year);}if (!preg_match("|^([0-9]{4})[-/\.]?([0-9]{1,2})[-/\.]?([0-9]{1,2})[ ,-]*(([0-9]{1,2}):?([0-9]{1,2}):?([0-9\.]{1,4}))?|",($v), $rr)) return false;if ($rr[1] <= TIMESTAMP_FIRST_YEAR && $rr[2]<= 1) {return 0;}// h-m-s-MM-DD-YYif (!isset($rr[5])) {return adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);}return @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1]);}/*** Format database date based on user defined format.** Also in ADORecordSet.** @param mixed $v Date in YYYY-MM-DD format, returned by database* @param string $fmt Format to apply, using date()* @param bool $gmt** @return string Formatted date*/function UserDate($v,$fmt='Y-m-d',$gmt=false) {$tt = $this->UnixDate($v);// $tt == -1 if pre TIMESTAMP_FIRST_YEARif (($tt === false || $tt == -1) && $v != false) {return $v;} else if ($tt == 0) {return $this->emptyDate;} else if ($tt == -1) {// pre-TIMESTAMP_FIRST_YEAR}return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);}/*** Format timestamp based on user defined format.** @param mixed $v Date in YYYY-MM-DD hh:mm:ss format* @param string $fmt Format to apply, using date()* @param bool $gmt** @return string Formatted timestamp*/function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false) {if (!isset($v)) {return $this->emptyTimeStamp;}# strlen(14) allows YYYYMMDDHHMMSS formatif (is_numeric($v) && strlen($v)<14) {return ($gmt) ? adodb_gmdate($fmt,$v) : adodb_date($fmt,$v);}$tt = $this->UnixTimeStamp($v);// $tt == -1 if pre TIMESTAMP_FIRST_YEARif (($tt === false || $tt == -1) && $v != false) {return $v;}if ($tt == 0) {return $this->emptyTimeStamp;}return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);}/*** Alias for addQ()* @param string $s* @param bool [$magic_quotes]* @return mixed** @deprecated 5.21.0* @noinspection PhpUnusedParameterInspection*/function escape($s,$magic_quotes=false) {return $this->addQ($s);}/*** Quotes a string, without prefixing nor appending quotes.** @param string $s The string to quote* @param bool $magic_quotes This param is not used since 5.21.0.* It remains for backwards compatibility.** @return string Quoted string** @noinspection PhpUnusedParameterInspection*/function addQ($s, $magic_quotes=false) {if ($this->replaceQuote[0] == '\\') {$s = str_replace(array('\\', "\0"),array('\\\\', "\\\0"),$s);}return str_replace("'", $this->replaceQuote, $s);}/*** Correctly quotes a string so that all strings are escaped.* We prefix and append to the string single-quotes.* An example is $db->qstr("Don't bother");* @link https://adodb.org/dokuwiki/doku.php?id=v5:reference:connection:qstr** @param string $s The string to quote* @param bool $magic_quotes This param is not used since 5.21.0.* It remains for backwards compatibility.** @return string Quoted string to be sent back to database** @noinspection PhpUnusedParameterInspection*/function qStr($s, $magic_quotes=false) {return "'" . $this->addQ($s) . "'";}/*** Execute query with pagination.** Will select the supplied $page number from a recordset, divided in* pages of $nrows rows each. It also saves two boolean values saying* if the given page is the first and/or last one of the recordset.** @param string $sql Query to execute* @param int $nrows Number of rows per page* @param int $page Page number to retrieve (1-based)* @param array|bool $inputarr Array of bind variables* @param int $secs2cache Time-to-live of the cache (in seconds), 0 to force query execution** @return ADORecordSet|bool the recordset ($rs->databaseType == 'array')** @author Iván Oliva*/function PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0) {global $ADODB_INCLUDED_LIB;if (empty($ADODB_INCLUDED_LIB)) {include_once(ADODB_DIR.'/adodb-lib.inc.php');}if ($this->pageExecuteCountRows) {$rs = _adodb_pageexecute_all_rows($this, $sql, $nrows, $page, $inputarr, $secs2cache);} else {$rs = _adodb_pageexecute_no_last_page($this, $sql, $nrows, $page, $inputarr, $secs2cache);}return $rs;}/*** Will select the supplied $page number from a recordset, given that it is paginated in pages of* $nrows rows per page. It also saves two boolean values saying if the given page is the first* and/or last one of the recordset. Added by Iván Oliva to provide recordset pagination.** @param int $secs2cache seconds to cache data, set to 0 to force query* @param string $sql* @param int $nrows is the number of rows per page to get* @param int $page is the page number to get (1-based)* @param mixed[]|bool $inputarr array of bind variables* @return mixed the recordset ($rs->databaseType == 'array')*/function CachePageExecute($secs2cache, $sql, $nrows, $page,$inputarr=false) {/*switch($this->dataProvider) {case 'postgres':case 'mysql':break;default: $secs2cache = 0; break;}*/return $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);}/*** Returns the maximum size of a MetaType C field. If the method* is not defined in the driver returns ADODB_STRINGMAX_NOTSET** @return int*/function charMax() {return ADODB_STRINGMAX_NOTSET;}/*** Returns the maximum size of a MetaType X field. If the method* is not defined in the driver returns ADODB_STRINGMAX_NOTSET** @return int*/function textMax() {return ADODB_STRINGMAX_NOTSET;}/*** Returns a substring of a varchar type field** Some databases have variations of the parameters, which is why* we have an ADOdb function for it** @param string $fld The field to sub-string* @param int $start The start point* @param int $length An optional length** @return string The SQL text*/function substr($fld,$start,$length=0) {$text = "{$this->substr}($fld,$start";if ($length > 0)$text .= ",$length";$text .= ')';return $text;}/** Formats the date into Month only format MM with leading zeroes** @param string $fld The name of the date to format** @return string The SQL text*/function month($fld) {return $this->sqlDate('m',$fld);}/** Formats the date into Day only format DD with leading zeroes** @param string $fld The name of the date to format* @return string The SQL text*/function day($fld) {return $this->sqlDate('d',$fld);}/** Formats the date into year only format YYYY** @param string $fld The name of the date to format** @return string The SQL text*/function year($fld) {return $this->sqlDate('Y',$fld);}/*** Get the last error recorded by PHP and clear the message.** By clearing the message, it becomes possible to detect whether a new error* has occurred, even when it is the same error as before being repeated.** @return mixed[]|null Array if an error has previously occurred. Null otherwise.*/protected function resetLastError() {$error = error_get_last();if (is_array($error)) {$error['message'] = '';}return $error;}/*** Compare a previously stored error message with the last error recorded by PHP* to determine whether a new error has occurred.** @param mixed[]|null $old Optional. Previously stored return value of error_get_last().** @return string The error message if a new error has occurred* or an empty string if no (new) errors have occurred..*/protected function getChangedErrorMsg($old = null) {$new = error_get_last();if (is_null($new)) {// No error has occurred yet at all.return '';}if (is_null($old)) {// First error recorded.return $new['message'];}$changed = false;foreach($new as $key => $value) {if ($new[$key] !== $old[$key]) {$changed = true;break;}}if ($changed === true) {return $new['message'];}return '';}} // end class ADOConnection//==============================================================================================// CLASS ADOFetchObj//==============================================================================================/*** Internal placeholder for record objects. Used by ADORecordSet->FetchObj().*/#[\AllowDynamicProperties]class ADOFetchObj {};/*** Class ADODB_Iterator_empty*/class ADODB_Iterator_empty implements Iterator {private $rs;function __construct($rs) {$this->rs = $rs;}#[\ReturnTypeWillChange]function rewind() {}#[\ReturnTypeWillChange]function valid() {return !$this->rs->EOF;}#[\ReturnTypeWillChange]function key() {return false;}#[\ReturnTypeWillChange]function current() {return false;}#[\ReturnTypeWillChange]function next() {}function __call($func, $params) {return call_user_func_array(array($this->rs, $func), $params);}#[\ReturnTypeWillChange]function hasMore() {return false;}}/*** Lightweight recordset when there are no records to be returned*/class ADORecordSet_empty implements IteratorAggregate{var $dataProvider = 'empty';var $databaseType = false;var $EOF = true;var $_numOfRows = 0;/** @var bool|array */var $fields = false;var $connection = false;function RowCount() {return 0;}function RecordCount() {return 0;}function PO_RecordCount() {return 0;}function Close() {return true;}function FetchRow() {return false;}function FieldCount() {return 0;}function Init() {}#[\ReturnTypeWillChange]function getIterator() {return new ADODB_Iterator_empty($this);}function GetAssoc() {return array();}function GetArray() {return array();}function GetAll() {return array();}function GetArrayLimit() {return array();}function GetRows() {return array();}function GetRowAssoc() {return array();}function MaxRecordCount() {return 0;}function NumRows() {return 0;}function NumCols() {return 0;}}//==============================================================================================// DATE AND TIME FUNCTIONS//==============================================================================================if (!defined('ADODB_DATE_VERSION')) {include_once(ADODB_DIR.'/adodb-time.inc.php');}/*** Class ADODB_Iterator*/class ADODB_Iterator implements Iterator {private $rs;function __construct($rs) {$this->rs = $rs;}#[\ReturnTypeWillChange]function rewind() {$this->rs->MoveFirst();}#[\ReturnTypeWillChange]function valid() {return !$this->rs->EOF;}#[\ReturnTypeWillChange]function key() {return $this->rs->_currentRow;}#[\ReturnTypeWillChange]function current() {return $this->rs->fields;}#[\ReturnTypeWillChange]function next() {$this->rs->MoveNext();}function __call($func, $params) {return call_user_func_array(array($this->rs, $func), $params);}function hasMore() {return !$this->rs->EOF;}}/*** RecordSet class that represents the dataset returned by the database.** To keep memory overhead low, this class holds only the current row in memory.* No prefetching of data is done, so the RecordCount() can return -1 (which* means recordcount not known).*/class ADORecordSet implements IteratorAggregate {/*** Used for cases when a recordset object is not created by executing a query.*/const DUMMY_QUERY_ID = -1;/*** public variables*/var $dataProvider = "native";/*** @var string Table name (used in _adodb_getupdatesql() and _adodb_getinsertsql())-*/public $tableName = '';/** @var bool|array */var $fields = false; /// holds the current row datavar $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob/// in other words, we use a text area for editing.var $canSeek = false; /// indicates that seek is supportedvar $sql; /// sql textvar $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.var $emptyTimeStamp = ' '; /// what to display when $time==0var $emptyDate = ' '; /// what to display when $time==0var $debug = false;var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsetsvar $bind = false; /// used by Fields() to hold array - should be private?var $fetchMode; /// default fetch mode/** @var ADOConnection The parent connection */var $connection = false;/*** private variables*/var $_numOfRows = -1; /** number of rows, or -1 */var $_numOfFields = -1; /** number of fields in recordset *//*** @var resource|int|false result link identifier*/var $_queryID = self::DUMMY_QUERY_ID;var $_currentRow = -1; /** This variable keeps the current row in the Recordset. */var $_closed = false; /** has recordset been closed */var $_inited = false; /** Init() should only be called once */var $_obj; /** Used by FetchObj */var $_names; /** Used by FetchObj */// Recordset pagination/** @var int Number of rows per page */var $rowsPerPage;/** @var int Current page number */var $_currentPage = -1;/** @var bool True if current page is the first page */var $_atFirstPage = false;/** @var bool True if current page is the last page */var $_atLastPage = false;/** @var int Last page number */var $_lastPageNo = -1;/** @var int Total number of rows in recordset */var $_maxRecordCount = 0;var $datetime = false;public $customActualTypes;public $customMetaTypes;/** @var int Only used in _adodb_getinsertsql() */public $insertSig;/*** @var ADOFieldObject[] Field metadata cache* @see fieldTypesArray()*/protected $fieldObjectsCache;/*** @var int Defines the Fetch Mode for a recordset* See the ADODB_FETCH_* constants*/public $adodbFetchMode;/*** Constructor** @param resource|int $queryID Query ID returned by ADOConnection->_query()* @param int|bool $mode The ADODB_FETCH_MODE value*/function __construct($queryID,$mode=false) {$this->_queryID = $queryID;}function __destruct() {$this->Close();}#[\ReturnTypeWillChange]function getIterator() {return new ADODB_Iterator($this);}/* this is experimental - i don't really know what to return... */function __toString() {include_once(ADODB_DIR.'/toexport.inc.php');return _adodb_export($this,',',',',false,true);}function Init() {if ($this->_inited) {return;}$this->_inited = true;if ($this->_queryID) {@$this->_initRS();} else {$this->_numOfRows = 0;$this->_numOfFields = 0;}if ($this->_numOfRows != 0 && $this->_numOfFields && $this->_currentRow == -1) {$this->_currentRow = 0;if ($this->EOF = ($this->_fetch() === false)) {$this->_numOfRows = 0; // _numOfRows could be -1}} else {$this->EOF = true;}}/*** Recordset initialization stub*/protected function _initRS() {}/*** Row fetch stub* @return bool*/protected function _fetch() {}/*** Generate a SELECT tag from a recordset, and return the HTML markup.** If the recordset has 2 columns, we treat the first one as the text to* display to the user, and the second as the return value. Extra columns* are discarded.** @param string $name Name of SELECT tag* @param string|array $defstr The value to highlight. Use an array for multiple highlight values.* @param bool|string $blank1stItem True to create an empty item (default), False not to add one;* 'string' to set its label and 'value:string' to assign a value to it.* @param bool $multiple True for multi-select list* @param int $size Number of rows to show (applies to multi-select box only)* @param string $selectAttr Additional attributes to defined for SELECT tag,* useful for holding javascript onChange='...' handlers, CSS class, etc.* @param bool $compareFirstCol When true (default), $defstr is compared against the value (column 2),* while false will compare against the description (column 1).** @return string HTML*/function getMenu($name, $defstr = '', $blank1stItem = true, $multiple = false,$size = 0, $selectAttr = '', $compareFirstCol = true){global $ADODB_INCLUDED_LIB;if (empty($ADODB_INCLUDED_LIB)) {include_once(ADODB_DIR.'/adodb-lib.inc.php');}return _adodb_getmenu($this, $name, $defstr, $blank1stItem, $multiple,$size, $selectAttr, $compareFirstCol);}/*** Generate a SELECT tag with groups from a recordset, and return the HTML markup.** The recordset must have 3 columns and be ordered by the 3rd column. The* first column contains the text to display to the user, the second is the* return value and the third is the option group. Extra columns are discarded.* Default strings are compared with the SECOND column.** @param string $name Name of SELECT tag* @param string|array $defstr The value to highlight. Use an array for multiple highlight values.* @param bool|string $blank1stItem True to create an empty item (default), False not to add one;* 'string' to set its label and 'value:string' to assign a value to it.* @param bool $multiple True for multi-select list* @param int $size Number of rows to show (applies to multi-select box only)* @param string $selectAttr Additional attributes to defined for SELECT tag,* useful for holding javascript onChange='...' handlers, CSS class, etc.* @param bool $compareFirstCol When true (default), $defstr is compared against the value (column 2),* while false will compare against the description (column 1).** @return string HTML*/function getMenuGrouped($name, $defstr = '', $blank1stItem = true, $multiple = false,$size = 0, $selectAttr = '', $compareFirstCol = true){global $ADODB_INCLUDED_LIB;if (empty($ADODB_INCLUDED_LIB)) {include_once(ADODB_DIR.'/adodb-lib.inc.php');}return _adodb_getmenu_gp($this, $name, $defstr, $blank1stItem, $multiple,$size, $selectAttr, $compareFirstCol);}/*** Generate a SELECT tag from a recordset, and return the HTML markup.** Same as GetMenu(), except that default strings are compared with the* FIRST column (the description).** @param string $name Name of SELECT tag* @param string|array $defstr The value to highlight. Use an array for multiple highlight values.* @param bool|string $blank1stItem True to create an empty item (default), False not to add one;* 'string' to set its label and 'value:string' to assign a value to it.* @param bool $multiple True for multi-select list* @param int $size Number of rows to show (applies to multi-select box only)* @param string $selectAttr Additional attributes to defined for SELECT tag,* useful for holding javascript onChange='...' handlers, CSS class, etc.** @return string HTML** @deprecated 5.21.0 Use getMenu() with $compareFirstCol = false instead.*/function getMenu2($name, $defstr = '', $blank1stItem = true, $multiple = false,$size = 0, $selectAttr = ''){return $this->getMenu($name, $defstr, $blank1stItem, $multiple,$size, $selectAttr,false);}/*** Generate a SELECT tag with groups from a recordset, and return the HTML markup.** Same as GetMenuGrouped(), except that default strings are compared with the* FIRST column (the description).** @param string $name Name of SELECT tag* @param string|array $defstr The value to highlight. Use an array for multiple highlight values.* @param bool|string $blank1stItem True to create an empty item (default), False not to add one;* 'string' to set its label and 'value:string' to assign a value to it.* @param bool $multiple True for multi-select list* @param int $size Number of rows to show (applies to multi-select box only)* @param string $selectAttr Additional attributes to defined for SELECT tag,* useful for holding javascript onChange='...' handlers, CSS class, etc.** @return string HTML** @deprecated 5.21.0 Use getMenuGrouped() with $compareFirstCol = false instead.*/function getMenu3($name, $defstr = '', $blank1stItem = true, $multiple = false,$size = 0, $selectAttr = ''){return $this->getMenuGrouped($name, $defstr, $blank1stItem, $multiple,$size, $selectAttr, false);}/*** return recordset as a 2-dimensional array.** @param int $nRows Number of rows to return. -1 means every row.** @return array indexed by the rows (0-based) from the recordset*/function GetArray($nRows = -1) {$results = array();$cnt = 0;while (!$this->EOF && $nRows != $cnt) {$results[] = $this->fields;$this->MoveNext();$cnt++;}return $results;}function GetAll($nRows = -1) {return $this->GetArray($nRows);}/*** Checks if there is another available recordset.** Some databases allow multiple recordsets to be returned.** @return boolean true if there is a next recordset, or false if no more*/function NextRecordSet() {return false;}/*** Return recordset as a 2-dimensional array.** Helper function for ADOConnection->SelectLimit()** @param int $nrows Number of rows to return* @param int $offset Starting row (1-based)** @return array an array indexed by the rows (0-based) from the recordset*/function getArrayLimit($nrows, $offset=-1) {if ($offset <= 0) {return $this->GetArray($nrows);}$this->Move($offset);$results = array();$cnt = 0;while (!$this->EOF && $nrows != $cnt) {$results[$cnt++] = $this->fields;$this->MoveNext();}return $results;}/*** Synonym for GetArray() for compatibility with ADO.** @param int $nRows Number of rows to return. -1 means every row.** @return array an array indexed by the rows (0-based) from the recordset*/function getRows($nRows = -1) {return $this->GetArray($nRows);}/*** return whole recordset as a 2-dimensional associative array if* there are more than 2 columns. The first column is treated as the* key and is not included in the array. If there is only 2 columns,* it will return a 1 dimensional array of key-value pairs unless* $force_array == true. This recordset method is currently part of* the API, but may not be in later versions of ADOdb. By preference, use* ADOconnnection::getAssoc()** @param bool $force_array (optional) Has only meaning if we have 2 data* columns. If false, a 1 dimensional* array is returned, otherwise a 2 dimensional* array is returned. If this sounds confusing,* read the source.** @param bool $first2cols (optional) Means if there are more than* 2 cols, ignore the remaining cols and* instead of returning* array[col0] => array(remaining cols),* return array[col0] => col1** @return mixed[]|false**/function getAssoc($force_array = false, $first2cols = false){/** Insufficient rows to show data*/if ($this->_numOfFields < 2)return;/** Empty recordset*/if (!$this->fields) {return array();}/** The number of fields is half the actual returned in BOTH mode*/$numberOfFields = $this->_numOfFields;/** Get the fetch mode when the call was executed, this may be* different than ADODB_FETCH_MODE*/$fetchMode = $this->connection->fetchMode;if ($fetchMode == ADODB_FETCH_BOTH) {/** If we are using BOTH, we present the data as if it* was in ASSOC mode. This could be enhanced by adding* a BOTH_ASSOC_MODE class property* We build a template of numeric keys. you could improve the* speed by caching this, indexed by number of keys*/$testKeys = array_fill(0,$numberOfFields,0);}$showArrayMethod = 0;if ($numberOfFields == 2)/** Key is always value of first element* Value is always value of second element*/$showArrayMethod = 1;if ($force_array)$showArrayMethod = 0;if ($first2cols)$showArrayMethod = 1;$results = array();while (!$this->EOF){$myFields = $this->fields;if ($fetchMode == ADODB_FETCH_BOTH) {/** extract the associative keys*/$myFields = array_diff_key($myFields,$testKeys);}/** key is value of first element, rest is data,* The key is not case processed*/$key = array_shift($myFields);switch ($showArrayMethod) {case 0:if ($fetchMode != ADODB_FETCH_NUM) {/** The driver should have already handled the key* casing, but in case it did not. We will check and force* this in later versions of ADOdb*/if (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_UPPER)$myFields = array_change_key_case($myFields,CASE_UPPER);elseif (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_LOWER)$myFields = array_change_key_case($myFields,CASE_LOWER);/** We have already shifted the key off* the front, so the rest is the value*/$results[$key] = $myFields;}else/** I want the values in a numeric array,* nicely re-indexed from zero*/$results[$key] = array_values($myFields);break;case 1:/** Don't care how long the array is,* I just want value of second column, and it doesn't* matter whether the array is associative or numeric*/$results[$key] = array_shift($myFields);break;}$this->MoveNext();}/** Done*/return $results;}/**** @param mixed $v is the character timestamp in YYYY-MM-DD hh:mm:ss format* @param string [$fmt] is the format to apply to it, using date()** @return string a timestamp formated as user desires*/function UserTimeStamp($v,$fmt='Y-m-d H:i:s') {if (is_numeric($v) && strlen($v)<14) {return adodb_date($fmt,$v);}$tt = $this->UnixTimeStamp($v);// $tt == -1 if pre TIMESTAMP_FIRST_YEARif (($tt === false || $tt == -1) && $v != false) {return $v;}if ($tt === 0) {return $this->emptyTimeStamp;}return adodb_date($fmt,$tt);}/*** @param mixed $v is the character date in YYYY-MM-DD format, returned by database* @param string $fmt is the format to apply to it, using date()** @return string a date formatted as user desires*/function UserDate($v,$fmt='Y-m-d') {$tt = $this->UnixDate($v);// $tt == -1 if pre TIMESTAMP_FIRST_YEARif (($tt === false || $tt == -1) && $v != false) {return $v;} else if ($tt == 0) {return $this->emptyDate;} else if ($tt == -1) {// pre-TIMESTAMP_FIRST_YEAR}return adodb_date($fmt,$tt);}/*** @param mixed $v is a date string in YYYY-MM-DD format** @return string date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format*/static function UnixDate($v) {return ADOConnection::UnixDate($v);}/*** @param string|object $v is a timestamp string in YYYY-MM-DD HH-NN-SS format** @return mixed date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format*/static function UnixTimeStamp($v) {return ADOConnection::UnixTimeStamp($v);}/*** PEAR DB Compat - do not use internally*/function Free() {return $this->Close();}/*** PEAR DB compat, number of rows** @return int*/function NumRows() {return $this->_numOfRows;}/*** PEAR DB compat, number of cols** @return int*/function NumCols() {return $this->_numOfFields;}/*** Fetch a row, returning false if no more rows.* This is PEAR DB compat mode.** @return mixed[]|false false or array containing the current record*/function FetchRow() {if ($this->EOF) {return false;}$arr = $this->fields;$this->_currentRow++;if (!$this->_fetch()) {$this->EOF = true;}return $arr;}/*** Fetch a row, returning PEAR_Error if no more rows.* This is PEAR DB compat mode.** @param mixed[]|false $arr** @return mixed DB_OK or error object*/function FetchInto(&$arr) {if ($this->EOF) {return (defined('PEAR_ERROR_RETURN')) ? new PEAR_Error('EOF',-1): false;}$arr = $this->fields;$this->MoveNext();return 1; // DB_OK}/*** Move to the first row in the recordset. Many databases do NOT support this.** @return bool true or false*/function MoveFirst() {if ($this->_currentRow == 0) {return true;}return $this->Move(0);}/*** Move to the last row in the recordset.** @return bool true or false*/function MoveLast() {if ($this->_numOfRows >= 0) {return $this->Move($this->_numOfRows-1);}if ($this->EOF) {return false;}while (!$this->EOF) {$f = $this->fields;$this->MoveNext();}$this->fields = $f;$this->EOF = false;return true;}/*** Move to next record in the recordset.** @return bool true if there still rows available, or false if there are no more rows (EOF).*/function MoveNext() {if (!$this->EOF) {$this->_currentRow++;if ($this->_fetch()) {return true;}}$this->EOF = true;/* -- tested error handling when scrolling cursor -- seems useless.$conn = $this->connection;if ($conn && $conn->raiseErrorFn && ($errno = $conn->ErrorNo())) {$fn = $conn->raiseErrorFn;$fn($conn->databaseType,'MOVENEXT',$errno,$conn->ErrorMsg().' ('.$this->sql.')',$conn->host,$conn->database);}*/return false;}/*** Random access to a specific row in the recordset. Some databases do not support* access to previous rows in the databases (no scrolling backwards).** @param int $rowNumber is the row to move to (0-based)** @return bool true if there still rows available, or false if there are no more rows (EOF).*/function Move($rowNumber = 0) {$this->EOF = false;if ($rowNumber == $this->_currentRow) {return true;}if ($rowNumber >= $this->_numOfRows) {if ($this->_numOfRows != -1) {$rowNumber = $this->_numOfRows-2;}}if ($rowNumber < 0) {$this->EOF = true;return false;}if ($this->canSeek) {if ($this->_seek($rowNumber)) {$this->_currentRow = $rowNumber;if ($this->_fetch()) {return true;}} else {$this->EOF = true;return false;}} else {if ($rowNumber < $this->_currentRow) {return false;}while (! $this->EOF && $this->_currentRow < $rowNumber) {$this->_currentRow++;if (!$this->_fetch()) {$this->EOF = true;}}return !($this->EOF);}$this->fields = false;$this->EOF = true;return false;}/*** Adjusts the result pointer to an arbitrary row in the result.** @param int $row The row to seek to.** @return bool False if the recordset contains no rows, otherwise true.*/function _seek($row) {}/*** Get the value of a field in the current row by column name.* Will not work if ADODB_FETCH_MODE is set to ADODB_FETCH_NUM.** @param string $colname is the field to access** @return mixed the value of $colname column*/function Fields($colname) {return $this->fields[$colname];}/*** Defines the function to use for table fields case conversion* depending on ADODB_ASSOC_CASE** @param int [$case]** @return string strtolower/strtoupper or false if no conversion needed*/protected function AssocCaseConvertFunction($case = ADODB_ASSOC_CASE) {switch($case) {case ADODB_ASSOC_CASE_UPPER:return 'strtoupper';case ADODB_ASSOC_CASE_LOWER:return 'strtolower';case ADODB_ASSOC_CASE_NATIVE:default:return false;}}/*** Builds the bind array associating keys to recordset fields** @param int [$upper] Case for the array keys, defaults to uppercase* (see ADODB_ASSOC_CASE_xxx constants)*/function GetAssocKeys($upper = ADODB_ASSOC_CASE) {if ($this->bind) {return;}$this->bind = array();// Define case conversion function for ASSOC fetch mode$fn_change_case = $this->AssocCaseConvertFunction($upper);// Build the bind arrayfor ($i=0; $i < $this->_numOfFields; $i++) {$o = $this->FetchField($i);// Set the array's keyif(is_numeric($o->name)) {// Just use the field ID$key = $i;}elseif( $fn_change_case ) {// Convert the key's case$key = $fn_change_case($o->name);}else {$key = $o->name;}$this->bind[$key] = $i;}}/*** Use associative array to get fields array for databases that do not support* associative arrays. Submitted by Paolo S. Asioli paolo.asioli#libero.it** @param int $upper Case for the array keys, defaults to uppercase* (see ADODB_ASSOC_CASE_xxx constants)* @return array*/function GetRowAssoc($upper = ADODB_ASSOC_CASE) {$record = array();$this->GetAssocKeys($upper);foreach($this->bind as $k => $v) {if( array_key_exists( $v, $this->fields ) ) {$record[$k] = $this->fields[$v];} elseif( array_key_exists( $k, $this->fields ) ) {$record[$k] = $this->fields[$k];} else {# This should not happen... trigger error ?$record[$k] = null;}}return $record;}/*** Clean up recordset** @return bool*/function Close() {// free connection object - this seems to globally free the object// and not merely the reference, so don't do this...// $this->connection = false;if (!$this->_closed) {$this->_closed = true;return $this->_close();} elsereturn true;}/*** Number of rows in recordset.** @return int Number of rows or -1 if this is not supported*/function recordCount() {return $this->_numOfRows;}/*** If we are using PageExecute(), this will return the maximum possible rows* that can be returned when paging a recordset.** @return int*/function MaxRecordCount() {return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->recordCount();}/*** Number of rows in recordset.* Alias for {@see recordCount()}** @return int Number of rows or -1 if this is not supported*/function rowCount() {return $this->recordCount();}/*** Portable RecordCount.** Be aware of possible problems in multiuser environments.* For better speed the table must be indexed by the condition.* Heavy test this before deploying.** @param string $table* @param string $condition** @return int Number of records from a previous SELECT. All databases support this.** @author Pablo Roca <pabloroca@mvps.org>*/function PO_RecordCount($table="", $condition="") {$lnumrows = $this->_numOfRows;// the database doesn't support native recordcount, so we do a workaroundif ($lnumrows == -1 && $this->connection) {IF ($table) {if ($condition) {$condition = " WHERE " . $condition;}$resultrows = $this->connection->Execute("SELECT COUNT(*) FROM $table $condition");if ($resultrows) {$lnumrows = reset($resultrows->fields);}}}return $lnumrows;}/*** @return the current row in the recordset. If at EOF, will return the last row. 0-based.*/function CurrentRow() {return $this->_currentRow;}/*** synonym for CurrentRow -- for ADO compat** @return the current row in the recordset. If at EOF, will return the last row. 0-based.*/function AbsolutePosition() {return $this->_currentRow;}/*** @return the number of columns in the recordset. Some databases will set this to 0* if no records are returned, others will return the number of columns in the query.*/function FieldCount() {return $this->_numOfFields;}/*** Get a Field's metadata from database.** Must be defined by child class.** @param int $fieldOffset** @return ADOFieldObject|false*/function fetchField($fieldOffset){return false;}/*** Get Field metadata for all the recordset's columns in an array.** @return ADOFieldObject[]*/function fieldTypesArray() {if (empty($this->fieldObjectsCache)) {for ($i = 0; $i < $this->_numOfFields; $i++) {$this->fieldObjectsCache[] = $this->fetchField($i);}}return $this->fieldObjectsCache;}/*** Return the fields array of the current row as an object for convenience.* The default case is lowercase field names.** @return the object with the properties set to the fields of the current row*/function FetchObj() {return $this->FetchObject(false);}/*** Return the fields array of the current row as an object for convenience.* The default case is uppercase.** @param bool $isUpper to set the object property names to uppercase** @return ADOFetchObj The object with properties set to the fields of the current row*/function FetchObject($isUpper=true) {if (empty($this->_obj)) {$this->_obj = new ADOFetchObj();$this->_names = array();for ($i=0; $i <$this->_numOfFields; $i++) {$f = $this->FetchField($i);$this->_names[] = $f->name;}}$o = clone($this->_obj);for ($i=0; $i <$this->_numOfFields; $i++) {$name = $this->_names[$i];if ($isUpper) {$n = strtoupper($name);} else {$n = $name;}$o->$n = $this->Fields($name);}return $o;}/*** Return the fields array of the current row as an object for convenience.* The default is lower-case field names.** @return ADOFetchObj|false The object with properties set to the fields of the current row* or false if EOF.** Fixed bug reported by tim@orotech.net*/function FetchNextObj() {return $this->FetchNextObject(false);}/*** Return the fields array of the current row as an object for convenience.* The default is upper case field names.** @param bool $isUpper to set the object property names to uppercase** @return ADOFetchObj|false The object with properties set to the fields of the current row* or false if EOF.** Fixed bug reported by tim@orotech.net*/function FetchNextObject($isUpper=true) {$o = false;if ($this->_numOfRows != 0 && !$this->EOF) {$o = $this->FetchObject($isUpper);$this->_currentRow++;if ($this->_fetch()) {return $o;}}$this->EOF = true;return $o;}/*** Get the ADOdb metatype.** Many databases use different names for the same type, so we transform* the native type to our standardised one, which uses 1 character codes.* @see https://adodb.org/dokuwiki/doku.php?id=v5:dictionary:dictionary_index#portable_data_types** @param string|ADOFieldObject $t Native type (usually ADOFieldObject->type)* It is also possible to provide an* ADOFieldObject here.* @param int $len The field's maximum length. This is because we treat* character fields bigger than a certain size as a 'B' (blob).* @param ADOFieldObject $fieldObj Field object returned by the database driver;* can hold additional info (eg. primary_key for mysql).** @return string The ADOdb Standard type*/function metaType($t, $len = -1, $fieldObj = false) {if ($t instanceof ADOFieldObject) {$fieldObj = $t;$t = $fieldObj->type;$len = $fieldObj->max_length;}// changed in 2.32 to hashing instead of switch stmt for speed...static $typeMap = array('VARCHAR' => 'C','VARCHAR2' => 'C','CHAR' => 'C','C' => 'C','STRING' => 'C','NCHAR' => 'C','NVARCHAR' => 'C','VARYING' => 'C','BPCHAR' => 'C','CHARACTER' => 'C','INTERVAL' => 'C', # Postgres'MACADDR' => 'C', # postgres'VAR_STRING' => 'C', # mysql##'LONGCHAR' => 'X','TEXT' => 'X','NTEXT' => 'X','M' => 'X','X' => 'X','CLOB' => 'X','NCLOB' => 'X','LVARCHAR' => 'X',##'BLOB' => 'B','IMAGE' => 'B','BINARY' => 'B','VARBINARY' => 'B','LONGBINARY' => 'B','B' => 'B',##'YEAR' => 'D', // mysql'DATE' => 'D','D' => 'D',##'UNIQUEIDENTIFIER' => 'C', # MS SQL Server##'SMALLDATETIME' => 'T','TIME' => 'T','TIMESTAMP' => 'T','DATETIME' => 'T','DATETIME2' => 'T','TIMESTAMPTZ' => 'T','T' => 'T','TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql##'BOOL' => 'L','BOOLEAN' => 'L','BIT' => 'L','L' => 'L',##'COUNTER' => 'R','R' => 'R','SERIAL' => 'R', // ifx'INT IDENTITY' => 'R',##'INT' => 'I','INT2' => 'I','INT4' => 'I','INT8' => 'I','INTEGER' => 'I','INTEGER UNSIGNED' => 'I','SHORT' => 'I','TINYINT' => 'I','SMALLINT' => 'I','I' => 'I',##'LONG' => 'N', // interbase is numeric, oci8 is blob'BIGINT' => 'N', // this is bigger than PHP 32-bit integers'DECIMAL' => 'N','DEC' => 'N','REAL' => 'N','DOUBLE' => 'N','DOUBLE PRECISION' => 'N','SMALLFLOAT' => 'N','FLOAT' => 'N','NUMBER' => 'N','NUM' => 'N','NUMERIC' => 'N','MONEY' => 'N',## informix 9.2'SQLINT' => 'I','SQLSERIAL' => 'I','SQLSMINT' => 'I','SQLSMFLOAT' => 'N','SQLFLOAT' => 'N','SQLMONEY' => 'N','SQLDECIMAL' => 'N','SQLDATE' => 'D','SQLVCHAR' => 'C','SQLCHAR' => 'C','SQLDTIME' => 'T','SQLINTERVAL' => 'N','SQLBYTES' => 'B','SQLTEXT' => 'X',## informix 10"SQLINT8" => 'I8',"SQLSERIAL8" => 'I8',"SQLNCHAR" => 'C',"SQLNVCHAR" => 'C',"SQLLVARCHAR" => 'X',"SQLBOOL" => 'L');$t = strtoupper($t);$tmap = (isset($typeMap[$t])) ? $typeMap[$t] : ADODB_DEFAULT_METATYPE;switch ($tmap) {case 'C':// is the char field is too long, return as text field...if ($this->blobSize >= 0) {if ($len > $this->blobSize) {return 'X';}} else if ($len > 250) {return 'X';}return 'C';case 'I':if (!empty($fieldObj->primary_key)) {return 'R';}return 'I';case false:return 'N';case 'B':if (isset($fieldObj->binary)) {return ($fieldObj->binary) ? 'B' : 'X';}return 'B';case 'D':if (!empty($this->connection) && !empty($this->connection->datetime)) {return 'T';}return 'D';default:if ($t == 'LONG' && $this->dataProvider == 'oci8') {return 'B';}return $tmap;}}/*** Convert case of field names associative array, if needed* @return void*/protected function _updatefields(){if( empty($this->fields)) {return;}// Determine case conversion function$fn_change_case = $this->AssocCaseConvertFunction();if(!$fn_change_case) {// No conversion neededreturn;}$arr = array();// Change the caseforeach($this->fields as $k => $v) {if (!is_integer($k)) {$k = $fn_change_case($k);}$arr[$k] = $v;}$this->fields = $arr;}function _close() {}/*** set/returns the current recordset page when paginating* @param int $page* @return int*/function absolutePage($page=-1) {if ($page != -1) {$this->_currentPage = $page;}return $this->_currentPage;}/*** set/returns the status of the atFirstPage flag when paginating* @param bool $status* @return bool*/function AtFirstPage($status=false) {if ($status != false) {$this->_atFirstPage = $status;}return $this->_atFirstPage;}/*** @param bool $page* @return bool*/function LastPageNo($page = false) {if ($page != false) {$this->_lastPageNo = $page;}return $this->_lastPageNo;}/*** set/returns the status of the atLastPage flag when paginating* @param bool $status* @return bool*/function AtLastPage($status=false) {if ($status != false) {$this->_atLastPage = $status;}return $this->_atLastPage;}} // end class ADORecordSet//==============================================================================================// CLASS ADORecordSet_array//==============================================================================================/*** This class encapsulates the concept of a recordset created in memory* as an array. This is useful for the creation of cached recordsets.** Note that the constructor is different from the standard ADORecordSet*/class ADORecordSet_array extends ADORecordSet{var $databaseType = 'array';var $_array; // holds the 2-dimensional data arrayvar $_types; // the array of types of each column (C B I L M)var $_colnames; // names of each column in arrayvar $_skiprow1; // skip 1st row because it holds column namesvar $_fieldobjects; // holds array of field objectsvar $canSeek = true;var $affectedrows = false;var $insertid = false;var $sql = '';var $compat = false;/*** Constructor** The parameters passed to this recordset are always fake because* this class does not use the queryID** @param resource|int $queryID Ignored* @param int|bool $mode The ADODB_FETCH_MODE value*/function __construct($queryID, $mode=false) {global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;// fetch() on EOF does not delete $this->fields$this->compat = !empty($ADODB_COMPAT_FETCH);parent::__construct($queryID); // fake queryID$this->fetchMode = $ADODB_FETCH_MODE;}/*** Setup the array.** @param array is a 2-dimensional array holding the data.* The first row should hold the column names* unless parameter $colnames is used.* @param typearr holds an array of types. These are the same types* used in MetaTypes (C,B,L,I,N).* @param string[]|false [$colnames] array of column names. If set, then the first row of* $array should not hold the column names.*/function InitArray($array,$typearr,$colnames=false) {$this->_array = $array;$this->_types = $typearr;if ($colnames) {$this->_skiprow1 = false;$this->_colnames = $colnames;} else {$this->_skiprow1 = true;$this->_colnames = $array[0];}$this->Init();}/*** Setup the Array and datatype file objects** @param array $array 2-dimensional array holding the data* The first row should hold the column names* unless parameter $colnames is used.* @param array $fieldarr Array of ADOFieldObject's.*/function InitArrayFields(&$array,&$fieldarr) {$this->_array = $array;$this->_skiprow1= false;if ($fieldarr) {$this->_fieldobjects = $fieldarr;}$this->Init();}/*** @param int [$nRows]* @return array*/function GetArray($nRows=-1) {if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {return $this->_array;} else {return ADORecordSet::GetArray($nRows);}}function _initrs() {$this->_numOfRows = sizeof($this->_array);if ($this->_skiprow1) {$this->_numOfRows -= 1;}$this->_numOfFields = (isset($this->_fieldobjects))? sizeof($this->_fieldobjects): sizeof($this->_types);}/*** Use associative array to get fields array** @param string $colname* @return mixed*/function Fields($colname) {$mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode;if ($mode & ADODB_FETCH_ASSOC) {if (!isset($this->fields[$colname]) && !is_null($this->fields[$colname])) {$colname = strtolower($colname);}return $this->fields[$colname];}if (!$this->bind) {$this->bind = array();for ($i=0; $i < $this->_numOfFields; $i++) {$o = $this->FetchField($i);$this->bind[strtoupper($o->name)] = $i;}}return $this->fields[$this->bind[strtoupper($colname)]];}/*** @param int [$fieldOffset]** @return \ADOFieldObject*/function FetchField($fieldOffset = -1) {if (isset($this->_fieldobjects)) {return $this->_fieldobjects[$fieldOffset];}$o = new ADOFieldObject();$o->name = $this->_colnames[$fieldOffset];$o->type = $this->_types[$fieldOffset];$o->max_length = -1; // length not knownreturn $o;}/*** @param int $row* @return bool*/function _seek($row) {if (sizeof($this->_array) && 0 <= $row && $row < $this->_numOfRows) {$this->_currentRow = $row;if ($this->_skiprow1) {$row += 1;}$this->fields = $this->_array[$row];return true;}return false;}/*** @return bool*/function MoveNext() {if (!$this->EOF) {$this->_currentRow++;$pos = $this->_currentRow;if ($this->_numOfRows <= $pos) {if (!$this->compat) {$this->fields = false;}} else {if ($this->_skiprow1) {$pos += 1;}$this->fields = $this->_array[$pos];return true;}$this->EOF = true;}return false;}/*** @return bool*/function _fetch() {$pos = $this->_currentRow;if ($this->_numOfRows <= $pos) {if (!$this->compat) {$this->fields = false;}return false;}if ($this->_skiprow1) {$pos += 1;}$this->fields = $this->_array[$pos];return true;}function _close() {return true;}} // ADORecordSet_array//==============================================================================================// HELPER FUNCTIONS//==============================================================================================/*** Synonym for ADOLoadCode. Private function. Do not use.** @deprecated*/function ADOLoadDB($dbType) {return ADOLoadCode($dbType);}/*** Load the code for a specific database driver. Private function. Do not use.*/function ADOLoadCode($dbType) {global $ADODB_LASTDB;if (!$dbType) {return false;}$db = strtolower($dbType);switch ($db) {case 'ado':$db = 'ado5';$class = 'ado';break;case 'ifx':case 'maxsql':$class = $db = 'mysqlt';break;case 'pgsql':case 'postgres':$class = $db = 'postgres9';break;case 'mysql':// mysql extension removed in PHP 7.0 - automatically switch to mysqli$class = $db = 'mysqli';break;default:if (substr($db, 0, 4) === 'pdo_') {ADOConnection::outp("Invalid database type: $db");return false;}$class = $db;break;}$file = "drivers/adodb-$db.inc.php";@include_once(ADODB_DIR . '/' . $file);$ADODB_LASTDB = $class;if (class_exists("ADODB_" . $class)) {return $class;}//ADOConnection::outp(adodb_pr(get_declared_classes(),true));if (!file_exists($file)) {ADOConnection::outp("Missing file: $file");} else {ADOConnection::outp("Syntax error in file: $file");}return false;}/*** Synonym for ADONewConnection for people like me who cannot remember the correct name** @param string [$db]** @return ADOConnection|false*/function NewADOConnection($db='') {return ADONewConnection($db);}/*** Instantiate a new Connection class for a specific database driver.** @param string $db Database Connection object to create. If undefined,* use the last database driver that was loaded by ADOLoadCode().** @return ADOConnection|false The freshly created instance of the Connection class* or false in case of error.*/function ADONewConnection($db='') {global $ADODB_NEWCONNECTION, $ADODB_LASTDB;if (!defined('ADODB_ASSOC_CASE')) {define('ADODB_ASSOC_CASE', ADODB_ASSOC_CASE_NATIVE);}/** Are there special characters in the dsn password* that disrupt parse_url*/$needsSpecialCharacterHandling = false;$errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;if (($at = strpos($db,'://')) !== FALSE) {$origdsn = $db;$fakedsn = 'fake'.substr($origdsn,$at);if (($at2 = strpos($origdsn,'@/')) !== FALSE) {// special handling of oracle, which might not have host$fakedsn = str_replace('@/','@adodb-fakehost/',$fakedsn);}if ((strpos($origdsn, 'sqlite')) !== FALSE && stripos($origdsn, '%2F') === FALSE) {// special handling for SQLite, it only might have the path to the database file.// If you try to connect to a SQLite database using a dsn// like 'sqlite:///path/to/database', the 'parse_url' php function// will throw you an exception with a message such as "unable to parse url"list($scheme, $path) = explode('://', $origdsn);$dsna['scheme'] = $scheme;if ($qmark = strpos($path,'?')) {$dsn['query'] = substr($path,$qmark+1);$path = substr($path,0,$qmark);}$dsna['path'] = '/' . urlencode($path);} else {/** Stop # character breaking parse_url*/$cFakedsn = str_replace('#','\035',$fakedsn);if (strcmp($fakedsn,$cFakedsn) != 0){/** There is a # in the string*/$needsSpecialCharacterHandling = true;/** This allows us to successfully parse the url*/$fakedsn = $cFakedsn;}$dsna = parse_url($fakedsn);}if (!$dsna) {return false;}$dsna['scheme'] = substr($origdsn,0,$at);if ($at2 !== FALSE) {$dsna['host'] = '';}if (strncmp($origdsn,'pdo',3) == 0) {$sch = explode('_',$dsna['scheme']);if (sizeof($sch)>1) {$dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';if ($sch[1] == 'sqlite') {$dsna['host'] = rawurlencode($sch[1].':'.rawurldecode($dsna['host']));} else {$dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host']));}$dsna['scheme'] = 'pdo';}}$db = @$dsna['scheme'];if (!$db) {return false;}$dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';$dsna['user'] = isset($dsna['user']) ? rawurldecode($dsna['user']) : '';$dsna['pass'] = isset($dsna['pass']) ? rawurldecode($dsna['pass']) : '';$dsna['path'] = isset($dsna['path']) ? rawurldecode(substr($dsna['path'],1)) : ''; # strip off initial /if ($needsSpecialCharacterHandling){/** Revert back to the original string*/$dsna = str_replace('\035','#',$dsna);}if (isset($dsna['query'])) {$opt1 = explode('&',$dsna['query']);foreach($opt1 as $k => $v) {$arr = explode('=',$v);$opt[$arr[0]] = isset($arr[1]) ? rawurldecode($arr[1]) : 1;}} else {$opt = array();}}/** phptype: Database backend used in PHP (mysql, odbc etc.)* dbsyntax: Database used with regards to SQL syntax etc.* protocol: Communication protocol to use (tcp, unix etc.)* hostspec: Host specification (hostname[:port])* database: Database to use on the DBMS server* username: User name for login* password: Password for login*/if (!empty($ADODB_NEWCONNECTION)) {$obj = $ADODB_NEWCONNECTION($db);}if(empty($obj)) {if (!isset($ADODB_LASTDB)) {$ADODB_LASTDB = '';}if (empty($db)) {$db = $ADODB_LASTDB;}if ($db != $ADODB_LASTDB) {$db = ADOLoadCode($db);}if (!$db) {if (isset($origdsn)) {$db = $origdsn;}if ($errorfn) {// raise an error$ignore = false;$errorfn('ADONewConnection', 'ADONewConnection', -998,"could not load the database driver for '$db'",$db,false,$ignore);} else {ADOConnection::outp( "<p>ADONewConnection: Unable to load database driver '$db'</p>",false);}return false;}$cls = 'ADODB_'.$db;if (!class_exists($cls)) {adodb_backtrace();return false;}$obj = new $cls();}# constructor should not failif ($obj) {if ($errorfn) {$obj->raiseErrorFn = $errorfn;}if (isset($dsna)) {if (isset($dsna['port'])) {$obj->port = $dsna['port'];}foreach($opt as $k => $v) {switch(strtolower($k)) {case 'new':$nconnect = true; $persist = true; break;case 'persist':case 'persistent': $persist = $v; break;case 'debug': $obj->debug = (integer) $v; break;#ibasecase 'role': $obj->role = $v; break;case 'dialect': $obj->dialect = (integer) $v; break;case 'charset': $obj->charset = $v; $obj->charSet=$v; break;case 'buffers': $obj->buffers = $v; break;case 'fetchmode': $obj->SetFetchMode($v); break;#adocase 'charpage': $obj->charPage = $v; break;#mysql, mysqlicase 'clientflags': $obj->clientFlags = $v; break;#mysql, mysqli, postgrescase 'port': $obj->port = $v; break;#mysqlicase 'socket': $obj->socket = $v; break;#oci8case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; break;case 'cachesecs': $obj->cacheSecs = $v; break;case 'memcache':$varr = explode(':',$v);$vlen = sizeof($varr);if ($vlen == 0) {break;}$obj->memCache = true;$obj->memCacheHost = explode(',',$varr[0]);if ($vlen == 1) {break;}$obj->memCachePort = $varr[1];if ($vlen == 2) {break;}$obj->memCacheCompress = $varr[2] ? true : false;break;}}if (empty($persist)) {$ok = $obj->Connect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);} else if (empty($nconnect)) {$ok = $obj->PConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);} else {$ok = $obj->NConnect($dsna['host'], $dsna['user'], $dsna['pass'], $dsna['path']);}if (!$ok) {return false;}}}return $obj;}// $perf == true means called by NewPerfMonitor(), otherwise for data dictionaryfunction _adodb_getdriver($provider,$drivername,$perf=false) {switch ($provider) {case 'odbtp':if (strncmp('odbtp_',$drivername,6)==0) {return substr($drivername,6);}case 'odbc' :if (strncmp('odbc_',$drivername,5)==0) {return substr($drivername,5);}case 'ado' :if (strncmp('ado_',$drivername,4)==0) {return substr($drivername,4);}case 'native':break;default:return $provider;}switch($drivername) {case 'mysqlt':case 'mysqli':$drivername='mysql';break;case 'postgres7':case 'postgres8':$drivername = 'postgres';break;case 'firebird15':$drivername = 'firebird';break;case 'oracle':$drivername = 'oci8';break;case 'access':if ($perf) {$drivername = '';}break;case 'db2' :case 'sapdb' :break;default:$drivername = 'generic';break;}return $drivername;}function NewPerfMonitor(&$conn) {$drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType,true);if (!$drivername || $drivername == 'generic') {return false;}include_once(ADODB_DIR.'/adodb-perf.inc.php');@include_once(ADODB_DIR."/perf/perf-$drivername.inc.php");$class = "Perf_$drivername";if (!class_exists($class)) {return false;}return new $class($conn);}/*** Get a new Data Dictionary object for the connection.** @param ADOConnection $conn* @param string $drivername** @return ADODB_DataDict|false*/function newDataDictionary(&$conn, $drivername='') {if (!$drivername) {$drivername = _adodb_getdriver($conn->dataProvider,$conn->databaseType);}include_once(ADODB_DIR.'/adodb-lib.inc.php');include_once(ADODB_DIR.'/adodb-datadict.inc.php');$path = ADODB_DIR."/datadict/datadict-$drivername.inc.php";if (!file_exists($path)) {ADOConnection::outp("Dictionary driver '$path' not available");return false;}include_once($path);$class = "ADODB2_$drivername";/** @var ADODB_DataDict $dict */$dict = new $class();$dict->dataProvider = $conn->dataProvider;$dict->connection = $conn;$dict->upperName = strtoupper($drivername);$dict->quote = $conn->nameQuote;if (!empty($conn->_connectionID)) {$dict->serverInfo = $conn->ServerInfo();}return $dict;}/*** Perform a print_r, with pre tags for better formatting.*/function adodb_pr($var,$as_string=false) {if ($as_string) {ob_start();}if (isset($_SERVER['HTTP_USER_AGENT'])) {echo " <pre>\n";print_r($var);echo "</pre>\n";} else {print_r($var);}if ($as_string) {$s = ob_get_contents();ob_end_clean();return $s;}}/*** Perform a stack-crawl and pretty print it.** @param bool $printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).* @param int $levels Number of levels to display* @param mixed $ishtml** @return string*/function adodb_backtrace($printOrArr=true,$levels=9999,$ishtml=null) {global $ADODB_INCLUDED_LIB;if (empty($ADODB_INCLUDED_LIB)) {include_once(ADODB_DIR.'/adodb-lib.inc.php');}return _adodb_backtrace($printOrArr,$levels,0,$ishtml);}}