summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/adodb/adodb-active-record.inc.php622
-rw-r--r--lib/adodb/adodb-csvlib.inc.php312
-rw-r--r--lib/adodb/adodb-datadict.inc.php889
-rw-r--r--lib/adodb/adodb-error.inc.php258
-rw-r--r--lib/adodb/adodb-errorhandler.inc.php79
-rw-r--r--lib/adodb/adodb-errorpear.inc.php88
-rw-r--r--lib/adodb/adodb-exceptions.inc.php82
-rw-r--r--lib/adodb/adodb-iterator.inc.php85
-rw-r--r--lib/adodb/adodb-lib.inc.php1137
-rw-r--r--lib/adodb/adodb-memcache.lib.inc.php118
-rw-r--r--lib/adodb/adodb-pager.inc.php290
-rw-r--r--lib/adodb/adodb-pear.inc.php374
-rw-r--r--lib/adodb/adodb-perf.inc.php1068
-rw-r--r--lib/adodb/adodb-php4.inc.php16
-rw-r--r--lib/adodb/adodb-time.inc.php1337
-rw-r--r--lib/adodb/adodb-xmlschema.inc.php2221
-rw-r--r--lib/adodb/adodb-xmlschema03.inc.php2403
-rw-r--r--lib/adodb/adodb.inc.php4231
-rw-r--r--lib/adodb/contrib/toxmlrpc.inc.php183
-rw-r--r--lib/adodb/datadict/datadict-access.inc.php95
-rw-r--r--lib/adodb/datadict/datadict-db2.inc.php143
-rw-r--r--lib/adodb/datadict/datadict-firebird.inc.php151
-rw-r--r--lib/adodb/datadict/datadict-generic.inc.php125
-rw-r--r--lib/adodb/datadict/datadict-ibase.inc.php67
-rw-r--r--lib/adodb/datadict/datadict-informix.inc.php80
-rw-r--r--lib/adodb/datadict/datadict-mssql.inc.php282
-rw-r--r--lib/adodb/datadict/datadict-mysql.inc.php181
-rw-r--r--lib/adodb/datadict/datadict-oci8.inc.php290
-rw-r--r--lib/adodb/datadict/datadict-postgres.inc.php371
-rw-r--r--lib/adodb/datadict/datadict-sapdb.inc.php121
-rw-r--r--lib/adodb/datadict/datadict-sybase.inc.php228
-rw-r--r--lib/adodb/drivers/adodb-access.inc.php87
-rw-r--r--lib/adodb/drivers/adodb-ado.inc.php634
-rw-r--r--lib/adodb/drivers/adodb-ado5.inc.php668
-rw-r--r--lib/adodb/drivers/adodb-ado_access.inc.php55
-rw-r--r--lib/adodb/drivers/adodb-ado_mssql.inc.php154
-rw-r--r--lib/adodb/drivers/adodb-borland_ibase.inc.php92
-rw-r--r--lib/adodb/drivers/adodb-csv.inc.php207
-rw-r--r--lib/adodb/drivers/adodb-db2.inc.php828
-rw-r--r--lib/adodb/drivers/adodb-fbsql.inc.php266
-rw-r--r--lib/adodb/drivers/adodb-firebird.inc.php77
-rw-r--r--lib/adodb/drivers/adodb-ibase.inc.php887
-rw-r--r--lib/adodb/drivers/adodb-informix.inc.php40
-rw-r--r--lib/adodb/drivers/adodb-informix72.inc.php475
-rw-r--r--lib/adodb/drivers/adodb-ldap.inc.php406
-rw-r--r--lib/adodb/drivers/adodb-mssql.inc.php1037
-rw-r--r--lib/adodb/drivers/adodb-mssql_n.inc.php166
-rw-r--r--lib/adodb/drivers/adodb-mssqlpo.inc.php62
-rw-r--r--lib/adodb/drivers/adodb-mysql.inc.php782
-rw-r--r--lib/adodb/drivers/adodb-mysqli.inc.php1020
-rw-r--r--lib/adodb/drivers/adodb-mysqlt.inc.php155
-rw-r--r--lib/adodb/drivers/adodb-netezza.inc.php170
-rw-r--r--lib/adodb/drivers/adodb-oci8.inc.php1512
-rw-r--r--lib/adodb/drivers/adodb-oci805.inc.php59
-rw-r--r--lib/adodb/drivers/adodb-oci8po.inc.php217
-rw-r--r--lib/adodb/drivers/adodb-odbc.inc.php738
-rw-r--r--lib/adodb/drivers/adodb-odbc_db2.inc.php368
-rw-r--r--lib/adodb/drivers/adodb-odbc_mssql.inc.php306
-rw-r--r--lib/adodb/drivers/adodb-odbc_oracle.inc.php115
-rw-r--r--lib/adodb/drivers/adodb-odbtp.inc.php743
-rw-r--r--lib/adodb/drivers/adodb-odbtp_unicode.inc.php39
-rw-r--r--lib/adodb/drivers/adodb-oracle.inc.php338
-rw-r--r--lib/adodb/drivers/adodb-pdo.inc.php569
-rw-r--r--lib/adodb/drivers/adodb-pdo_mssql.inc.php61
-rw-r--r--lib/adodb/drivers/adodb-pdo_mysql.inc.php168
-rw-r--r--lib/adodb/drivers/adodb-pdo_oci.inc.php93
-rw-r--r--lib/adodb/drivers/adodb-pdo_pgsql.inc.php230
-rw-r--r--lib/adodb/drivers/adodb-postgres.inc.php14
-rw-r--r--lib/adodb/drivers/adodb-postgres64.inc.php1064
-rw-r--r--lib/adodb/drivers/adodb-postgres7.inc.php264
-rw-r--r--lib/adodb/drivers/adodb-postgres8.inc.php12
-rw-r--r--lib/adodb/drivers/adodb-proxy.inc.php33
-rw-r--r--lib/adodb/drivers/adodb-sapdb.inc.php184
-rw-r--r--lib/adodb/drivers/adodb-sqlanywhere.inc.php169
-rw-r--r--lib/adodb/drivers/adodb-sqlite.inc.php398
-rw-r--r--lib/adodb/drivers/adodb-sqlitepo.inc.php62
-rw-r--r--lib/adodb/drivers/adodb-sybase.inc.php418
-rw-r--r--lib/adodb/drivers/adodb-sybase_ase.inc.php119
-rw-r--r--lib/adodb/drivers/adodb-vfp.inc.php107
-rw-r--r--lib/adodb/icons/adodb.gifbin0 -> 1091 bytes
-rw-r--r--lib/adodb/icons/adodb2.gifbin0 -> 1458 bytes
-rw-r--r--lib/adodb/lang/adodb-ar.inc.php34
-rw-r--r--lib/adodb/lang/adodb-bg.inc.php38
-rw-r--r--lib/adodb/lang/adodb-bgutf8.inc.php38
-rw-r--r--lib/adodb/lang/adodb-ca.inc.php35
-rw-r--r--lib/adodb/lang/adodb-cn.inc.php35
-rw-r--r--lib/adodb/lang/adodb-cz.inc.php40
-rw-r--r--lib/adodb/lang/adodb-da.inc.php33
-rw-r--r--lib/adodb/lang/adodb-de.inc.php33
-rw-r--r--lib/adodb/lang/adodb-en.inc.php34
-rw-r--r--lib/adodb/lang/adodb-es.inc.php33
-rw-r--r--lib/adodb/lang/adodb-esperanto.inc.php35
-rw-r--r--lib/adodb/lang/adodb-fr.inc.php33
-rw-r--r--lib/adodb/lang/adodb-hu.inc.php34
-rw-r--r--lib/adodb/lang/adodb-it.inc.php34
-rw-r--r--lib/adodb/lang/adodb-nl.inc.php33
-rw-r--r--lib/adodb/lang/adodb-pl.inc.php36
-rw-r--r--lib/adodb/lang/adodb-pt-br.inc.php35
-rw-r--r--lib/adodb/lang/adodb-ro.inc.php36
-rw-r--r--lib/adodb/lang/adodb-ru1251.inc.php35
-rw-r--r--lib/adodb/lang/adodb-sv.inc.php33
-rw-r--r--lib/adodb/lang/adodb-uk1251.inc.php35
-rw-r--r--lib/adodb/perf/perf-db2.inc.php102
-rw-r--r--lib/adodb/perf/perf-informix.inc.php70
-rw-r--r--lib/adodb/perf/perf-mssql.inc.php164
-rw-r--r--lib/adodb/perf/perf-mysql.inc.php315
-rw-r--r--lib/adodb/perf/perf-oci8.inc.php509
-rw-r--r--lib/adodb/perf/perf-postgres.inc.php124
-rw-r--r--lib/adodb/pivottable.inc.php187
-rw-r--r--lib/adodb/rsfilter.inc.php61
-rw-r--r--lib/adodb/server.php100
-rw-r--r--lib/adodb/session/adodb-compress-bzip2.php118
-rw-r--r--lib/adodb/session/adodb-compress-gzip.php93
-rw-r--r--lib/adodb/session/adodb-cryptsession.php27
-rw-r--r--lib/adodb/session/adodb-cryptsession2.php27
-rw-r--r--lib/adodb/session/adodb-encrypt-mcrypt.php109
-rw-r--r--lib/adodb/session/adodb-encrypt-md5.php39
-rw-r--r--lib/adodb/session/adodb-encrypt-secret.php48
-rw-r--r--lib/adodb/session/adodb-encrypt-sha1.php32
-rw-r--r--lib/adodb/session/adodb-session-clob.php24
-rw-r--r--lib/adodb/session/adodb-session-clob2.php24
-rw-r--r--lib/adodb/session/adodb-session.php934
-rw-r--r--lib/adodb/session/adodb-session2.php941
-rw-r--r--lib/adodb/session/crypt.inc.php161
-rw-r--r--lib/adodb/session/old/adodb-cryptsession.php324
-rw-r--r--lib/adodb/session/old/adodb-session-clob.php448
-rw-r--r--lib/adodb/session/old/adodb-session.php439
-rw-r--r--lib/adodb/session/old/crypt.inc.php64
-rw-r--r--lib/adodb/session/session_schema.xml26
-rw-r--r--lib/adodb/session/session_schema2.xml38
-rw-r--r--lib/adodb/toexport.inc.php133
-rw-r--r--lib/adodb/tohtml.inc.php195
-rw-r--r--lib/adodb/xmlschema.dtd39
-rw-r--r--lib/adodb/xmlschema03.dtd43
-rw-r--r--lib/adodb/xsl/convert-0.1-0.2.xsl205
-rw-r--r--lib/adodb/xsl/convert-0.1-0.3.xsl221
-rw-r--r--lib/adodb/xsl/convert-0.2-0.1.xsl207
-rw-r--r--lib/adodb/xsl/convert-0.2-0.3.xsl281
-rw-r--r--lib/adodb/xsl/remove-0.2.xsl54
-rw-r--r--lib/adodb/xsl/remove-0.3.xsl54
l---------lib/smarty1
-rw-r--r--lib/smarty-2.6.8/Config_File.class.php389
-rw-r--r--lib/smarty-2.6.8/Smarty.class.php1944
-rw-r--r--lib/smarty-2.6.8/Smarty_Compiler.class.php2327
-rw-r--r--lib/smarty-2.6.8/debug.tpl157
-rw-r--r--lib/smarty-2.6.8/internals/core.assemble_plugin_filepath.php67
-rw-r--r--lib/smarty-2.6.8/internals/core.assign_smarty_interface.php43
-rw-r--r--lib/smarty-2.6.8/internals/core.create_dir_structure.php79
-rw-r--r--lib/smarty-2.6.8/internals/core.display_debug_console.php61
-rw-r--r--lib/smarty-2.6.8/internals/core.get_include_path.php44
-rw-r--r--lib/smarty-2.6.8/internals/core.get_microtime.php23
-rw-r--r--lib/smarty-2.6.8/internals/core.get_php_resource.php80
-rw-r--r--lib/smarty-2.6.8/internals/core.is_secure.php59
-rw-r--r--lib/smarty-2.6.8/internals/core.is_trusted.php47
-rw-r--r--lib/smarty-2.6.8/internals/core.load_plugins.php125
-rw-r--r--lib/smarty-2.6.8/internals/core.load_resource_plugin.php74
-rw-r--r--lib/smarty-2.6.8/internals/core.process_cached_inserts.php71
-rw-r--r--lib/smarty-2.6.8/internals/core.process_compiled_include.php37
-rw-r--r--lib/smarty-2.6.8/internals/core.read_cache_file.php101
-rw-r--r--lib/smarty-2.6.8/internals/core.rm_auto.php71
-rw-r--r--lib/smarty-2.6.8/internals/core.rmdir.php54
-rw-r--r--lib/smarty-2.6.8/internals/core.run_insert_handler.php71
-rw-r--r--lib/smarty-2.6.8/internals/core.smarty_include_php.php50
-rw-r--r--lib/smarty-2.6.8/internals/core.write_cache_file.php96
-rw-r--r--lib/smarty-2.6.8/internals/core.write_compiled_include.php91
-rw-r--r--lib/smarty-2.6.8/internals/core.write_compiled_resource.php35
-rw-r--r--lib/smarty-2.6.8/internals/core.write_file.php54
-rw-r--r--lib/smarty-2.6.8/plugins/block.textformat.php103
-rw-r--r--lib/smarty-2.6.8/plugins/compiler.assign.php40
-rw-r--r--lib/smarty-2.6.8/plugins/function.assign_debug_info.php40
-rw-r--r--lib/smarty-2.6.8/plugins/function.config_load.php142
-rw-r--r--lib/smarty-2.6.8/plugins/function.counter.php80
-rw-r--r--lib/smarty-2.6.8/plugins/function.cycle.php102
-rw-r--r--lib/smarty-2.6.8/plugins/function.debug.php35
-rw-r--r--lib/smarty-2.6.8/plugins/function.eval.php49
-rw-r--r--lib/smarty-2.6.8/plugins/function.fetch.php221
-rw-r--r--lib/smarty-2.6.8/plugins/function.html_checkboxes.php143
-rw-r--r--lib/smarty-2.6.8/plugins/function.html_image.php142
-rw-r--r--lib/smarty-2.6.8/plugins/function.html_options.php122
-rw-r--r--lib/smarty-2.6.8/plugins/function.html_radios.php156
-rw-r--r--lib/smarty-2.6.8/plugins/function.html_select_date.php331
-rw-r--r--lib/smarty-2.6.8/plugins/function.html_select_time.php194
-rw-r--r--lib/smarty-2.6.8/plugins/function.html_table.php177
-rw-r--r--lib/smarty-2.6.8/plugins/function.mailto.php165
-rw-r--r--lib/smarty-2.6.8/plugins/function.math.php84
-rw-r--r--lib/smarty-2.6.8/plugins/function.popup.php119
-rw-r--r--lib/smarty-2.6.8/plugins/function.popup_init.php40
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.capitalize.php43
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.cat.php33
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.count_characters.php32
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.count_paragraphs.php29
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.count_sentences.php29
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.count_words.php33
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.date_format.php58
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.debug_print_var.php90
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.default.php32
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.escape.php93
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.indent.php28
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.lower.php26
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.nl2br.php35
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.regex_replace.php35
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.replace.php30
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.spacify.php30
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.string_format.php29
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.strip.php33
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.strip_tags.php32
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.truncate.php50
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.upper.php26
-rw-r--r--lib/smarty-2.6.8/plugins/modifier.wordwrap.php29
-rw-r--r--lib/smarty-2.6.8/plugins/outputfilter.trimwhitespace.php75
-rw-r--r--lib/smarty-2.6.8/plugins/shared.escape_special_chars.php31
-rw-r--r--lib/smarty-2.6.8/plugins/shared.make_timestamp.php46
212 files changed, 52050 insertions, 0 deletions
diff --git a/lib/adodb/adodb-active-record.inc.php b/lib/adodb/adodb-active-record.inc.php
new file mode 100644
index 0000000..35bf968
--- /dev/null
+++ b/lib/adodb/adodb-active-record.inc.php
@@ -0,0 +1,622 @@
+<?php
+/*
+
+@version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Latest version is available at http://adodb.sourceforge.net
+
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Active Record implementation. Superset of Zend Framework's.
+
+ Version 0.07
+
+ See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord
+ for info on Ruby on Rails Active Record implementation
+*/
+
+global $_ADODB_ACTIVE_DBS;
+global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
+
+// array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
+$_ADODB_ACTIVE_DBS = array();
+
+
+class ADODB_Active_DB {
+ var $db; // ADOConnection
+ var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
+}
+
+class ADODB_Active_Table {
+ var $name; // table name
+ var $flds; // assoc array of adofieldobjs, indexed by fieldname
+ var $keys; // assoc array of primary keys, indexed by fieldname
+ var $_created; // only used when stored as a cached file
+}
+
+// returns index into $_ADODB_ACTIVE_DBS
+function ADODB_SetDatabaseAdapter(&$db)
+{
+ global $_ADODB_ACTIVE_DBS;
+
+ foreach($_ADODB_ACTIVE_DBS as $k => $d) {
+ if (PHP_VERSION >= 5) {
+ if ($d->db === $db) return $k;
+ } else {
+ if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database)
+ return $k;
+ }
+ }
+
+ $obj = new ADODB_Active_DB();
+ $obj->db =& $db;
+ $obj->tables = array();
+
+ $_ADODB_ACTIVE_DBS[] = $obj;
+
+ return sizeof($_ADODB_ACTIVE_DBS)-1;
+}
+
+
+class ADODB_Active_Record {
+ var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
+ var $_table; // tablename, if set in class definition then use it as table name
+ var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
+ var $_where; // where clause set in Load()
+ var $_saved = false; // indicates whether data is already inserted.
+ var $_lasterr = false; // last error message
+ var $_original = false; // the original values loaded or inserted, refreshed on update
+
+ // should be static
+ function SetDatabaseAdapter(&$db)
+ {
+ return ADODB_SetDatabaseAdapter($db);
+ }
+
+ // php4 constructor
+ function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
+ {
+ ADODB_Active_Record::__construct($table,$pkeyarr,$db);
+ }
+
+ // php5 constructor
+ function __construct($table = false, $pkeyarr=false, $db=false)
+ {
+ global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
+
+ if ($db == false && is_object($pkeyarr)) {
+ $db = $pkeyarr;
+ $pkeyarr = false;
+ }
+
+ if (!$table) {
+ if (!empty($this->_table)) $table = $this->_table;
+ else $table = $this->_pluralize(get_class($this));
+ }
+ if ($db) {
+ $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
+ } else
+ $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
+
+
+ if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
+
+ $this->_table = $table;
+ $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
+ $this->UpdateActiveTable($pkeyarr);
+ }
+
+ function __wakeup()
+ {
+ $class = get_class($this);
+ new $class;
+ }
+
+ function _pluralize($table)
+ {
+ $ut = strtoupper($table);
+ $len = strlen($table);
+ $lastc = $ut[$len-1];
+ $lastc2 = substr($ut,$len-2);
+ switch ($lastc) {
+ case 'S':
+ return $table.'es';
+ case 'Y':
+ return substr($table,0,$len-1).'ies';
+ case 'X':
+ return $table.'es';
+ case 'H':
+ if ($lastc2 == 'CH' || $lastc2 == 'SH')
+ return $table.'es';
+ default:
+ return $table.'s';
+ }
+ }
+
+ //////////////////////////////////
+
+ // update metadata
+ function UpdateActiveTable($pkeys=false,$forceUpdate=false)
+ {
+ global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
+
+ $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];
+
+ $table = $this->_table;
+ $tables = $activedb->tables;
+ $tableat = $this->_tableat;
+ if (!$forceUpdate && !empty($tables[$tableat])) {
+ $tobj =& $tables[$tableat];
+ foreach($tobj->flds as $name => $fld)
+ $this->$name = null;
+ return;
+ }
+
+ $db =& $activedb->db;
+ $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
+ if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
+ $fp = fopen($fname,'r');
+ @flock($fp, LOCK_SH);
+ $acttab = unserialize(fread($fp,100000));
+ fclose($fp);
+ if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
+ // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
+ // ideally, you should cache at least 32 secs
+ $activedb->tables[$table] = $acttab;
+
+ //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
+ return;
+ } else if ($db->debug) {
+ ADOConnection::outp("Refreshing cached active record file: $fname");
+ }
+ }
+ $activetab = new ADODB_Active_Table();
+ $activetab->name = $table;
+
+
+ $cols = $db->MetaColumns($table);
+ if (!$cols) {
+ $this->Error("Invalid table name: $table",'UpdateActiveTable');
+ return false;
+ }
+ $fld = reset($cols);
+ if (!$pkeys) {
+ if (isset($fld->primary_key)) {
+ $pkeys = array();
+ foreach($cols as $name => $fld) {
+ if (!empty($fld->primary_key)) $pkeys[] = $name;
+ }
+ } else
+ $pkeys = $this->GetPrimaryKeys($db, $table);
+ }
+ if (empty($pkeys)) {
+ $this->Error("No primary key found for table $table",'UpdateActiveTable');
+ return false;
+ }
+
+ $attr = array();
+ $keys = array();
+
+ switch($ADODB_ASSOC_CASE) {
+ case 0:
+ foreach($cols as $name => $fldobj) {
+ $name = strtolower($name);
+ $this->$name = null;
+ $attr[$name] = $fldobj;
+ }
+ foreach($pkeys as $k => $name) {
+ $keys[strtolower($name)] = strtolower($name);
+ }
+ break;
+
+ case 1:
+ foreach($cols as $name => $fldobj) {
+ $name = strtoupper($name);
+ $this->$name = null;
+ $attr[$name] = $fldobj;
+ }
+
+ foreach($pkeys as $k => $name) {
+ $keys[strtoupper($name)] = strtoupper($name);
+ }
+ break;
+ default:
+ foreach($cols as $name => $fldobj) {
+ $name = ($fldobj->name);
+ $this->$name = null;
+ $attr[$name] = $fldobj;
+ }
+ foreach($pkeys as $k => $name) {
+ $keys[$name] = $cols[$name]->name;
+ }
+ break;
+ }
+
+ $activetab->keys = $keys;
+ $activetab->flds = $attr;
+
+ if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
+ $activetab->_created = time();
+ $s = serialize($activetab);
+ if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
+ adodb_write_file($fname,$s);
+ }
+ $activedb->tables[$table] = $activetab;
+ }
+
+ function GetPrimaryKeys(&$db, $table)
+ {
+ return $db->MetaPrimaryKeys($table);
+ }
+
+ // error handler for both PHP4+5.
+ function Error($err,$fn)
+ {
+ global $_ADODB_ACTIVE_DBS;
+
+ $fn = get_class($this).'::'.$fn;
+ $this->_lasterr = $fn.': '.$err;
+
+ if ($this->_dbat < 0) $db = false;
+ else {
+ $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+ $db =& $activedb->db;
+ }
+
+ if (function_exists('adodb_throw')) {
+ if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
+ else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
+ } else
+ if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
+
+ }
+
+ // return last error message
+ function ErrorMsg()
+ {
+ if (!function_exists('adodb_throw')) {
+ if ($this->_dbat < 0) $db = false;
+ else $db = $this->DB();
+
+ // last error could be database error too
+ if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
+ }
+ return $this->_lasterr;
+ }
+
+ function ErrorNo()
+ {
+ if ($this->_dbat < 0) return -9999; // no database connection...
+ $db = $this->DB();
+
+ return (int) $db->ErrorNo();
+ }
+
+
+ // retrieve ADOConnection from _ADODB_Active_DBs
+ function &DB()
+ {
+ global $_ADODB_ACTIVE_DBS;
+
+ if ($this->_dbat < 0) {
+ $false = false;
+ $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
+ return $false;
+ }
+ $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+ $db =& $activedb->db;
+ return $db;
+ }
+
+ // retrieve ADODB_Active_Table
+ function &TableInfo()
+ {
+ global $_ADODB_ACTIVE_DBS;
+
+ $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+ $table =& $activedb->tables[$this->_tableat];
+ return $table;
+ }
+
+ // set a numeric array (using natural table field ordering) as object properties
+ function Set(&$row)
+ {
+ $db =& $this->DB();
+
+ if (!$row) {
+ $this->_saved = false;
+ return false;
+ }
+
+ $this->_saved = true;
+
+ $table =& $this->TableInfo();
+ if (sizeof($table->flds) != sizeof($row)) {
+ $this->Error("Table structure of $this->_table has changed","Load");
+ return false;
+ }
+
+ $cnt = 0;
+ foreach($table->flds as $name=>$fld) {
+ $this->$name = $row[$cnt];
+ $cnt += 1;
+ }
+ $this->_original = $row;
+ return true;
+ }
+
+ // get last inserted id for INSERT
+ function LastInsertID(&$db,$fieldname)
+ {
+ if ($db->hasInsertID)
+ $val = $db->Insert_ID($this->_table,$fieldname);
+ else
+ $val = false;
+
+ if (is_null($val) || $val === false) {
+ // this might not work reliably in multi-user environment
+ return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
+ }
+ return $val;
+ }
+
+ // quote data in where clause
+ function doquote(&$db, $val,$t)
+ {
+ switch($t) {
+ case 'D':
+ case 'T':
+ if (empty($val)) return 'null';
+
+ case 'C':
+ case 'X':
+ if (is_null($val)) return 'null';
+
+ if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") {
+ return $db->qstr($val);
+ break;
+ }
+ default:
+ return $val;
+ break;
+ }
+ }
+
+ // generate where clause for an UPDATE/SELECT
+ function GenWhere(&$db, &$table)
+ {
+ $keys = $table->keys;
+ $parr = array();
+
+ foreach($keys as $k) {
+ $f = $table->flds[$k];
+ if ($f) {
+ $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
+ }
+ }
+ return implode(' and ', $parr);
+ }
+
+
+ //------------------------------------------------------------ Public functions below
+
+ function Load($where,$bindarr=false)
+ {
+ $db =& $this->DB(); if (!$db) return false;
+ $this->_where = $where;
+
+ $save = $db->SetFetchMode(ADODB_FETCH_NUM);
+ $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
+ $db->SetFetchMode($save);
+
+ return $this->Set($row);
+ }
+
+ // false on error
+ function Save()
+ {
+ if ($this->_saved) $ok = $this->Update();
+ else $ok = $this->Insert();
+
+ return $ok;
+ }
+
+ // false on error
+ function Insert()
+ {
+ $db =& $this->DB(); if (!$db) return false;
+ $cnt = 0;
+ $table =& $this->TableInfo();
+
+ $valarr = array();
+ $names = array();
+ $valstr = array();
+
+ foreach($table->flds as $name=>$fld) {
+ $val = $this->$name;
+ if(!is_null($val) || !array_key_exists($name, $table->keys)) {
+ $valarr[] = $val;
+ $names[] = $name;
+ $valstr[] = $db->Param($cnt);
+ $cnt += 1;
+ }
+ }
+
+ if (empty($names)){
+ foreach($table->flds as $name=>$fld) {
+ $valarr[] = null;
+ $names[] = $name;
+ $valstr[] = $db->Param($cnt);
+ $cnt += 1;
+ }
+ }
+ $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
+ $ok = $db->Execute($sql,$valarr);
+
+ if ($ok) {
+ $this->_saved = true;
+ $autoinc = false;
+ foreach($table->keys as $k) {
+ if (is_null($this->$k)) {
+ $autoinc = true;
+ break;
+ }
+ }
+ if ($autoinc && sizeof($table->keys) == 1) {
+ $k = reset($table->keys);
+ $this->$k = $this->LastInsertID($db,$k);
+ }
+ }
+
+ $this->_original = $valarr;
+ return !empty($ok);
+ }
+
+ function Delete()
+ {
+ $db =& $this->DB(); if (!$db) return false;
+ $table =& $this->TableInfo();
+
+ $where = $this->GenWhere($db,$table);
+ $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
+ $ok = $db->Execute($sql);
+
+ return $ok ? true : false;
+ }
+
+ // returns an array of active record objects
+ function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
+ {
+ $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
+ $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
+ return $arr;
+ }
+
+ // returns 0 on error, 1 on update, 2 on insert
+ function Replace()
+ {
+ global $ADODB_ASSOC_CASE;
+
+ $db =& $this->DB(); if (!$db) return false;
+ $table =& $this->TableInfo();
+
+ $pkey = $table->keys;
+
+ foreach($table->flds as $name=>$fld) {
+ $val = $this->$name;
+ /*
+ if (is_null($val)) {
+ if (isset($fld->not_null) && $fld->not_null) {
+ if (isset($fld->default_value) && strlen($fld->default_value)) continue;
+ else {
+ $this->Error("Cannot update null into $name","Replace");
+ return false;
+ }
+ }
+ }*/
+ if (is_null($val) && !empty($fld->auto_increment)) {
+ continue;
+ }
+ $t = $db->MetaType($fld->type);
+ $arr[$name] = $this->doquote($db,$val,$t);
+ $valarr[] = $val;
+ }
+
+ if (!is_array($pkey)) $pkey = array($pkey);
+
+
+ if ($ADODB_ASSOC_CASE == 0)
+ foreach($pkey as $k => $v)
+ $pkey[$k] = strtolower($v);
+ elseif ($ADODB_ASSOC_CASE == 0)
+ foreach($pkey as $k => $v)
+ $pkey[$k] = strtoupper($v);
+
+ $ok = $db->Replace($this->_table,$arr,$pkey);
+ if ($ok) {
+ $this->_saved = true; // 1= update 2=insert
+ if ($ok == 2) {
+ $autoinc = false;
+ foreach($table->keys as $k) {
+ if (is_null($this->$k)) {
+ $autoinc = true;
+ break;
+ }
+ }
+ if ($autoinc && sizeof($table->keys) == 1) {
+ $k = reset($table->keys);
+ $this->$k = $this->LastInsertID($db,$k);
+ }
+ }
+
+ $this->_original =& $valarr;
+ }
+ return $ok;
+ }
+
+ // returns 0 on error, 1 on update, -1 if no change in data (no update)
+ function Update()
+ {
+ $db =& $this->DB(); if (!$db) return false;
+ $table =& $this->TableInfo();
+
+ $where = $this->GenWhere($db, $table);
+
+ if (!$where) {
+ $this->error("Where missing for table $table", "Update");
+ return false;
+ }
+ $valarr = array();
+ $neworig = array();
+ $pairs = array();
+ $i = -1;
+ $cnt = 0;
+ foreach($table->flds as $name=>$fld) {
+ $i += 1;
+ $val = $this->$name;
+ $neworig[] = $val;
+
+ if (isset($table->keys[$name])) {
+ continue;
+ }
+
+ if (is_null($val)) {
+ if (isset($fld->not_null) && $fld->not_null) {
+ if (isset($fld->default_value) && strlen($fld->default_value)) continue;
+ else {
+ $this->Error("Cannot set field $name to NULL","Update");
+ return false;
+ }
+ }
+ }
+
+ if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
+ continue;
+ }
+ $valarr[] = $val;
+ $pairs[] = $name.'='.$db->Param($cnt);
+ $cnt += 1;
+ }
+
+
+ if (!$cnt) return -1;
+ $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
+ $ok = $db->Execute($sql,$valarr);
+ if ($ok) {
+ $this->_original =& $neworig;
+ return 1;
+ }
+ return 0;
+ }
+
+ function GetAttributeNames()
+ {
+ $table =& $this->TableInfo();
+ if (!$table) return false;
+ return array_keys($table->flds);
+ }
+
+};
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-csvlib.inc.php b/lib/adodb/adodb-csvlib.inc.php
new file mode 100644
index 0000000..1e34d39
--- /dev/null
+++ b/lib/adodb/adodb-csvlib.inc.php
@@ -0,0 +1,312 @@
+<?php
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+global $ADODB_INCLUDED_CSV;
+$ADODB_INCLUDED_CSV = 1;
+
+/*
+
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Library for CSV serialization. This is used by the csv/proxy driver and is the
+ CacheExecute() serialization format.
+
+ ==== NOTE ====
+ Format documented at http://php.weblogs.com/ADODB_CSV
+ ==============
+*/
+
+ /**
+ * convert a recordset into special format
+ *
+ * @param rs the recordset
+ *
+ * @return the CSV formated data
+ */
+ function _rs2serialize(&$rs,$conn=false,$sql='')
+ {
+ $max = ($rs) ? $rs->FieldCount() : 0;
+
+ if ($sql) $sql = urlencode($sql);
+ // metadata setup
+
+ if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete
+ if (is_object($conn)) {
+ $sql .= ','.$conn->Affected_Rows();
+ $sql .= ','.$conn->Insert_ID();
+ } else
+ $sql .= ',,';
+
+ $text = "====-1,0,$sql\n";
+ return $text;
+ }
+ $tt = ($rs->timeCreated) ? $rs->timeCreated : time();
+
+ ## changed format from ====0 to ====1
+ $line = "====1,$tt,$sql\n";
+
+ if ($rs->databaseType == 'array') {
+ $rows =& $rs->_array;
+ } else {
+ $rows = array();
+ while (!$rs->EOF) {
+ $rows[] = $rs->fields;
+ $rs->MoveNext();
+ }
+ }
+
+ for($i=0; $i < $max; $i++) {
+ $o =& $rs->FetchField($i);
+ $flds[] = $o;
+ }
+
+ $savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
+ $class = $rs->connection->arrayClass;
+ $rs2 = new $class();
+ $rs2->sql = $rs->sql;
+ $rs2->oldProvider = $rs->dataProvider;
+ $rs2->InitArrayFields($rows,$flds);
+ $rs2->fetchMode = $savefetch;
+ return $line.serialize($rs2);
+ }
+
+
+/**
+* Open CSV file and convert it into Data.
+*
+* @param url file/ftp/http url
+* @param err returns the error message
+* @param timeout dispose if recordset has been alive for $timeout secs
+*
+* @return recordset, or false if error occured. If no
+* error occurred in sql INSERT/UPDATE/DELETE,
+* empty recordset is returned
+*/
+ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
+ {
+ $false = false;
+ $err = false;
+ $fp = @fopen($url,'rb');
+ if (!$fp) {
+ $err = $url.' file/URL not found';
+ return $false;
+ }
+ @flock($fp, LOCK_SH);
+ $arr = array();
+ $ttl = 0;
+
+ if ($meta = fgetcsv($fp, 32000, ",")) {
+ // check if error message
+ if (strncmp($meta[0],'****',4) === 0) {
+ $err = trim(substr($meta[0],4,1024));
+ fclose($fp);
+ return $false;
+ }
+ // check for meta data
+ // $meta[0] is -1 means return an empty recordset
+ // $meta[1] contains a time
+
+ if (strncmp($meta[0], '====',4) === 0) {
+
+ if ($meta[0] == "====-1") {
+ if (sizeof($meta) < 5) {
+ $err = "Corrupt first line for format -1";
+ fclose($fp);
+ return $false;
+ }
+ fclose($fp);
+
+ if ($timeout > 0) {
+ $err = " Illegal Timeout $timeout ";
+ return $false;
+ }
+
+ $rs = new $rsclass($val=true);
+ $rs->fields = array();
+ $rs->timeCreated = $meta[1];
+ $rs->EOF = true;
+ $rs->_numOfFields = 0;
+ $rs->sql = urldecode($meta[2]);
+ $rs->affectedrows = (integer)$meta[3];
+ $rs->insertid = $meta[4];
+ return $rs;
+ }
+ # Under high volume loads, we want only 1 thread/process to _write_file
+ # so that we don't have 50 processes queueing to write the same data.
+ # We use probabilistic timeout, ahead of time.
+ #
+ # -4 sec before timeout, give processes 1/32 chance of timing out
+ # -2 sec before timeout, give processes 1/16 chance of timing out
+ # -1 sec after timeout give processes 1/4 chance of timing out
+ # +0 sec after timeout, give processes 100% chance of timing out
+ if (sizeof($meta) > 1) {
+ if($timeout >0){
+ $tdiff = (integer)( $meta[1]+$timeout - time());
+ if ($tdiff <= 2) {
+ switch($tdiff) {
+ case 4:
+ case 3:
+ if ((rand() & 31) == 0) {
+ fclose($fp);
+ $err = "Timeout 3";
+ return $false;
+ }
+ break;
+ case 2:
+ if ((rand() & 15) == 0) {
+ fclose($fp);
+ $err = "Timeout 2";
+ return $false;
+ }
+ break;
+ case 1:
+ if ((rand() & 3) == 0) {
+ fclose($fp);
+ $err = "Timeout 1";
+ return $false;
+ }
+ break;
+ default:
+ fclose($fp);
+ $err = "Timeout 0";
+ return $false;
+ } // switch
+
+ } // if check flush cache
+ }// (timeout>0)
+ $ttl = $meta[1];
+ }
+ //================================================
+ // new cache format - use serialize extensively...
+ if ($meta[0] === '====1') {
+ // slurp in the data
+ $MAXSIZE = 128000;
+
+ $text = fread($fp,$MAXSIZE);
+ if (strlen($text)) {
+ while ($txt = fread($fp,$MAXSIZE)) {
+ $text .= $txt;
+ }
+ }
+ fclose($fp);
+ $rs = unserialize($text);
+ if (is_object($rs)) $rs->timeCreated = $ttl;
+ else {
+ $err = "Unable to unserialize recordset";
+ //echo htmlspecialchars($text),' !--END--!<p>';
+ }
+ return $rs;
+ }
+
+ $meta = false;
+ $meta = fgetcsv($fp, 32000, ",");
+ if (!$meta) {
+ fclose($fp);
+ $err = "Unexpected EOF 1";
+ return $false;
+ }
+ }
+
+ // Get Column definitions
+ $flds = array();
+ foreach($meta as $o) {
+ $o2 = explode(':',$o);
+ if (sizeof($o2)!=3) {
+ $arr[] = $meta;
+ $flds = false;
+ break;
+ }
+ $fld = new ADOFieldObject();
+ $fld->name = urldecode($o2[0]);
+ $fld->type = $o2[1];
+ $fld->max_length = $o2[2];
+ $flds[] = $fld;
+ }
+ } else {
+ fclose($fp);
+ $err = "Recordset had unexpected EOF 2";
+ return $false;
+ }
+
+ // slurp in the data
+ $MAXSIZE = 128000;
+
+ $text = '';
+ while ($txt = fread($fp,$MAXSIZE)) {
+ $text .= $txt;
+ }
+
+ fclose($fp);
+ @$arr = unserialize($text);
+ //var_dump($arr);
+ if (!is_array($arr)) {
+ $err = "Recordset had unexpected EOF (in serialized recordset)";
+ if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
+ return $false;
+ }
+ $rs = new $rsclass();
+ $rs->timeCreated = $ttl;
+ $rs->InitArrayFields($arr,$flds);
+ return $rs;
+ }
+
+
+ /**
+ * Save a file $filename and its $contents (normally for caching) with file locking
+ */
+ function adodb_write_file($filename, $contents,$debug=false)
+ {
+ # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
+ # So to simulate locking, we assume that rename is an atomic operation.
+ # First we delete $filename, then we create a $tempfile write to it and
+ # rename to the desired $filename. If the rename works, then we successfully
+ # modified the file exclusively.
+ # What a stupid need - having to simulate locking.
+ # Risks:
+ # 1. $tempfile name is not unique -- very very low
+ # 2. unlink($filename) fails -- ok, rename will fail
+ # 3. adodb reads stale file because unlink fails -- ok, $rs timeout occurs
+ # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated
+ if (strncmp(PHP_OS,'WIN',3) === 0) {
+ // skip the decimal place
+ $mtime = substr(str_replace(' ','_',microtime()),2);
+ // getmypid() actually returns 0 on Win98 - never mind!
+ $tmpname = $filename.uniqid($mtime).getmypid();
+ if (!($fd = @fopen($tmpname,'a'))) return false;
+ $ok = ftruncate($fd,0);
+ if (!fwrite($fd,$contents)) $ok = false;
+ fclose($fd);
+ chmod($tmpname,0644);
+ // the tricky moment
+ @unlink($filename);
+ if (!@rename($tmpname,$filename)) {
+ unlink($tmpname);
+ $ok = false;
+ }
+ if (!$ok) {
+ if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
+ }
+ return $ok;
+ }
+ if (!($fd = @fopen($filename, 'a'))) return false;
+ if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
+ $ok = fwrite( $fd, $contents );
+ fclose($fd);
+ chmod($filename,0644);
+ }else {
+ fclose($fd);
+ if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
+ $ok = false;
+ }
+
+ return $ok;
+ }
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-datadict.inc.php b/lib/adodb/adodb-datadict.inc.php
new file mode 100644
index 0000000..c31edd8
--- /dev/null
+++ b/lib/adodb/adodb-datadict.inc.php
@@ -0,0 +1,889 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+ DOCUMENTATION:
+
+ See adodb/tests/test-datadict.php for docs and examples.
+*/
+
+/*
+ Test script for parser
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+function Lens_ParseTest()
+{
+$str = "`zcol ACOL` NUMBER(32,2) DEFAULT 'The \"cow\" (and Jim''s dog) jumps over the moon' PRIMARY, INTI INT AUTO DEFAULT 0, zcol2\"afs ds";
+print "<p>$str</p>";
+$a= Lens_ParseArgs($str);
+print "<pre>";
+print_r($a);
+print "</pre>";
+}
+
+
+if (!function_exists('ctype_alnum')) {
+ function ctype_alnum($text) {
+ return preg_match('/^[a-z0-9]*$/i', $text);
+ }
+}
+
+//Lens_ParseTest();
+
+/**
+ Parse arguments, treat "text" (text) and 'text' as quotation marks.
+ To escape, use "" or '' or ))
+
+ Will read in "abc def" sans quotes, as: abc def
+ Same with 'abc def'.
+ However if `abc def`, then will read in as `abc def`
+
+ @param endstmtchar Character that indicates end of statement
+ @param tokenchars Include the following characters in tokens apart from A-Z and 0-9
+ @returns 2 dimensional array containing parsed tokens.
+*/
+function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
+{
+ $pos = 0;
+ $intoken = false;
+ $stmtno = 0;
+ $endquote = false;
+ $tokens = array();
+ $tokens[$stmtno] = array();
+ $max = strlen($args);
+ $quoted = false;
+ $tokarr = array();
+
+ while ($pos < $max) {
+ $ch = substr($args,$pos,1);
+ switch($ch) {
+ case ' ':
+ case "\t":
+ case "\n":
+ case "\r":
+ if (!$quoted) {
+ if ($intoken) {
+ $intoken = false;
+ $tokens[$stmtno][] = implode('',$tokarr);
+ }
+ break;
+ }
+
+ $tokarr[] = $ch;
+ break;
+
+ case '`':
+ if ($intoken) $tokarr[] = $ch;
+ case '(':
+ case ')':
+ case '"':
+ case "'":
+
+ if ($intoken) {
+ if (empty($endquote)) {
+ $tokens[$stmtno][] = implode('',$tokarr);
+ if ($ch == '(') $endquote = ')';
+ else $endquote = $ch;
+ $quoted = true;
+ $intoken = true;
+ $tokarr = array();
+ } else if ($endquote == $ch) {
+ $ch2 = substr($args,$pos+1,1);
+ if ($ch2 == $endquote) {
+ $pos += 1;
+ $tokarr[] = $ch2;
+ } else {
+ $quoted = false;
+ $intoken = false;
+ $tokens[$stmtno][] = implode('',$tokarr);
+ $endquote = '';
+ }
+ } else
+ $tokarr[] = $ch;
+
+ }else {
+
+ if ($ch == '(') $endquote = ')';
+ else $endquote = $ch;
+ $quoted = true;
+ $intoken = true;
+ $tokarr = array();
+ if ($ch == '`') $tokarr[] = '`';
+ }
+ break;
+
+ default:
+
+ if (!$intoken) {
+ if ($ch == $endstmtchar) {
+ $stmtno += 1;
+ $tokens[$stmtno] = array();
+ break;
+ }
+
+ $intoken = true;
+ $quoted = false;
+ $endquote = false;
+ $tokarr = array();
+
+ }
+
+ if ($quoted) $tokarr[] = $ch;
+ else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch;
+ else {
+ if ($ch == $endstmtchar) {
+ $tokens[$stmtno][] = implode('',$tokarr);
+ $stmtno += 1;
+ $tokens[$stmtno] = array();
+ $intoken = false;
+ $tokarr = array();
+ break;
+ }
+ $tokens[$stmtno][] = implode('',$tokarr);
+ $tokens[$stmtno][] = $ch;
+ $intoken = false;
+ }
+ }
+ $pos += 1;
+ }
+ if ($intoken) $tokens[$stmtno][] = implode('',$tokarr);
+
+ return $tokens;
+}
+
+
+class ADODB_DataDict {
+ var $connection;
+ var $debug = false;
+ var $dropTable = 'DROP TABLE %s';
+ var $renameTable = 'RENAME TABLE %s TO %s';
+ var $dropIndex = 'DROP INDEX %s';
+ var $addCol = ' ADD';
+ var $alterCol = ' ALTER COLUMN';
+ var $dropCol = ' DROP COLUMN';
+ var $renameColumn = 'ALTER TABLE %s RENAME COLUMN %s TO %s'; // table, old-column, new-column, column-definitions (not used by default)
+ var $nameRegex = '\w';
+ var $nameRegexBrackets = 'a-zA-Z0-9_\(\)';
+ var $schema = false;
+ var $serverInfo = array();
+ var $autoIncrement = false;
+ var $dataProvider;
+ var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); // for changetablesql
+ var $blobSize = 100; /// any varchar/char field this size or greater is treated as a blob
+ /// in other words, we use a text area for editting.
+
+ function GetCommentSQL($table,$col)
+ {
+ return false;
+ }
+
+ function SetCommentSQL($table,$col,$cmt)
+ {
+ return false;
+ }
+
+ function MetaTables()
+ {
+ if (!$this->connection->IsConnected()) return array();
+ return $this->connection->MetaTables();
+ }
+
+ function MetaColumns($tab, $upper=true, $schema=false)
+ {
+ if (!$this->connection->IsConnected()) return array();
+ return $this->connection->MetaColumns($this->TableName($tab), $upper, $schema);
+ }
+
+ function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
+ {
+ if (!$this->connection->IsConnected()) return array();
+ return $this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey);
+ }
+
+ function MetaIndexes($table, $primary = false, $owner = false)
+ {
+ if (!$this->connection->IsConnected()) return array();
+ return $this->connection->MetaIndexes($this->TableName($table), $primary, $owner);
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ return ADORecordSet::MetaType($t,$len,$fieldobj);
+ }
+
+ function NameQuote($name = NULL,$allowBrackets=false)
+ {
+ if (!is_string($name)) {
+ return FALSE;
+ }
+
+ $name = trim($name);
+
+ if ( !is_object($this->connection) ) {
+ return $name;
+ }
+
+ $quote = $this->connection->nameQuote;
+
+ // if name is of the form `name`, quote it
+ if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
+ return $quote . $matches[1] . $quote;
+ }
+
+ // if name contains special characters, quote it
+ $regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;
+
+ if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
+ return $quote . $name . $quote;
+ }
+
+ return $name;
+ }
+
+ function TableName($name)
+ {
+ if ( $this->schema ) {
+ return $this->NameQuote($this->schema) .'.'. $this->NameQuote($name);
+ }
+ return $this->NameQuote($name);
+ }
+
+ // Executes the sql array returned by GetTableSQL and GetIndexSQL
+ function ExecuteSQLArray($sql, $continueOnError = true)
+ {
+ $rez = 2;
+ $conn = &$this->connection;
+ $saved = $conn->debug;
+ foreach($sql as $line) {
+
+ if ($this->debug) $conn->debug = true;
+ $ok = $conn->Execute($line);
+ $conn->debug = $saved;
+ if (!$ok) {
+ if ($this->debug) ADOConnection::outp($conn->ErrorMsg());
+ if (!$continueOnError) return 0;
+ $rez = 1;
+ }
+ }
+ return $rez;
+ }
+
+ /**
+ Returns the actual type given a character code.
+
+ C: varchar
+ X: CLOB (character large object) or largest varchar size if CLOB is not supported
+ C2: Multibyte varchar
+ X2: Multibyte CLOB
+
+ B: BLOB (binary large object)
+
+ D: Date
+ T: Date-time
+ L: Integer field suitable for storing booleans (0 or 1)
+ I: Integer
+ F: Floating point number
+ N: Numeric or decimal number
+ */
+
+ function ActualType($meta)
+ {
+ return $meta;
+ }
+
+ function CreateDatabase($dbname,$options=false)
+ {
+ $options = $this->_Options($options);
+ $sql = array();
+
+ $s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
+ if (isset($options[$this->upperName]))
+ $s .= ' '.$options[$this->upperName];
+
+ $sql[] = $s;
+ return $sql;
+ }
+
+ /*
+ Generates the SQL to create index. Returns an array of sql strings.
+ */
+ function CreateIndexSQL($idxname, $tabname, $flds, $idxoptions = false)
+ {
+ if (!is_array($flds)) {
+ $flds = explode(',',$flds);
+ }
+
+ foreach($flds as $key => $fld) {
+ # some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32)
+ $flds[$key] = $this->NameQuote($fld,$allowBrackets=true);
+ }
+
+ return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions));
+ }
+
+ function DropIndexSQL ($idxname, $tabname = NULL)
+ {
+ return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname)));
+ }
+
+ function SetSchema($schema)
+ {
+ $this->schema = $schema;
+ }
+
+ function AddColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey,$idxs) = $this->_GenFields($flds);
+ // genfields can return FALSE at times
+ if ($lines == null) $lines = array();
+ $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
+ foreach($lines as $v) {
+ $sql[] = $alter . $v;
+ }
+ if (is_array($idxs)) {
+ foreach($idxs as $idx => $idxdef) {
+ $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
+ $sql = array_merge($sql, $sql_idxs);
+ }
+ }
+ return $sql;
+ }
+
+ /**
+ * Change the definition of one column
+ *
+ * As some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
+ * to allow, recreating the table and copying the content over to the new table
+ * @param string $tabname table-name
+ * @param string $flds column-name and type for the changed column
+ * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
+ * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
+ * @return array with SQL strings
+ */
+ function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey,$idxs) = $this->_GenFields($flds);
+ // genfields can return FALSE at times
+ if ($lines == null) $lines = array();
+ $alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
+ foreach($lines as $v) {
+ $sql[] = $alter . $v;
+ }
+ if (is_array($idxs)) {
+ foreach($idxs as $idx => $idxdef) {
+ $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
+ $sql = array_merge($sql, $sql_idxs);
+ }
+
+ }
+ return $sql;
+ }
+
+ /**
+ * Rename one column
+ *
+ * Some DBM's can only do this together with changeing the type of the column (even if that stays the same, eg. mysql)
+ * @param string $tabname table-name
+ * @param string $oldcolumn column-name to be renamed
+ * @param string $newcolumn new column-name
+ * @param string $flds='' complete column-defintion-string like for AddColumnSQL, only used by mysql atm., default=''
+ * @return array with SQL strings
+ */
+ function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
+ {
+ $tabname = $this->TableName ($tabname);
+ if ($flds) {
+ list($lines,$pkey,$idxs) = $this->_GenFields($flds);
+ // genfields can return FALSE at times
+ if ($lines == null) $lines = array();
+ list(,$first) = each($lines);
+ list(,$column_def) = split("[\t ]+",$first,2);
+ }
+ return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
+ }
+
+ /**
+ * Drop one column
+ *
+ * Some DBM's can't do that on there own, you need to supply the complete defintion of the new table,
+ * to allow, recreating the table and copying the content over to the new table
+ * @param string $tabname table-name
+ * @param string $flds column-name and type for the changed column
+ * @param string $tableflds='' complete defintion of the new table, eg. for postgres, default ''
+ * @param array/string $tableoptions='' options for the new table see CreateTableSQL, default ''
+ * @return array with SQL strings
+ */
+ function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
+ {
+ $tabname = $this->TableName ($tabname);
+ if (!is_array($flds)) $flds = explode(',',$flds);
+ $sql = array();
+ $alter = 'ALTER TABLE ' . $tabname . $this->dropCol . ' ';
+ foreach($flds as $v) {
+ $sql[] = $alter . $this->NameQuote($v);
+ }
+ return $sql;
+ }
+
+ function DropTableSQL($tabname)
+ {
+ return array (sprintf($this->dropTable, $this->TableName($tabname)));
+ }
+
+ function RenameTableSQL($tabname,$newname)
+ {
+ return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname)));
+ }
+
+ /**
+ Generate the SQL to create table. Returns an array of sql strings.
+ */
+ function CreateTableSQL($tabname, $flds, $tableoptions=array())
+ {
+ list($lines,$pkey,$idxs) = $this->_GenFields($flds, true);
+ // genfields can return FALSE at times
+ if ($lines == null) $lines = array();
+
+ $taboptions = $this->_Options($tableoptions);
+ $tabname = $this->TableName ($tabname);
+ $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
+
+ // ggiunta - 2006/10/12 - KLUDGE:
+ // if we are on autoincrement, and table options includes REPLACE, the
+ // autoincrement sequence has already been dropped on table creation sql, so
+ // we avoid passing REPLACE to trigger creation code. This prevents
+ // creating sql that double-drops the sequence
+ if ($this->autoIncrement && isset($taboptions['REPLACE']))
+ unset($taboptions['REPLACE']);
+ $tsql = $this->_Triggers($tabname,$taboptions);
+ foreach($tsql as $s) $sql[] = $s;
+
+ if (is_array($idxs)) {
+ foreach($idxs as $idx => $idxdef) {
+ $sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
+ $sql = array_merge($sql, $sql_idxs);
+ }
+ }
+
+ return $sql;
+ }
+
+ function _GenFields($flds,$widespacing=false)
+ {
+ if (is_string($flds)) {
+ $padding = ' ';
+ $txt = $flds.$padding;
+ $flds = array();
+ $flds0 = Lens_ParseArgs($txt,',');
+ $hasparam = false;
+ foreach($flds0 as $f0) {
+ $f1 = array();
+ foreach($f0 as $token) {
+ switch (strtoupper($token)) {
+ case 'INDEX':
+ $f1['INDEX'] = '';
+ // fall through intentionally
+ case 'CONSTRAINT':
+ case 'DEFAULT':
+ $hasparam = $token;
+ break;
+ default:
+ if ($hasparam) $f1[$hasparam] = $token;
+ else $f1[] = $token;
+ $hasparam = false;
+ break;
+ }
+ }
+ // 'index' token without a name means single column index: name it after column
+ if (array_key_exists('INDEX', $f1) && $f1['INDEX'] == '') {
+ $f1['INDEX'] = isset($f0['NAME']) ? $f0['NAME'] : $f0[0];
+ // check if column name used to create an index name was quoted
+ if (($f1['INDEX'][0] == '"' || $f1['INDEX'][0] == "'" || $f1['INDEX'][0] == "`") &&
+ ($f1['INDEX'][0] == substr($f1['INDEX'], -1))) {
+ $f1['INDEX'] = $f1['INDEX'][0].'idx_'.substr($f1['INDEX'], 1, -1).$f1['INDEX'][0];
+ }
+ else
+ $f1['INDEX'] = 'idx_'.$f1['INDEX'];
+ }
+ // reset it, so we don't get next field 1st token as INDEX...
+ $hasparam = false;
+
+ $flds[] = $f1;
+
+ }
+ }
+ $this->autoIncrement = false;
+ $lines = array();
+ $pkey = array();
+ $idxs = array();
+ foreach($flds as $fld) {
+ $fld = _array_change_key_case($fld);
+
+ $fname = false;
+ $fdefault = false;
+ $fautoinc = false;
+ $ftype = false;
+ $fsize = false;
+ $fprec = false;
+ $fprimary = false;
+ $fnoquote = false;
+ $fdefts = false;
+ $fdefdate = false;
+ $fconstraint = false;
+ $fnotnull = false;
+ $funsigned = false;
+ $findex = '';
+ $funiqueindex = false;
+
+ //-----------------
+ // Parse attributes
+ foreach($fld as $attr => $v) {
+ if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
+ else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
+
+ switch($attr) {
+ case '0':
+ case 'NAME': $fname = $v; break;
+ case '1':
+ case 'TYPE': $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
+
+ case 'SIZE':
+ $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
+ if ($dotat === false) $fsize = $v;
+ else {
+ $fsize = substr($v,0,$dotat);
+ $fprec = substr($v,$dotat+1);
+ }
+ break;
+ case 'UNSIGNED': $funsigned = true; break;
+ case 'AUTOINCREMENT':
+ case 'AUTO': $fautoinc = true; $fnotnull = true; break;
+ case 'KEY':
+ // a primary key col can be non unique in itself (if key spans many cols...)
+ case 'PRIMARY': $fprimary = $v; $fnotnull = true; /*$funiqueindex = true;*/ break;
+ case 'DEF':
+ case 'DEFAULT': $fdefault = $v; break;
+ case 'NOTNULL': $fnotnull = $v; break;
+ case 'NOQUOTE': $fnoquote = $v; break;
+ case 'DEFDATE': $fdefdate = $v; break;
+ case 'DEFTIMESTAMP': $fdefts = $v; break;
+ case 'CONSTRAINT': $fconstraint = $v; break;
+ // let INDEX keyword create a 'very standard' index on column
+ case 'INDEX': $findex = $v; break;
+ case 'UNIQUE': $funiqueindex = true; break;
+ } //switch
+ } // foreach $fld
+
+ //--------------------
+ // VALIDATE FIELD INFO
+ if (!strlen($fname)) {
+ if ($this->debug) ADOConnection::outp("Undefined NAME");
+ return false;
+ }
+
+ $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname));
+ $fname = $this->NameQuote($fname);
+
+ if (!strlen($ftype)) {
+ if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
+ return false;
+ } else {
+ $ftype = strtoupper($ftype);
+ }
+
+ $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
+
+ if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls
+
+ if ($fprimary) $pkey[] = $fname;
+
+ // some databases do not allow blobs to have defaults
+ if ($ty == 'X') $fdefault = false;
+
+ // build list of indexes
+ if ($findex != '') {
+ if (array_key_exists($findex, $idxs)) {
+ $idxs[$findex]['cols'][] = ($fname);
+ if (in_array('UNIQUE', $idxs[$findex]['opts']) != $funiqueindex) {
+ if ($this->debug) ADOConnection::outp("Index $findex defined once UNIQUE and once not");
+ }
+ if ($funiqueindex && !in_array('UNIQUE', $idxs[$findex]['opts']))
+ $idxs[$findex]['opts'][] = 'UNIQUE';
+ }
+ else
+ {
+ $idxs[$findex] = array();
+ $idxs[$findex]['cols'] = array($fname);
+ if ($funiqueindex)
+ $idxs[$findex]['opts'] = array('UNIQUE');
+ else
+ $idxs[$findex]['opts'] = array();
+ }
+ }
+
+ //--------------------
+ // CONSTRUCT FIELD SQL
+ if ($fdefts) {
+ if (substr($this->connection->databaseType,0,5) == 'mysql') {
+ $ftype = 'TIMESTAMP';
+ } else {
+ $fdefault = $this->connection->sysTimeStamp;
+ }
+ } else if ($fdefdate) {
+ if (substr($this->connection->databaseType,0,5) == 'mysql') {
+ $ftype = 'TIMESTAMP';
+ } else {
+ $fdefault = $this->connection->sysDate;
+ }
+ } else if ($fdefault !== false && !$fnoquote) {
+ if ($ty == 'C' or $ty == 'X' or
+ ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault))) {
+
+ if (($ty == 'D' || $ty == 'T') && strtolower($fdefault) != 'null') {
+ // convert default date into database-aware code
+ if ($ty == 'T')
+ {
+ $fdefault = $this->connection->DBTimeStamp($fdefault);
+ }
+ else
+ {
+ $fdefault = $this->connection->DBDate($fdefault);
+ }
+ }
+ else
+ if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ')
+ $fdefault = trim($fdefault);
+ else if (strtolower($fdefault) != 'null')
+ $fdefault = $this->connection->qstr($fdefault);
+ }
+ }
+ $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
+
+ // add index creation
+ if ($widespacing) $fname = str_pad($fname,24);
+
+ // check for field names appearing twice
+ if (array_key_exists($fid, $lines)) {
+ ADOConnection::outp("Field '$fname' defined twice");
+ }
+
+ $lines[$fid] = $fname.' '.$ftype.$suffix;
+
+ if ($fautoinc) $this->autoIncrement = true;
+ } // foreach $flds
+
+ return array($lines,$pkey,$idxs);
+ }
+
+ /**
+ GENERATE THE SIZE PART OF THE DATATYPE
+ $ftype is the actual type
+ $ty is the type defined originally in the DDL
+ */
+ function _GetSize($ftype, $ty, $fsize, $fprec)
+ {
+ if (strlen($fsize) && $ty != 'X' && $ty != 'B' && strpos($ftype,'(') === false) {
+ $ftype .= "(".$fsize;
+ if (strlen($fprec)) $ftype .= ",".$fprec;
+ $ftype .= ')';
+ }
+ return $ftype;
+ }
+
+
+ // return string must begin with space
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+ {
+ $suffix = '';
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+ {
+ $sql = array();
+
+ if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
+ $sql[] = sprintf ($this->dropIndex, $idxname);
+ if ( isset($idxoptions['DROP']) )
+ return $sql;
+ }
+
+ if ( empty ($flds) ) {
+ return $sql;
+ }
+
+ $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
+
+ $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
+
+ if ( isset($idxoptions[$this->upperName]) )
+ $s .= $idxoptions[$this->upperName];
+
+ if ( is_array($flds) )
+ $flds = implode(', ',$flds);
+ $s .= '(' . $flds . ')';
+ $sql[] = $s;
+
+ return $sql;
+ }
+
+ function _DropAutoIncrement($tabname)
+ {
+ return false;
+ }
+
+ function _TableSQL($tabname,$lines,$pkey,$tableoptions)
+ {
+ $sql = array();
+
+ if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) {
+ $sql[] = sprintf($this->dropTable,$tabname);
+ if ($this->autoIncrement) {
+ $sInc = $this->_DropAutoIncrement($tabname);
+ if ($sInc) $sql[] = $sInc;
+ }
+ if ( isset ($tableoptions['DROP']) ) {
+ return $sql;
+ }
+ }
+ $s = "CREATE TABLE $tabname (\n";
+ $s .= implode(",\n", $lines);
+ if (sizeof($pkey)>0) {
+ $s .= ",\n PRIMARY KEY (";
+ $s .= implode(", ",$pkey).")";
+ }
+ if (isset($tableoptions['CONSTRAINTS']))
+ $s .= "\n".$tableoptions['CONSTRAINTS'];
+
+ if (isset($tableoptions[$this->upperName.'_CONSTRAINTS']))
+ $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
+
+ $s .= "\n)";
+ if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
+ $sql[] = $s;
+
+ return $sql;
+ }
+
+ /**
+ GENERATE TRIGGERS IF NEEDED
+ used when table has auto-incrementing field that is emulated using triggers
+ */
+ function _Triggers($tabname,$taboptions)
+ {
+ return array();
+ }
+
+ /**
+ Sanitize options, so that array elements with no keys are promoted to keys
+ */
+ function _Options($opts)
+ {
+ if (!is_array($opts)) return array();
+ $newopts = array();
+ foreach($opts as $k => $v) {
+ if (is_numeric($k)) $newopts[strtoupper($v)] = $v;
+ else $newopts[strtoupper($k)] = $v;
+ }
+ return $newopts;
+ }
+
+ /**
+ "Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
+
+ This function changes/adds new fields to your table. You don't
+ have to know if the col is new or not. It will check on its own.
+ */
+ function ChangeTableSQL($tablename, $flds, $tableoptions = false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false);
+
+ // check table exists
+ $save_handler = $this->connection->raiseErrorFn;
+ $this->connection->raiseErrorFn = '';
+ $cols = $this->MetaColumns($tablename);
+ $this->connection->raiseErrorFn = $save_handler;
+
+ if (isset($savem)) $this->connection->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if ( empty($cols)) {
+ return $this->CreateTableSQL($tablename, $flds, $tableoptions);
+ }
+
+ if (is_array($flds)) {
+ // Cycle through the update fields, comparing
+ // existing fields to fields to update.
+ // if the Metatype and size is exactly the
+ // same, ignore - by Mark Newham
+ $holdflds = array();
+ foreach($flds as $k=>$v) {
+ if ( isset($cols[$k]) && is_object($cols[$k]) ) {
+ // If already not allowing nulls, then don't change
+ $obj = $cols[$k];
+ if (isset($obj->not_null) && $obj->not_null)
+ $v = str_replace('NOT NULL','',$v);
+
+ $c = $cols[$k];
+ $ml = $c->max_length;
+ $mt = $this->MetaType($c->type,$ml);
+ if ($ml == -1) $ml = '';
+ if ($mt == 'X') $ml = $v['SIZE'];
+ if (($mt != $v['TYPE']) || $ml != $v['SIZE']) {
+ $holdflds[$k] = $v;
+ }
+ } else {
+ $holdflds[$k] = $v;
+ }
+ }
+ $flds = $holdflds;
+ }
+
+
+ // already exists, alter table instead
+ list($lines,$pkey,$idxs) = $this->_GenFields($flds);
+ // genfields can return FALSE at times
+ if ($lines == null) $lines = array();
+ $alter = 'ALTER TABLE ' . $this->TableName($tablename);
+ $sql = array();
+
+ foreach ( $lines as $id => $v ) {
+ if ( isset($cols[$id]) && is_object($cols[$id]) ) {
+
+ $flds = Lens_ParseArgs($v,',');
+
+ // We are trying to change the size of the field, if not allowed, simply ignore the request.
+ if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) {
+ echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>";
+ continue;
+ }
+ $sql[] = $alter . $this->alterCol . ' ' . $v;
+ } else {
+ $sql[] = $alter . $this->addCol . ' ' . $v;
+ }
+ }
+
+ return $sql;
+ }
+} // class
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-error.inc.php b/lib/adodb/adodb-error.inc.php
new file mode 100644
index 0000000..e60976b
--- /dev/null
+++ b/lib/adodb/adodb-error.inc.php
@@ -0,0 +1,258 @@
+<?php
+/**
+ * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * The following code is adapted from the PEAR DB error handling code.
+ * Portions (c)1997-2002 The PHP Group.
+ */
+
+
+if (!defined("DB_ERROR")) define("DB_ERROR",-1);
+
+if (!defined("DB_ERROR_SYNTAX")) {
+ define("DB_ERROR_SYNTAX", -2);
+ define("DB_ERROR_CONSTRAINT", -3);
+ define("DB_ERROR_NOT_FOUND", -4);
+ define("DB_ERROR_ALREADY_EXISTS", -5);
+ define("DB_ERROR_UNSUPPORTED", -6);
+ define("DB_ERROR_MISMATCH", -7);
+ define("DB_ERROR_INVALID", -8);
+ define("DB_ERROR_NOT_CAPABLE", -9);
+ define("DB_ERROR_TRUNCATED", -10);
+ define("DB_ERROR_INVALID_NUMBER", -11);
+ define("DB_ERROR_INVALID_DATE", -12);
+ define("DB_ERROR_DIVZERO", -13);
+ define("DB_ERROR_NODBSELECTED", -14);
+ define("DB_ERROR_CANNOT_CREATE", -15);
+ define("DB_ERROR_CANNOT_DELETE", -16);
+ define("DB_ERROR_CANNOT_DROP", -17);
+ define("DB_ERROR_NOSUCHTABLE", -18);
+ define("DB_ERROR_NOSUCHFIELD", -19);
+ define("DB_ERROR_NEED_MORE_DATA", -20);
+ define("DB_ERROR_NOT_LOCKED", -21);
+ define("DB_ERROR_VALUE_COUNT_ON_ROW", -22);
+ define("DB_ERROR_INVALID_DSN", -23);
+ define("DB_ERROR_CONNECT_FAILED", -24);
+ define("DB_ERROR_EXTENSION_NOT_FOUND",-25);
+ define("DB_ERROR_NOSUCHDB", -25);
+ define("DB_ERROR_ACCESS_VIOLATION", -26);
+}
+
+function adodb_errormsg($value)
+{
+global $ADODB_LANG,$ADODB_LANG_ARRAY;
+
+ if (empty($ADODB_LANG)) $ADODB_LANG = 'en';
+ if (isset($ADODB_LANG_ARRAY['LANG']) && $ADODB_LANG_ARRAY['LANG'] == $ADODB_LANG) ;
+ else {
+ include_once(ADODB_DIR."/lang/adodb-$ADODB_LANG.inc.php");
+ }
+ return isset($ADODB_LANG_ARRAY[$value]) ? $ADODB_LANG_ARRAY[$value] : $ADODB_LANG_ARRAY[DB_ERROR];
+}
+
+function adodb_error($provider,$dbType,$errno)
+{
+ //var_dump($errno);
+ if (is_numeric($errno) && $errno == 0) return 0;
+ switch($provider) {
+ case 'mysql': $map = adodb_error_mysql(); break;
+
+ case 'oracle':
+ case 'oci8': $map = adodb_error_oci8(); break;
+
+ case 'ibase': $map = adodb_error_ibase(); break;
+
+ case 'odbc': $map = adodb_error_odbc(); break;
+
+ case 'mssql':
+ case 'sybase': $map = adodb_error_mssql(); break;
+
+ case 'informix': $map = adodb_error_ifx(); break;
+
+ case 'postgres': return adodb_error_pg($errno); break;
+
+ case 'sqlite': return $map = adodb_error_sqlite(); break;
+ default:
+ return DB_ERROR;
+ }
+ //print_r($map);
+ //var_dump($errno);
+ if (isset($map[$errno])) return $map[$errno];
+ return DB_ERROR;
+}
+
+//**************************************************************************************
+
+function adodb_error_pg($errormsg)
+{
+ if (is_numeric($errormsg)) return (integer) $errormsg;
+ static $error_regexps = array(
+ '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/' => DB_ERROR_NOSUCHTABLE,
+ '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/' => DB_ERROR_ALREADY_EXISTS,
+ '/divide by zero$/' => DB_ERROR_DIVZERO,
+ '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,
+ '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,
+ '/parser: parse error at or near \"/' => DB_ERROR_SYNTAX,
+ '/referential integrity violation/' => DB_ERROR_CONSTRAINT,
+ '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key violates unique constraint/'
+ => DB_ERROR_ALREADY_EXISTS
+ );
+ reset($error_regexps);
+ while (list($regexp,$code) = each($error_regexps)) {
+ if (preg_match($regexp, $errormsg)) {
+ return $code;
+ }
+ }
+ // Fall back to DB_ERROR if there was no mapping.
+ return DB_ERROR;
+}
+
+function adodb_error_odbc()
+{
+static $MAP = array(
+ '01004' => DB_ERROR_TRUNCATED,
+ '07001' => DB_ERROR_MISMATCH,
+ '21S01' => DB_ERROR_MISMATCH,
+ '21S02' => DB_ERROR_MISMATCH,
+ '22003' => DB_ERROR_INVALID_NUMBER,
+ '22008' => DB_ERROR_INVALID_DATE,
+ '22012' => DB_ERROR_DIVZERO,
+ '23000' => DB_ERROR_CONSTRAINT,
+ '24000' => DB_ERROR_INVALID,
+ '34000' => DB_ERROR_INVALID,
+ '37000' => DB_ERROR_SYNTAX,
+ '42000' => DB_ERROR_SYNTAX,
+ 'IM001' => DB_ERROR_UNSUPPORTED,
+ 'S0000' => DB_ERROR_NOSUCHTABLE,
+ 'S0001' => DB_ERROR_NOT_FOUND,
+ 'S0002' => DB_ERROR_NOSUCHTABLE,
+ 'S0011' => DB_ERROR_ALREADY_EXISTS,
+ 'S0012' => DB_ERROR_NOT_FOUND,
+ 'S0021' => DB_ERROR_ALREADY_EXISTS,
+ 'S0022' => DB_ERROR_NOT_FOUND,
+ 'S1000' => DB_ERROR_NOSUCHTABLE,
+ 'S1009' => DB_ERROR_INVALID,
+ 'S1090' => DB_ERROR_INVALID,
+ 'S1C00' => DB_ERROR_NOT_CAPABLE
+ );
+ return $MAP;
+}
+
+function adodb_error_ibase()
+{
+static $MAP = array(
+ -104 => DB_ERROR_SYNTAX,
+ -150 => DB_ERROR_ACCESS_VIOLATION,
+ -151 => DB_ERROR_ACCESS_VIOLATION,
+ -155 => DB_ERROR_NOSUCHTABLE,
+ -157 => DB_ERROR_NOSUCHFIELD,
+ -158 => DB_ERROR_VALUE_COUNT_ON_ROW,
+ -170 => DB_ERROR_MISMATCH,
+ -171 => DB_ERROR_MISMATCH,
+ -172 => DB_ERROR_INVALID,
+ -204 => DB_ERROR_INVALID,
+ -205 => DB_ERROR_NOSUCHFIELD,
+ -206 => DB_ERROR_NOSUCHFIELD,
+ -208 => DB_ERROR_INVALID,
+ -219 => DB_ERROR_NOSUCHTABLE,
+ -297 => DB_ERROR_CONSTRAINT,
+ -530 => DB_ERROR_CONSTRAINT,
+ -803 => DB_ERROR_CONSTRAINT,
+ -551 => DB_ERROR_ACCESS_VIOLATION,
+ -552 => DB_ERROR_ACCESS_VIOLATION,
+ -922 => DB_ERROR_NOSUCHDB,
+ -923 => DB_ERROR_CONNECT_FAILED,
+ -924 => DB_ERROR_CONNECT_FAILED
+ );
+
+ return $MAP;
+}
+
+function adodb_error_ifx()
+{
+static $MAP = array(
+ '-201' => DB_ERROR_SYNTAX,
+ '-206' => DB_ERROR_NOSUCHTABLE,
+ '-217' => DB_ERROR_NOSUCHFIELD,
+ '-329' => DB_ERROR_NODBSELECTED,
+ '-1204' => DB_ERROR_INVALID_DATE,
+ '-1205' => DB_ERROR_INVALID_DATE,
+ '-1206' => DB_ERROR_INVALID_DATE,
+ '-1209' => DB_ERROR_INVALID_DATE,
+ '-1210' => DB_ERROR_INVALID_DATE,
+ '-1212' => DB_ERROR_INVALID_DATE
+ );
+
+ return $MAP;
+}
+
+function adodb_error_oci8()
+{
+static $MAP = array(
+ 1 => DB_ERROR_ALREADY_EXISTS,
+ 900 => DB_ERROR_SYNTAX,
+ 904 => DB_ERROR_NOSUCHFIELD,
+ 923 => DB_ERROR_SYNTAX,
+ 942 => DB_ERROR_NOSUCHTABLE,
+ 955 => DB_ERROR_ALREADY_EXISTS,
+ 1476 => DB_ERROR_DIVZERO,
+ 1722 => DB_ERROR_INVALID_NUMBER,
+ 2289 => DB_ERROR_NOSUCHTABLE,
+ 2291 => DB_ERROR_CONSTRAINT,
+ 2449 => DB_ERROR_CONSTRAINT
+ );
+
+ return $MAP;
+}
+
+function adodb_error_mssql()
+{
+static $MAP = array(
+ 208 => DB_ERROR_NOSUCHTABLE,
+ 2601 => DB_ERROR_ALREADY_EXISTS
+ );
+
+ return $MAP;
+}
+
+function adodb_error_sqlite()
+{
+static $MAP = array(
+ 1 => DB_ERROR_SYNTAX
+ );
+
+ return $MAP;
+}
+
+function adodb_error_mysql()
+{
+static $MAP = array(
+ 1004 => DB_ERROR_CANNOT_CREATE,
+ 1005 => DB_ERROR_CANNOT_CREATE,
+ 1006 => DB_ERROR_CANNOT_CREATE,
+ 1007 => DB_ERROR_ALREADY_EXISTS,
+ 1008 => DB_ERROR_CANNOT_DROP,
+ 1045 => DB_ERROR_ACCESS_VIOLATION,
+ 1046 => DB_ERROR_NODBSELECTED,
+ 1049 => DB_ERROR_NOSUCHDB,
+ 1050 => DB_ERROR_ALREADY_EXISTS,
+ 1051 => DB_ERROR_NOSUCHTABLE,
+ 1054 => DB_ERROR_NOSUCHFIELD,
+ 1062 => DB_ERROR_ALREADY_EXISTS,
+ 1064 => DB_ERROR_SYNTAX,
+ 1100 => DB_ERROR_NOT_LOCKED,
+ 1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
+ 1146 => DB_ERROR_NOSUCHTABLE,
+ 1048 => DB_ERROR_CONSTRAINT,
+ 2002 => DB_ERROR_CONNECT_FAILED,
+ 2005 => DB_ERROR_CONNECT_FAILED
+ );
+
+ return $MAP;
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-errorhandler.inc.php b/lib/adodb/adodb-errorhandler.inc.php
new file mode 100644
index 0000000..87a9267
--- /dev/null
+++ b/lib/adodb/adodb-errorhandler.inc.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://php.weblogs.com
+ *
+*/
+
+
+// added Claudio Bustos clbustos#entelchile.net
+if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR);
+
+if (!defined('ADODB_ERROR_HANDLER')) define('ADODB_ERROR_HANDLER','ADODB_Error_Handler');
+
+/**
+* Default Error Handler. This will be called with the following params
+*
+* @param $dbms the RDBMS you are connecting to
+* @param $fn the name of the calling function (in uppercase)
+* @param $errno the native error number from the database
+* @param $errmsg the native error msg from the database
+* @param $p1 $fn specific parameter - see below
+* @param $p2 $fn specific parameter - see below
+* @param $thisConn $current connection object - can be false if no connection object created
+*/
+function ADODB_Error_Handler($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
+{
+ if (error_reporting() == 0) return; // obey @ protocol
+ switch($fn) {
+ case 'EXECUTE':
+ $sql = $p1;
+ $inputparams = $p2;
+
+ $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")\n";
+ break;
+
+ case 'PCONNECT':
+ case 'CONNECT':
+ $host = $p1;
+ $database = $p2;
+
+ $s = "$dbms error: [$errno: $errmsg] in $fn($host, '****', '****', $database)\n";
+ break;
+ default:
+ $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
+ break;
+ }
+ /*
+ * Log connection error somewhere
+ * 0 message is sent to PHP's system logger, using the Operating System's system
+ * logging mechanism or a file, depending on what the error_log configuration
+ * directive is set to.
+ * 1 message is sent by email to the address in the destination parameter.
+ * This is the only message type where the fourth parameter, extra_headers is used.
+ * This message type uses the same internal function as mail() does.
+ * 2 message is sent through the PHP debugging connection.
+ * This option is only available if remote debugging has been enabled.
+ * In this case, the destination parameter specifies the host name or IP address
+ * and optionally, port number, of the socket receiving the debug information.
+ * 3 message is appended to the file destination
+ */
+ if (defined('ADODB_ERROR_LOG_TYPE')) {
+ $t = date('Y-m-d H:i:s');
+ if (defined('ADODB_ERROR_LOG_DEST'))
+ error_log("($t) $s", ADODB_ERROR_LOG_TYPE, ADODB_ERROR_LOG_DEST);
+ else
+ error_log("($t) $s", ADODB_ERROR_LOG_TYPE);
+ }
+
+
+ //print "<p>$s</p>";
+ trigger_error($s,ADODB_ERROR_HANDLER_TYPE);
+}
+?>
diff --git a/lib/adodb/adodb-errorpear.inc.php b/lib/adodb/adodb-errorpear.inc.php
new file mode 100644
index 0000000..31cbe61
--- /dev/null
+++ b/lib/adodb/adodb-errorpear.inc.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://php.weblogs.com
+ *
+*/
+include_once('PEAR.php');
+
+if (!defined('ADODB_ERROR_HANDLER')) define('ADODB_ERROR_HANDLER','ADODB_Error_PEAR');
+
+/*
+* Enabled the following if you want to terminate scripts when an error occurs
+*/
+//PEAR::setErrorHandling (PEAR_ERROR_DIE);
+
+/*
+* Name of the PEAR_Error derived class to call.
+*/
+if (!defined('ADODB_PEAR_ERROR_CLASS')) define('ADODB_PEAR_ERROR_CLASS','PEAR_Error');
+
+/*
+* Store the last PEAR_Error object here
+*/
+global $ADODB_Last_PEAR_Error; $ADODB_Last_PEAR_Error = false;
+
+ /**
+* Error Handler with PEAR support. This will be called with the following params
+*
+* @param $dbms the RDBMS you are connecting to
+* @param $fn the name of the calling function (in uppercase)
+* @param $errno the native error number from the database
+* @param $errmsg the native error msg from the database
+* @param $p1 $fn specific parameter - see below
+* @param $P2 $fn specific parameter - see below
+ */
+function ADODB_Error_PEAR($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)
+{
+global $ADODB_Last_PEAR_Error;
+
+ if (error_reporting() == 0) return; // obey @ protocol
+ switch($fn) {
+ case 'EXECUTE':
+ $sql = $p1;
+ $inputparams = $p2;
+
+ $s = "$dbms error: [$errno: $errmsg] in $fn(\"$sql\")";
+ break;
+
+ case 'PCONNECT':
+ case 'CONNECT':
+ $host = $p1;
+ $database = $p2;
+
+ $s = "$dbms error: [$errno: $errmsg] in $fn('$host', ?, ?, '$database')";
+ break;
+
+ default:
+ $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";
+ break;
+ }
+
+ $class = ADODB_PEAR_ERROR_CLASS;
+ $ADODB_Last_PEAR_Error = new $class($s, $errno,
+ $GLOBALS['_PEAR_default_error_mode'],
+ $GLOBALS['_PEAR_default_error_options'],
+ $errmsg);
+
+ //print "<p>!$s</p>";
+}
+
+/**
+* Returns last PEAR_Error object. This error might be for an error that
+* occured several sql statements ago.
+*/
+function &ADODB_PEAR_Error()
+{
+global $ADODB_Last_PEAR_Error;
+
+ return $ADODB_Last_PEAR_Error;
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-exceptions.inc.php b/lib/adodb/adodb-exceptions.inc.php
new file mode 100644
index 0000000..3eebc4e
--- /dev/null
+++ b/lib/adodb/adodb-exceptions.inc.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://php.weblogs.com
+ *
+ * Exception-handling code using PHP5 exceptions (try-catch-throw).
+ */
+
+
+if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR);
+define('ADODB_ERROR_HANDLER','adodb_throw');
+
+class ADODB_Exception extends Exception {
+var $dbms;
+var $fn;
+var $sql = '';
+var $params = '';
+var $host = '';
+var $database = '';
+
+ function __construct($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
+ {
+ switch($fn) {
+ case 'EXECUTE':
+ $this->sql = $p1;
+ $this->params = $p2;
+ $s = "$dbms error: [$errno: $errmsg] in $fn(\"$p1\")\n";
+ break;
+
+ case 'PCONNECT':
+ case 'CONNECT':
+ $user = $thisConnection->user;
+ $s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)\n";
+ break;
+ default:
+ $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
+ break;
+ }
+
+ $this->dbms = $dbms;
+ if ($thisConnection) {
+ $this->host = $thisConnection->host;
+ $this->database = $thisConnection->database;
+ }
+ $this->fn = $fn;
+ $this->msg = $errmsg;
+
+ if (!is_numeric($errno)) $errno = -1;
+ parent::__construct($s,$errno);
+ }
+}
+
+/**
+* Default Error Handler. This will be called with the following params
+*
+* @param $dbms the RDBMS you are connecting to
+* @param $fn the name of the calling function (in uppercase)
+* @param $errno the native error number from the database
+* @param $errmsg the native error msg from the database
+* @param $p1 $fn specific parameter - see below
+* @param $P2 $fn specific parameter - see below
+*/
+
+function adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
+{
+global $ADODB_EXCEPTION;
+
+ if (error_reporting() == 0) return; // obey @ protocol
+ if (is_string($ADODB_EXCEPTION)) $errfn = $ADODB_EXCEPTION;
+ else $errfn = 'ADODB_EXCEPTION';
+ throw new $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection);
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-iterator.inc.php b/lib/adodb/adodb-iterator.inc.php
new file mode 100644
index 0000000..d291e78
--- /dev/null
+++ b/lib/adodb/adodb-iterator.inc.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4.
+
+ Declares the ADODB Base Class for PHP5 "ADODB_BASE_RS", and supports iteration with
+ the ADODB_Iterator class.
+
+ $rs = $db->Execute("select * from adoxyz");
+ foreach($rs as $k => $v) {
+ echo $k; print_r($v); echo "<br>";
+ }
+
+
+ Iterator code based on http://cvs.php.net/cvs.php/php-src/ext/spl/examples/cachingiterator.inc?login=2
+ */
+
+
+ class ADODB_Iterator implements Iterator {
+
+ private $rs;
+
+ function __construct($rs)
+ {
+ $this->rs = $rs;
+ }
+ function rewind()
+ {
+ $this->rs->MoveFirst();
+ }
+
+ function valid()
+ {
+ return !$this->rs->EOF;
+ }
+
+ function key()
+ {
+ return $this->rs->_currentRow;
+ }
+
+ function current()
+ {
+ return $this->rs->fields;
+ }
+
+ 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;
+ }
+
+}
+
+
+class ADODB_BASE_RS implements IteratorAggregate {
+ 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);
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-lib.inc.php b/lib/adodb/adodb-lib.inc.php
new file mode 100644
index 0000000..2a67f28
--- /dev/null
+++ b/lib/adodb/adodb-lib.inc.php
@@ -0,0 +1,1137 @@
+<?php
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+global $ADODB_INCLUDED_LIB;
+$ADODB_INCLUDED_LIB = 1;
+
+/*
+ @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim\@natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Less commonly used functions are placed here to reduce size of adodb.inc.php.
+*/
+
+function adodb_probetypes(&$array,&$types,$probe=8)
+{
+// probe and guess the type
+ $types = array();
+ if ($probe > sizeof($array)) $max = sizeof($array);
+ else $max = $probe;
+
+
+ for ($j=0;$j < $max; $j++) {
+ $row =& $array[$j];
+ if (!$row) break;
+ $i = -1;
+ foreach($row as $v) {
+ $i += 1;
+
+ if (isset($types[$i]) && $types[$i]=='C') continue;
+
+ //print " ($i ".$types[$i]. "$v) ";
+ $v = trim($v);
+
+ if (!preg_match('/^[+-]{0,1}[0-9\.]+$/',$v)) {
+ $types[$i] = 'C'; // once C, always C
+
+ continue;
+ }
+ if ($j == 0) {
+ // If empty string, we presume is character
+ // test for integer for 1st row only
+ // after that it is up to testing other rows to prove
+ // that it is not an integer
+ if (strlen($v) == 0) $types[$i] = 'C';
+ if (strpos($v,'.') !== false) $types[$i] = 'N';
+ else $types[$i] = 'I';
+ continue;
+ }
+
+ if (strpos($v,'.') !== false) $types[$i] = 'N';
+
+ }
+ }
+
+}
+
+function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs)
+{
+ $oldX = sizeof(reset($arr));
+ $oldY = sizeof($arr);
+
+ if ($hdr) {
+ $startx = 1;
+ $hdr = array('Fields');
+ for ($y = 0; $y < $oldY; $y++) {
+ $hdr[] = $arr[$y][0];
+ }
+ } else
+ $startx = 0;
+
+ for ($x = $startx; $x < $oldX; $x++) {
+ if ($fobjs) {
+ $o = $fobjs[$x];
+ $newarr[] = array($o->name);
+ } else
+ $newarr[] = array();
+
+ for ($y = 0; $y < $oldY; $y++) {
+ $newarr[$x-$startx][] = $arr[$y][$x];
+ }
+ }
+}
+
+// Force key to upper.
+// See also http://www.php.net/manual/en/function.array-change-key-case.php
+function _array_change_key_case($an_array)
+{
+ if (is_array($an_array)) {
+ $new_array = array();
+ foreach($an_array as $key=>$value)
+ $new_array[strtoupper($key)] = $value;
+
+ return $new_array;
+ }
+
+ return $an_array;
+}
+
+function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc)
+{
+ if (count($fieldArray) == 0) return 0;
+ $first = true;
+ $uSet = '';
+
+ if (!is_array($keyCol)) {
+ $keyCol = array($keyCol);
+ }
+ foreach($fieldArray as $k => $v) {
+ if ($autoQuote && !is_numeric($v) and strncmp($v,"'",1) !== 0 and strcasecmp($v,$zthis->null2null)!=0) {
+ $v = $zthis->qstr($v);
+ $fieldArray[$k] = $v;
+ }
+ if (in_array($k,$keyCol)) continue; // skip UPDATE if is key
+
+ if ($first) {
+ $first = false;
+ $uSet = "$k=$v";
+ } else
+ $uSet .= ",$k=$v";
+ }
+
+ $where = false;
+ foreach ($keyCol as $v) {
+ if (isset($fieldArray[$v])) {
+ if ($where) $where .= ' and '.$v.'='.$fieldArray[$v];
+ else $where = $v.'='.$fieldArray[$v];
+ }
+ }
+
+ if ($uSet && $where) {
+ $update = "UPDATE $table SET $uSet WHERE $where";
+
+ $rs = $zthis->Execute($update);
+
+
+ if ($rs) {
+ if ($zthis->poorAffectedRows) {
+ /*
+ The Select count(*) wipes out any errors that the update would have returned.
+ http://phplens.com/lens/lensforum/msgs.php?id=5696
+ */
+ if ($zthis->ErrorNo()<>0) return 0;
+
+ # affected_rows == 0 if update field values identical to old values
+ # for mysql - which is silly.
+
+ $cnt = $zthis->GetOne("select count(*) from $table where $where");
+ if ($cnt > 0) return 1; // record already exists
+ } else {
+ if (($zthis->Affected_Rows()>0)) return 1;
+ }
+ } else
+ return 0;
+ }
+
+ // print "<p>Error=".$this->ErrorNo().'<p>';
+ $first = true;
+ foreach($fieldArray as $k => $v) {
+ if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col
+
+ if ($first) {
+ $first = false;
+ $iCols = "$k";
+ $iVals = "$v";
+ } else {
+ $iCols .= ",$k";
+ $iVals .= ",$v";
+ }
+ }
+ $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
+ $rs = $zthis->Execute($insert);
+ return ($rs) ? 2 : 0;
+}
+
+// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
+function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
+ $size=0, $selectAttr='',$compareFields0=true)
+{
+ $hasvalue = false;
+
+ if ($multiple or is_array($defstr)) {
+ if ($size==0) $size=5;
+ $attr = ' multiple size="'.$size.'"';
+ if (!strpos($name,'[]')) $name .= '[]';
+ } else if ($size) $attr = ' size="'.$size.'"';
+ else $attr ='';
+
+ $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
+ if ($blank1stItem)
+ if (is_string($blank1stItem)) {
+ $barr = explode(':',$blank1stItem);
+ if (sizeof($barr) == 1) $barr[] = '';
+ $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>";
+ } else $s .= "\n<option></option>";
+
+ if ($zthis->FieldCount() > 1) $hasvalue=true;
+ else $compareFields0 = true;
+
+ $value = '';
+ $optgroup = null;
+ $firstgroup = true;
+ $fieldsize = $zthis->FieldCount();
+ while(!$zthis->EOF) {
+ $zval = rtrim(reset($zthis->fields));
+
+ if ($blank1stItem && $zval=="") {
+ $zthis->MoveNext();
+ continue;
+ }
+
+ if ($fieldsize > 1) {
+ if (isset($zthis->fields[1]))
+ $zval2 = rtrim($zthis->fields[1]);
+ else
+ $zval2 = rtrim(next($zthis->fields));
+ }
+ $selected = ($compareFields0) ? $zval : $zval2;
+
+ $group = '';
+ if ($fieldsize > 2) {
+ $group = rtrim($zthis->fields[2]);
+ }
+/*
+ if ($optgroup != $group) {
+ $optgroup = $group;
+ if ($firstgroup) {
+ $firstgroup = false;
+ $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
+ } else {
+ $s .="\n</optgroup>";
+ $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
+ }
+ }
+*/
+ if ($hasvalue)
+ $value = " value='".htmlspecialchars($zval2)."'";
+
+ if (is_array($defstr)) {
+
+ if (in_array($selected,$defstr))
+ $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
+ else
+ $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+ }
+ else {
+ if (strcasecmp($selected,$defstr)==0)
+ $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
+ else
+ $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+ }
+ $zthis->MoveNext();
+ } // while
+
+ // closing last optgroup
+ if($optgroup != null) {
+ $s .= "\n</optgroup>";
+ }
+ return $s ."\n</select>\n";
+}
+
+// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
+function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
+ $size=0, $selectAttr='',$compareFields0=true)
+{
+ $hasvalue = false;
+
+ if ($multiple or is_array($defstr)) {
+ if ($size==0) $size=5;
+ $attr = ' multiple size="'.$size.'"';
+ if (!strpos($name,'[]')) $name .= '[]';
+ } else if ($size) $attr = ' size="'.$size.'"';
+ else $attr ='';
+
+ $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
+ if ($blank1stItem)
+ if (is_string($blank1stItem)) {
+ $barr = explode(':',$blank1stItem);
+ if (sizeof($barr) == 1) $barr[] = '';
+ $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>";
+ } else $s .= "\n<option></option>";
+
+ if ($zthis->FieldCount() > 1) $hasvalue=true;
+ else $compareFields0 = true;
+
+ $value = '';
+ $optgroup = null;
+ $firstgroup = true;
+ $fieldsize = sizeof($zthis->fields);
+ while(!$zthis->EOF) {
+ $zval = rtrim(reset($zthis->fields));
+
+ if ($blank1stItem && $zval=="") {
+ $zthis->MoveNext();
+ continue;
+ }
+
+ if ($fieldsize > 1) {
+ if (isset($zthis->fields[1]))
+ $zval2 = rtrim($zthis->fields[1]);
+ else
+ $zval2 = rtrim(next($zthis->fields));
+ }
+ $selected = ($compareFields0) ? $zval : $zval2;
+
+ $group = '';
+ if (isset($zthis->fields[2])) {
+ $group = rtrim($zthis->fields[2]);
+ }
+
+ if ($optgroup != $group) {
+ $optgroup = $group;
+ if ($firstgroup) {
+ $firstgroup = false;
+ $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
+ } else {
+ $s .="\n</optgroup>";
+ $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
+ }
+ }
+
+ if ($hasvalue)
+ $value = " value='".htmlspecialchars($zval2)."'";
+
+ if (is_array($defstr)) {
+
+ if (in_array($selected,$defstr))
+ $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
+ else
+ $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+ }
+ else {
+ if (strcasecmp($selected,$defstr)==0)
+ $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
+ else
+ $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
+ }
+ $zthis->MoveNext();
+ } // while
+
+ // closing last optgroup
+ if($optgroup != null) {
+ $s .= "\n</optgroup>";
+ }
+ return $s ."\n</select>\n";
+}
+
+
+/*
+ Count the number of records this sql statement will return by using
+ query rewriting heuristics...
+
+ Does not work with UNIONs, except with postgresql and oracle.
+
+ Usage:
+
+ $conn->Connect(...);
+ $cnt = _adodb_getcount($conn, $sql);
+
+*/
+function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
+{
+ $qryRecs = 0;
+
+ if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) ||
+ preg_match('/\s+GROUP\s+BY\s+/is',$sql) ||
+ preg_match('/\s+UNION\s+/is',$sql)) {
+ // ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias
+ // but this is only supported by oracle and postgresql...
+ if ($zthis->dataProvider == 'oci8') {
+
+ $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql);
+
+ // Allow Oracle hints to be used for query optimization, Chris Wrye
+ if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) {
+ $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")";
+ } else
+ $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")";
+
+ } else if (strncmp($zthis->databaseType,'postgres',8) == 0) {
+ $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql);
+ $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_";
+ }
+ } else {
+ // now replace SELECT ... FROM with SELECT COUNT(*) FROM
+ $rewritesql = preg_replace(
+ '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);
+
+
+
+ // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails
+ // with mssql, access and postgresql. Also a good speedup optimization - skips sorting!
+ // also see http://phplens.com/lens/lensforum/msgs.php?id=12752
+ if (preg_match('/\sORDER\s+BY\s*\(/i',$rewritesql))
+ $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$rewritesql);
+ else
+ $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$rewritesql);
+ }
+
+
+
+ if (isset($rewritesql) && $rewritesql != $sql) {
+ if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[1];
+
+ if ($secs2cache) {
+ // we only use half the time of secs2cache because the count can quickly
+ // become inaccurate if new records are added
+ $qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);
+
+ } else {
+ $qryRecs = $zthis->GetOne($rewritesql,$inputarr);
+ }
+ if ($qryRecs !== false) return $qryRecs;
+ }
+ //--------------------------------------------
+ // query rewrite failed - so try slower way...
+
+
+ // strip off unneeded ORDER BY if no UNION
+ if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
+ else $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);
+
+ if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
+
+ $rstest = &$zthis->Execute($rewritesql,$inputarr);
+ if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
+
+ if ($rstest) {
+ $qryRecs = $rstest->RecordCount();
+ if ($qryRecs == -1) {
+ global $ADODB_EXTENSION;
+ // some databases will return -1 on MoveLast() - change to MoveNext()
+ if ($ADODB_EXTENSION) {
+ while(!$rstest->EOF) {
+ adodb_movenext($rstest);
+ }
+ } else {
+ while(!$rstest->EOF) {
+ $rstest->MoveNext();
+ }
+ }
+ $qryRecs = $rstest->_currentRow;
+ }
+ $rstest->Close();
+ if ($qryRecs == -1) return 0;
+ }
+ return $qryRecs;
+}
+
+/*
+ Code originally from "Cornel G" <conyg@fx.ro>
+
+ This code might not work with SQL that has UNION in it
+
+ Also if you are using CachePageExecute(), there is a strong possibility that
+ data will get out of synch. use CachePageExecute() only with tables that
+ rarely change.
+*/
+function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
+ $inputarr=false, $secs2cache=0)
+{
+ $atfirstpage = false;
+ $atlastpage = false;
+ $lastpageno=1;
+
+ // If an invalid nrows is supplied,
+ // we assume a default value of 10 rows per page
+ if (!isset($nrows) || $nrows <= 0) $nrows = 10;
+
+ $qryRecs = false; //count records for no offset
+
+ $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
+ $lastpageno = (int) ceil($qryRecs / $nrows);
+ $zthis->_maxRecordCount = $qryRecs;
+
+
+
+ // ***** Here we check whether $page is the last page or
+ // whether we are trying to retrieve
+ // a page number greater than the last page number.
+ if ($page >= $lastpageno) {
+ $page = $lastpageno;
+ $atlastpage = true;
+ }
+
+ // If page number <= 1, then we are at the first page
+ if (empty($page) || $page <= 1) {
+ $page = 1;
+ $atfirstpage = true;
+ }
+
+ // We get the data we want
+ $offset = $nrows * ($page-1);
+ if ($secs2cache > 0)
+ $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
+ else
+ $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
+
+
+ // Before returning the RecordSet, we set the pagination properties we need
+ if ($rsreturn) {
+ $rsreturn->_maxRecordCount = $qryRecs;
+ $rsreturn->rowsPerPage = $nrows;
+ $rsreturn->AbsolutePage($page);
+ $rsreturn->AtFirstPage($atfirstpage);
+ $rsreturn->AtLastPage($atlastpage);
+ $rsreturn->LastPageNo($lastpageno);
+ }
+ return $rsreturn;
+}
+
+// Iván Oliva version
+function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
+{
+
+ $atfirstpage = false;
+ $atlastpage = false;
+
+ if (!isset($page) || $page <= 1) { // If page number <= 1, then we are at the first page
+ $page = 1;
+ $atfirstpage = true;
+ }
+ if ($nrows <= 0) $nrows = 10; // If an invalid nrows is supplied, we assume a default value of 10 rows per page
+
+ // ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than
+ // the last page number.
+ $pagecounter = $page + 1;
+ $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
+ if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
+ else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
+ if ($rstest) {
+ while ($rstest && $rstest->EOF && $pagecounter>0) {
+ $atlastpage = true;
+ $pagecounter--;
+ $pagecounteroffset = $nrows * ($pagecounter - 1);
+ $rstest->Close();
+ if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
+ else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
+ }
+ if ($rstest) $rstest->Close();
+ }
+ if ($atlastpage) { // If we are at the last page or beyond it, we are going to retrieve it
+ $page = $pagecounter;
+ if ($page == 1) $atfirstpage = true; // We have to do this again in case the last page is the same as the first
+ //... page, that is, the recordset has only 1 page.
+ }
+
+ // We get the data we want
+ $offset = $nrows * ($page-1);
+ if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
+ else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
+
+ // Before returning the RecordSet, we set the pagination properties we need
+ if ($rsreturn) {
+ $rsreturn->rowsPerPage = $nrows;
+ $rsreturn->AbsolutePage($page);
+ $rsreturn->AtFirstPage($atfirstpage);
+ $rsreturn->AtLastPage($atlastpage);
+ }
+ return $rsreturn;
+}
+
+function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=2)
+{
+ global $ADODB_QUOTE_FIELDNAMES;
+
+ if (!$rs) {
+ printf(ADODB_BAD_RS,'GetUpdateSQL');
+ return false;
+ }
+
+ $fieldUpdatedCount = 0;
+ $arrFields = _array_change_key_case($arrFields);
+
+ $hasnumeric = isset($rs->fields[0]);
+ $setFields = '';
+
+ // Loop through all of the fields in the recordset
+ for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
+ // Get the field from the recordset
+ $field = $rs->FetchField($i);
+
+ // If the recordset field is one
+ // of the fields passed in then process.
+ $upperfname = strtoupper($field->name);
+ if (adodb_key_exists($upperfname,$arrFields,$force)) {
+
+ // If the existing field value in the recordset
+ // is different from the value passed in then
+ // go ahead and append the field name and new value to
+ // the update query.
+
+ if ($hasnumeric) $val = $rs->fields[$i];
+ else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
+ else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name];
+ else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)];
+ else $val = '';
+
+
+ if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
+ // Set the counter for the number of fields that will be updated.
+ $fieldUpdatedCount++;
+
+ // Based on the datatype of the field
+ // Format the value properly for the database
+ $type = $rs->MetaType($field->type);
+
+
+ if ($type == 'null') {
+ $type = 'C';
+ }
+
+ if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES))
+ $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;
+ else
+ $fnameq = $upperfname;
+
+
+ // is_null requires php 4.0.4
+ //********************************************************//
+ if (is_null($arrFields[$upperfname])
+ || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
+ || $arrFields[$upperfname] === $zthis->null2null
+ )
+ {
+ switch ($force) {
+
+ //case 0:
+ // //Ignore empty values. This is allready handled in "adodb_key_exists" function.
+ //break;
+
+ case 1:
+ //Set null
+ $setFields .= $field->name . " = null, ";
+ break;
+
+ case 2:
+ //Set empty
+ $arrFields[$upperfname] = "";
+ $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
+ break;
+ default:
+ case 3:
+ //Set the value that was given in array, so you can give both null and empty values
+ if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
+ $setFields .= $field->name . " = null, ";
+ } else {
+ $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
+ }
+ break;
+ }
+ //********************************************************//
+ } else {
+ //we do this so each driver can customize the sql for
+ //DB specific column types.
+ //Oracle needs BLOB types to be handled with a returning clause
+ //postgres has special needs as well
+ $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,
+ $arrFields, $magicq);
+ }
+ }
+ }
+ }
+
+ // If there were any modified fields then build the rest of the update query.
+ if ($fieldUpdatedCount > 0 || $forceUpdate) {
+ // Get the table name from the existing query.
+ if (!empty($rs->tableName)) $tableName = $rs->tableName;
+ else {
+ preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
+ $tableName = $tableName[1];
+ }
+ // Get the full where clause excluding the word "WHERE" from
+ // the existing query.
+ preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
+
+ $discard = false;
+ // not a good hack, improvements?
+ if ($whereClause) {
+ #var_dump($whereClause);
+ if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard));
+ else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard));
+ else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard));
+ else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see http://sourceforge.net/tracker/index.php?func=detail&aid=1379638&group_id=42718&atid=433976
+ } else
+ $whereClause = array(false,false);
+
+ if ($discard)
+ $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));
+
+ $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2);
+ if (strlen($whereClause[1]) > 0)
+ $sql .= ' WHERE '.$whereClause[1];
+
+ return $sql;
+
+ } else {
+ return false;
+ }
+}
+
+function adodb_key_exists($key, &$arr,$force=2)
+{
+ if ($force<=0) {
+ // the following is the old behaviour where null or empty fields are ignored
+ return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0);
+ }
+
+ if (isset($arr[$key])) return true;
+ ## null check below
+ if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr);
+ return false;
+}
+
+/**
+ * There is a special case of this function for the oci8 driver.
+ * The proper way to handle an insert w/ a blob in oracle requires
+ * a returning clause with bind variables and a descriptor blob.
+ *
+ *
+ */
+function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
+{
+static $cacheRS = false;
+static $cacheSig = 0;
+static $cacheCols;
+ global $ADODB_QUOTE_FIELDNAMES;
+
+ $tableName = '';
+ $values = '';
+ $fields = '';
+ $recordSet = null;
+ $arrFields = _array_change_key_case($arrFields);
+ $fieldInsertedCount = 0;
+
+ if (is_string($rs)) {
+ //ok we have a table name
+ //try and get the column info ourself.
+ $tableName = $rs;
+
+ //we need an object for the recordSet
+ //because we have to call MetaType.
+ //php can't do a $rsclass::MetaType()
+ $rsclass = $zthis->rsPrefix.$zthis->databaseType;
+ $recordSet = new $rsclass(-1,$zthis->fetchMode);
+ $recordSet->connection = &$zthis;
+
+ if (is_string($cacheRS) && $cacheRS == $rs) {
+ $columns =& $cacheCols;
+ } else {
+ $columns = $zthis->MetaColumns( $tableName );
+ $cacheRS = $tableName;
+ $cacheCols = $columns;
+ }
+ } else if (is_subclass_of($rs, 'adorecordset')) {
+ if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) {
+ $columns =& $cacheCols;
+ } else {
+ for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
+ $columns[] = $rs->FetchField($i);
+ $cacheRS = $cacheSig;
+ $cacheCols = $columns;
+ $rs->insertSig = $cacheSig++;
+ }
+ $recordSet =& $rs;
+
+ } else {
+ printf(ADODB_BAD_RS,'GetInsertSQL');
+ return false;
+ }
+
+ // Loop through all of the fields in the recordset
+ foreach( $columns as $field ) {
+ $upperfname = strtoupper($field->name);
+ if (adodb_key_exists($upperfname,$arrFields,$force)) {
+ $bad = false;
+ if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES))
+ $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;
+ else
+ $fnameq = $upperfname;
+
+ $type = $recordSet->MetaType($field->type);
+
+ /********************************************************/
+ if (is_null($arrFields[$upperfname])
+ || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
+ || $arrFields[$upperfname] === $zthis->null2null
+ )
+ {
+ switch ($force) {
+
+ case 0: // we must always set null if missing
+ $bad = true;
+ break;
+
+ case 1:
+ $values .= "null, ";
+ break;
+
+ case 2:
+ //Set empty
+ $arrFields[$upperfname] = "";
+ $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,$arrFields, $magicq);
+ break;
+
+ default:
+ case 3:
+ //Set the value that was given in array, so you can give both null and empty values
+ if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
+ $values .= "null, ";
+ } else {
+ $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields, $magicq);
+ }
+ break;
+ } // switch
+
+ /*********************************************************/
+ } else {
+ //we do this so each driver can customize the sql for
+ //DB specific column types.
+ //Oracle needs BLOB types to be handled with a returning clause
+ //postgres has special needs as well
+ $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,
+ $arrFields, $magicq);
+ }
+
+ if ($bad) continue;
+ // Set the counter for the number of fields that will be inserted.
+ $fieldInsertedCount++;
+
+
+ // Get the name of the fields to insert
+ $fields .= $fnameq . ", ";
+ }
+ }
+
+
+ // If there were any inserted fields then build the rest of the insert query.
+ if ($fieldInsertedCount <= 0) return false;
+
+ // Get the table name from the existing query.
+ if (!$tableName) {
+ if (!empty($rs->tableName)) $tableName = $rs->tableName;
+ else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName))
+ $tableName = $tableName[1];
+ else
+ return false;
+ }
+
+ // Strip off the comma and space on the end of both the fields
+ // and their values.
+ $fields = substr($fields, 0, -2);
+ $values = substr($values, 0, -2);
+
+ // Append the fields and their values to the insert query.
+ return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' )';
+}
+
+
+/**
+ * This private method is used to help construct
+ * the update/sql which is generated by GetInsertSQL and GetUpdateSQL.
+ * It handles the string construction of 1 column -> sql string based on
+ * the column type. We want to do 'safe' handling of BLOBs
+ *
+ * @param string the type of sql we are trying to create
+ * 'I' or 'U'.
+ * @param string column data type from the db::MetaType() method
+ * @param string the column name
+ * @param array the column value
+ *
+ * @return string
+ *
+ */
+function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields, $magicq)
+{
+ $sql = '';
+
+ // Based on the datatype of the field
+ // Format the value properly for the database
+ switch($type) {
+ case 'B':
+ //in order to handle Blobs correctly, we need
+ //to do some magic for Oracle
+
+ //we need to create a new descriptor to handle
+ //this properly
+ if (!empty($zthis->hasReturningInto)) {
+ if ($action == 'I') {
+ $sql = 'empty_blob(), ';
+ } else {
+ $sql = $fnameq. '=empty_blob(), ';
+ }
+ //add the variable to the returning clause array
+ //so the user can build this later in
+ //case they want to add more to it
+ $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
+ } else if (empty($arrFields[$fname])){
+ if ($action == 'I') {
+ $sql = 'empty_blob(), ';
+ } else {
+ $sql = $fnameq. '=empty_blob(), ';
+ }
+ } else {
+ //this is to maintain compatibility
+ //with older adodb versions.
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
+ }
+ break;
+
+ case "X":
+ //we need to do some more magic here for long variables
+ //to handle these correctly in oracle.
+
+ //create a safe bind var name
+ //to avoid conflicts w/ dupes.
+ if (!empty($zthis->hasReturningInto)) {
+ if ($action == 'I') {
+ $sql = ':xx'.$fname.'xx, ';
+ } else {
+ $sql = $fnameq.'=:xx'.$fname.'xx, ';
+ }
+ //add the variable to the returning clause array
+ //so the user can build this later in
+ //case they want to add more to it
+ $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
+ } else {
+ //this is to maintain compatibility
+ //with older adodb versions.
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
+ }
+ break;
+
+ default:
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
+ break;
+ }
+
+ return $sql;
+}
+
+function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq, $recurse=true)
+{
+
+ if ($recurse) {
+ switch($zthis->dataProvider) {
+ case 'postgres':
+ if ($type == 'L') $type = 'C';
+ break;
+ case 'oci8':
+ return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq);
+
+ }
+ }
+
+ switch($type) {
+ case "C":
+ case "X":
+ case 'B':
+ $val = $zthis->qstr($arrFields[$fname],$magicq);
+ break;
+
+ case "D":
+ $val = $zthis->DBDate($arrFields[$fname]);
+ break;
+
+ case "T":
+ $val = $zthis->DBTimeStamp($arrFields[$fname]);
+ break;
+
+ default:
+ $val = $arrFields[$fname];
+ if (empty($val)) $val = '0';
+ break;
+ }
+
+ if ($action == 'I') return $val . ", ";
+
+
+ return $fnameq . "=" . $val . ", ";
+
+}
+
+
+
+function _adodb_debug_execute(&$zthis, $sql, $inputarr)
+{
+ $ss = '';
+ if ($inputarr) {
+ foreach($inputarr as $kk=>$vv) {
+ if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
+ $ss .= "($kk=>'$vv') ";
+ }
+ $ss = "[ $ss ]";
+ }
+ $sqlTxt = is_array($sql) ? $sql[0] : $sql;
+ /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql);
+ $sqlTxt = str_replace(',',', ',$sqlTxt);
+ $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt);
+ */
+ // check if running from browser or command-line
+ $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
+
+ $dbt = $zthis->databaseType;
+ if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType;
+ if ($inBrowser) {
+ if ($ss) {
+ $ss = '<code>'.htmlspecialchars($ss).'</code>';
+ }
+ if ($zthis->debug === -1)
+ ADOConnection::outp( "<br />\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<br />\n",false);
+ else
+ ADOConnection::outp( "<hr />\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr />\n",false);
+ } else {
+ ADOConnection::outp("-----\n($dbt): ".$sqlTxt."\n-----\n",false);
+ }
+
+ $qID = $zthis->_query($sql,$inputarr);
+
+ /*
+ Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
+ because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
+ */
+ if ($zthis->databaseType == 'mssql') {
+ // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
+ if($emsg = $zthis->ErrorMsg()) {
+ if ($err = $zthis->ErrorNo()) ADOConnection::outp($err.': '.$emsg);
+ }
+ } else if (!$qID) {
+ ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg());
+ }
+
+ if ($zthis->debug === 99) _adodb_backtrace(true,9999,2);
+ return $qID;
+}
+
+# pretty print the debug_backtrace function
+function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
+{
+ if (!function_exists('debug_backtrace')) return '';
+
+ $html = (isset($_SERVER['HTTP_USER_AGENT']));
+ $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
+
+ $MAXSTRLEN = 128;
+
+ $s = ($html) ? '<pre align=left>' : '';
+
+ if (is_array($printOrArr)) $traceArr = $printOrArr;
+ else $traceArr = debug_backtrace();
+ array_shift($traceArr);
+ array_shift($traceArr);
+ $tabs = sizeof($traceArr)-2;
+
+ foreach ($traceArr as $arr) {
+ if ($skippy) {$skippy -= 1; continue;}
+ $levels -= 1;
+ if ($levels < 0) break;
+
+ $args = array();
+ for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' &nbsp; ' : "\t";
+ $tabs -= 1;
+ if ($html) $s .= '<font face="Courier New,Courier">';
+ if (isset($arr['class'])) $s .= $arr['class'].'.';
+ if (isset($arr['args']))
+ foreach($arr['args'] as $v) {
+ if (is_null($v)) $args[] = 'null';
+ else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
+ else if (is_object($v)) $args[] = 'Object:'.get_class($v);
+ else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
+ else {
+ $v = (string) @$v;
+ $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
+ if (strlen($v) > $MAXSTRLEN) $str .= '...';
+ $args[] = $str;
+ }
+ }
+ $s .= $arr['function'].'('.implode(', ',$args).')';
+
+
+ $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file']));
+
+ $s .= "\n";
+ }
+ if ($html) $s .= '</pre>';
+ if ($printOrArr) print $s;
+
+ return $s;
+}
+/*
+function _adodb_find_from($sql)
+{
+
+ $sql = str_replace(array("\n","\r"), ' ', $sql);
+ $charCount = strlen($sql);
+
+ $inString = false;
+ $quote = '';
+ $parentheseCount = 0;
+ $prevChars = '';
+ $nextChars = '';
+
+
+ for($i = 0; $i < $charCount; $i++) {
+
+ $char = substr($sql,$i,1);
+ $prevChars = substr($sql,0,$i);
+ $nextChars = substr($sql,$i+1);
+
+ if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) {
+ $quote = $char;
+ $inString = true;
+ }
+
+ elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) {
+ $quote = "";
+ $inString = false;
+ }
+
+ elseif($char == "(" && $inString === false)
+ $parentheseCount++;
+
+ elseif($char == ")" && $inString === false && $parentheseCount > 0)
+ $parentheseCount--;
+
+ elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM")
+ return $i;
+
+ }
+}
+*/
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-memcache.lib.inc.php b/lib/adodb/adodb-memcache.lib.inc.php
new file mode 100644
index 0000000..bc6b420
--- /dev/null
+++ b/lib/adodb/adodb-memcache.lib.inc.php
@@ -0,0 +1,118 @@
+<?php
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+global $ADODB_INCLUDED_MEMCACHE;
+$ADODB_INCLUDED_MEMCACHE = 1;
+
+/*
+
+ V4.90 8 June 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+*/
+
+ function &getmemcache($key,&$err, $timeout=0, $host, $port)
+ {
+ $false = false;
+ $err = false;
+
+ if (!function_exists('memcache_pconnect')) {
+ $err = 'Memcache module PECL extension not found!';
+ return $false;
+ }
+
+ $memcache = new Memcache;
+ if (!@$memcache->pconnect($host, $port)) {
+ $err = 'Can\'t connect to memcache server on: '.$host.':'.$port;
+ return $false;
+ }
+
+ $rs = $memcache->get($key);
+ if (!$rs) {
+ $err = 'Item with such key doesn\'t exists on the memcached server.';
+ return $false;
+ }
+
+ $tdiff = intval($rs->timeCreated+$timeout - time());
+ if ($tdiff <= 2) {
+ switch($tdiff) {
+ case 2:
+ if ((rand() & 15) == 0) {
+ $err = "Timeout 2";
+ return $false;
+ }
+ break;
+ case 1:
+ if ((rand() & 3) == 0) {
+ $err = "Timeout 1";
+ return $false;
+ }
+ break;
+ default:
+ $err = "Timeout 0";
+ return $false;
+ }
+ }
+ return $rs;
+ }
+
+ function putmemcache($key, $rs, $host, $port, $compress, $debug=false)
+ {
+ $false = false;
+ $true = true;
+
+ if (!function_exists('memcache_pconnect')) {
+ if ($debug) ADOConnection::outp(" Memcache module PECL extension not found!<br>\n");
+ return $false;
+ }
+
+ $memcache = new Memcache;
+ if (!@$memcache->pconnect($host, $port)) {
+ if ($debug) ADOConnection::outp(" Can't connect to memcache server on: $host:$port<br>\n");
+ return $false;
+ }
+
+ $rs->timeCreated = time();
+ if (!$memcache->set($key, $rs, $compress, 0)) {
+ if ($debug) ADOConnection::outp(" Failed to save data at the memcached server!<br>\n");
+ return $false;
+ }
+ return $true;
+ }
+
+ function flushmemcache($key=false, $host, $port, $debug=false)
+ {
+ if (!function_exists('memcache_pconnect')) {
+ if ($debug) ADOConnection::outp(" Memcache module PECL extension not found!<br>\n");
+ return;
+ }
+
+ $memcache = new Memcache;
+ if (!@$memcache->pconnect($host, $port)) {
+ if ($debug) ADOConnection::outp(" Can't connect to memcache server on: $host:$port<br>\n");
+ return;
+ }
+
+ if ($key) {
+ if (!$memcache->delete($key)) {
+ if ($debug) ADOConnection::outp("CacheFlush: $key entery doesn't exist on memcached server!<br>\n");
+ } else {
+ if ($debug) ADOConnection::outp("CacheFlush: $key entery flushed from memcached server!<br>\n");
+ }
+ } else {
+ if (!$memcache->flush()) {
+ if ($debug) ADOConnection::outp("CacheFlush: Failure flushing all enteries from memcached server!<br>\n");
+ } else {
+ if ($debug) ADOConnection::outp("CacheFlush: All enteries flushed from memcached server!<br>\n");
+ }
+ }
+ return;
+ }
+?>
diff --git a/lib/adodb/adodb-pager.inc.php b/lib/adodb/adodb-pager.inc.php
new file mode 100644
index 0000000..22321b2
--- /dev/null
+++ b/lib/adodb/adodb-pager.inc.php
@@ -0,0 +1,290 @@
+<?php
+
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+ This class provides recordset pagination with
+ First/Prev/Next/Last links.
+
+ Feel free to modify this class for your own use as
+ it is very basic. To learn how to use it, see the
+ example in adodb/tests/testpaging.php.
+
+ "Pablo Costa" <pablo@cbsp.com.br> implemented Render_PageLinks().
+
+ Please note, this class is entirely unsupported,
+ and no free support requests except for bug reports
+ will be entertained by the author.
+
+*/
+class ADODB_Pager {
+ var $id; // unique id for pager (defaults to 'adodb')
+ var $db; // ADODB connection object
+ var $sql; // sql used
+ var $rs; // recordset generated
+ var $curr_page; // current page number before Render() called, calculated in constructor
+ var $rows; // number of rows per page
+ var $linksPerPage=10; // number of links per page in navigation bar
+ var $showPageLinks;
+
+ var $gridAttributes = 'width=100% border=1 bgcolor=white';
+
+ // Localize text strings here
+ var $first = '<code>|&lt;</code>';
+ var $prev = '<code>&lt;&lt;</code>';
+ var $next = '<code>>></code>';
+ var $last = '<code>>|</code>';
+ var $moreLinks = '...';
+ var $startLinks = '...';
+ var $gridHeader = false;
+ var $htmlSpecialChars = true;
+ var $page = 'Page';
+ var $linkSelectedColor = 'red';
+ var $cache = 0; #secs to cache with CachePageExecute()
+
+ //----------------------------------------------
+ // constructor
+ //
+ // $db adodb connection object
+ // $sql sql statement
+ // $id optional id to identify which pager,
+ // if you have multiple on 1 page.
+ // $id should be only be [a-z0-9]*
+ //
+ function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)
+ {
+ global $PHP_SELF;
+
+ $curr_page = $id.'_curr_page';
+ if (empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks
+
+ $this->sql = $sql;
+ $this->id = $id;
+ $this->db = $db;
+ $this->showPageLinks = $showPageLinks;
+
+ $next_page = $id.'_next_page';
+
+ if (isset($_GET[$next_page])) {
+ $_SESSION[$curr_page] = (integer) $_GET[$next_page];
+ }
+ if (empty($_SESSION[$curr_page])) $_SESSION[$curr_page] = 1; ## at first page
+
+ $this->curr_page = $_SESSION[$curr_page];
+
+ }
+
+ //---------------------------
+ // Display link to first page
+ function Render_First($anchor=true)
+ {
+ global $PHP_SELF;
+ if ($anchor) {
+ ?>
+ <a href="<?php echo $PHP_SELF,'?',$this->id;?>_next_page=1"><?php echo $this->first;?></a> &nbsp;
+ <?php
+ } else {
+ print "$this->first &nbsp; ";
+ }
+ }
+
+ //--------------------------
+ // Display link to next page
+ function render_next($anchor=true)
+ {
+ global $PHP_SELF;
+
+ if ($anchor) {
+ ?>
+ <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() + 1 ?>"><?php echo $this->next;?></a> &nbsp;
+ <?php
+ } else {
+ print "$this->next &nbsp; ";
+ }
+ }
+
+ //------------------
+ // Link to last page
+ //
+ // for better performance with large recordsets, you can set
+ // $this->db->pageExecuteCountRows = false, which disables
+ // last page counting.
+ function render_last($anchor=true)
+ {
+ global $PHP_SELF;
+
+ if (!$this->db->pageExecuteCountRows) return;
+
+ if ($anchor) {
+ ?>
+ <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->LastPageNo() ?>"><?php echo $this->last;?></a> &nbsp;
+ <?php
+ } else {
+ print "$this->last &nbsp; ";
+ }
+ }
+
+ //---------------------------------------------------
+ // original code by "Pablo Costa" <pablo@cbsp.com.br>
+ function render_pagelinks()
+ {
+ global $PHP_SELF;
+ $pages = $this->rs->LastPageNo();
+ $linksperpage = $this->linksPerPage ? $this->linksPerPage : $pages;
+ for($i=1; $i <= $pages; $i+=$linksperpage)
+ {
+ if($this->rs->AbsolutePage() >= $i)
+ {
+ $start = $i;
+ }
+ }
+ $numbers = '';
+ $end = $start+$linksperpage-1;
+ $link = $this->id . "_next_page";
+ if($end > $pages) $end = $pages;
+
+
+ if ($this->startLinks && $start > 1) {
+ $pos = $start - 1;
+ $numbers .= "<a href=$PHP_SELF?$link=$pos>$this->startLinks</a> ";
+ }
+
+ for($i=$start; $i <= $end; $i++) {
+ if ($this->rs->AbsolutePage() == $i)
+ $numbers .= "<font color=$this->linkSelectedColor><b>$i</b></font> ";
+ else
+ $numbers .= "<a href=$PHP_SELF?$link=$i>$i</a> ";
+
+ }
+ if ($this->moreLinks && $end < $pages)
+ $numbers .= "<a href=$PHP_SELF?$link=$i>$this->moreLinks</a> ";
+ print $numbers . ' &nbsp; ';
+ }
+ // Link to previous page
+ function render_prev($anchor=true)
+ {
+ global $PHP_SELF;
+ if ($anchor) {
+ ?>
+ <a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>"><?php echo $this->prev;?></a> &nbsp;
+ <?php
+ } else {
+ print "$this->prev &nbsp; ";
+ }
+ }
+
+ //--------------------------------------------------------
+ // Simply rendering of grid. You should override this for
+ // better control over the format of the grid
+ //
+ // We use output buffering to keep code clean and readable.
+ function RenderGrid()
+ {
+ global $gSQLBlockRows; // used by rs2html to indicate how many rows to display
+ include_once(ADODB_DIR.'/tohtml.inc.php');
+ ob_start();
+ $gSQLBlockRows = $this->rows;
+ rs2html($this->rs,$this->gridAttributes,$this->gridHeader,$this->htmlSpecialChars);
+ $s = ob_get_contents();
+ ob_end_clean();
+ return $s;
+ }
+
+ //-------------------------------------------------------
+ // Navigation bar
+ //
+ // we use output buffering to keep the code easy to read.
+ function RenderNav()
+ {
+ ob_start();
+ if (!$this->rs->AtFirstPage()) {
+ $this->Render_First();
+ $this->Render_Prev();
+ } else {
+ $this->Render_First(false);
+ $this->Render_Prev(false);
+ }
+ if ($this->showPageLinks){
+ $this->Render_PageLinks();
+ }
+ if (!$this->rs->AtLastPage()) {
+ $this->Render_Next();
+ $this->Render_Last();
+ } else {
+ $this->Render_Next(false);
+ $this->Render_Last(false);
+ }
+ $s = ob_get_contents();
+ ob_end_clean();
+ return $s;
+ }
+
+ //-------------------
+ // This is the footer
+ function RenderPageCount()
+ {
+ if (!$this->db->pageExecuteCountRows) return '';
+ $lastPage = $this->rs->LastPageNo();
+ if ($lastPage == -1) $lastPage = 1; // check for empty rs.
+ if ($this->curr_page > $lastPage) $this->curr_page = 1;
+ return "<font size=-1>$this->page ".$this->curr_page."/".$lastPage."</font>";
+ }
+
+ //-----------------------------------
+ // Call this class to draw everything.
+ function Render($rows=10)
+ {
+ global $ADODB_COUNTRECS;
+
+ $this->rows = $rows;
+
+ if ($this->db->dataProvider == 'informix') $this->db->cursorType = IFX_SCROLL;
+
+ $savec = $ADODB_COUNTRECS;
+ if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;
+ if ($this->cache)
+ $rs = &$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
+ else
+ $rs = &$this->db->PageExecute($this->sql,$rows,$this->curr_page);
+ $ADODB_COUNTRECS = $savec;
+
+ $this->rs = &$rs;
+ if (!$rs) {
+ print "<h3>Query failed: $this->sql</h3>";
+ return;
+ }
+
+ if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage()))
+ $header = $this->RenderNav();
+ else
+ $header = "&nbsp;";
+
+ $grid = $this->RenderGrid();
+ $footer = $this->RenderPageCount();
+
+ $this->RenderLayout($header,$grid,$footer);
+
+ $rs->Close();
+ $this->rs = false;
+ }
+
+ //------------------------------------------------------
+ // override this to control overall layout and formating
+ function RenderLayout($header,$grid,$footer,$attributes='border=1 bgcolor=beige')
+ {
+ echo "<table ".$attributes."><tr><td>",
+ $header,
+ "</td></tr><tr><td>",
+ $grid,
+ "</td></tr><tr><td>",
+ $footer,
+ "</td></tr></table>";
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-pear.inc.php b/lib/adodb/adodb-pear.inc.php
new file mode 100644
index 0000000..ecaf753
--- /dev/null
+++ b/lib/adodb/adodb-pear.inc.php
@@ -0,0 +1,374 @@
+<?php
+/**
+ * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * PEAR DB Emulation Layer for ADODB.
+ *
+ * The following code is modelled on PEAR DB code by Stig Bakken <ssb@fast.no> |
+ * and Tomas V.V.Cox <cox@idecnet.com>. Portions (c)1997-2002 The PHP Group.
+ */
+
+ /*
+ We support:
+
+ DB_Common
+ ---------
+ query - returns PEAR_Error on error
+ limitQuery - return PEAR_Error on error
+ prepare - does not return PEAR_Error on error
+ execute - does not return PEAR_Error on error
+ setFetchMode - supports ASSOC and ORDERED
+ errorNative
+ quote
+ nextID
+ disconnect
+
+ getOne
+ getAssoc
+ getRow
+ getCol
+ getAll
+
+ DB_Result
+ ---------
+ numRows - returns -1 if not supported
+ numCols
+ fetchInto - does not support passing of fetchmode
+ fetchRows - does not support passing of fetchmode
+ free
+ */
+
+define('ADODB_PEAR',dirname(__FILE__));
+include_once "PEAR.php";
+include_once ADODB_PEAR."/adodb-errorpear.inc.php";
+include_once ADODB_PEAR."/adodb.inc.php";
+
+if (!defined('DB_OK')) {
+define("DB_OK", 1);
+define("DB_ERROR",-1);
+
+// autoExecute constants
+define('DB_AUTOQUERY_INSERT', 1);
+define('DB_AUTOQUERY_UPDATE', 2);
+
+/**
+ * This is a special constant that tells DB the user hasn't specified
+ * any particular get mode, so the default should be used.
+ */
+
+define('DB_FETCHMODE_DEFAULT', 0);
+
+/**
+ * Column data indexed by numbers, ordered from 0 and up
+ */
+
+define('DB_FETCHMODE_ORDERED', 1);
+
+/**
+ * Column data indexed by column names
+ */
+
+define('DB_FETCHMODE_ASSOC', 2);
+
+/* for compatibility */
+
+define('DB_GETMODE_ORDERED', DB_FETCHMODE_ORDERED);
+define('DB_GETMODE_ASSOC', DB_FETCHMODE_ASSOC);
+
+/**
+ * these are constants for the tableInfo-function
+ * they are bitwised or'ed. so if there are more constants to be defined
+ * in the future, adjust DB_TABLEINFO_FULL accordingly
+ */
+
+define('DB_TABLEINFO_ORDER', 1);
+define('DB_TABLEINFO_ORDERTABLE', 2);
+define('DB_TABLEINFO_FULL', 3);
+}
+
+/**
+ * The main "DB" class is simply a container class with some static
+ * methods for creating DB objects as well as some utility functions
+ * common to all parts of DB.
+ *
+ */
+
+class DB
+{
+ /**
+ * Create a new DB object for the specified database type
+ *
+ * @param $type string database type, for example "mysql"
+ *
+ * @return object a newly created DB object, or a DB error code on
+ * error
+ */
+
+ function &factory($type)
+ {
+ include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");
+ $obj = &NewADOConnection($type);
+ if (!is_object($obj)) $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+ return $obj;
+ }
+
+ /**
+ * Create a new DB object and connect to the specified database
+ *
+ * @param $dsn mixed "data source name", see the DB::parseDSN
+ * method for a description of the dsn format. Can also be
+ * specified as an array of the format returned by DB::parseDSN.
+ *
+ * @param $options mixed if boolean (or scalar), tells whether
+ * this connection should be persistent (for backends that support
+ * this). This parameter can also be an array of options, see
+ * DB_common::setOption for more information on connection
+ * options.
+ *
+ * @return object a newly created DB connection object, or a DB
+ * error object on error
+ *
+ * @see DB::parseDSN
+ * @see DB::isError
+ */
+ function &connect($dsn, $options = false)
+ {
+ if (is_array($dsn)) {
+ $dsninfo = $dsn;
+ } else {
+ $dsninfo = DB::parseDSN($dsn);
+ }
+ switch ($dsninfo["phptype"]) {
+ case 'pgsql': $type = 'postgres7'; break;
+ case 'ifx': $type = 'informix9'; break;
+ default: $type = $dsninfo["phptype"]; break;
+ }
+
+ if (is_array($options) && isset($options["debug"]) &&
+ $options["debug"] >= 2) {
+ // expose php errors with sufficient debug level
+ @include_once("adodb-$type.inc.php");
+ } else {
+ @include_once("adodb-$type.inc.php");
+ }
+
+ @$obj =& NewADOConnection($type);
+ if (!is_object($obj)) {
+ $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+ return $obj;
+ }
+ if (is_array($options)) {
+ foreach($options as $k => $v) {
+ switch(strtolower($k)) {
+ case 'persist':
+ case 'persistent': $persist = $v; break;
+ #ibase
+ case 'dialect': $obj->dialect = $v; break;
+ case 'charset': $obj->charset = $v; break;
+ case 'buffers': $obj->buffers = $v; break;
+ #ado
+ case 'charpage': $obj->charPage = $v; break;
+ #mysql
+ case 'clientflags': $obj->clientFlags = $v; break;
+ }
+ }
+ } else {
+ $persist = false;
+ }
+
+ if (isset($dsninfo['socket'])) $dsninfo['hostspec'] .= ':'.$dsninfo['socket'];
+ else if (isset($dsninfo['port'])) $dsninfo['hostspec'] .= ':'.$dsninfo['port'];
+
+ if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
+ else $ok = $obj->Connect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
+
+ if (!$ok) $obj = ADODB_PEAR_Error();
+ return $obj;
+ }
+
+ /**
+ * Return the DB API version
+ *
+ * @return int the DB API version number
+ */
+ function apiVersion()
+ {
+ return 2;
+ }
+
+ /**
+ * Tell whether a result code from a DB method is an error
+ *
+ * @param $value int result code
+ *
+ * @return bool whether $value is an error
+ */
+ function isError($value)
+ {
+ if (!is_object($value)) return false;
+ $class = get_class($value);
+ return $class == 'pear_error' || is_subclass_of($value, 'pear_error') ||
+ $class == 'db_error' || is_subclass_of($value, 'db_error');
+ }
+
+
+ /**
+ * Tell whether a result code from a DB method is a warning.
+ * Warnings differ from errors in that they are generated by DB,
+ * and are not fatal.
+ *
+ * @param $value mixed result value
+ *
+ * @return bool whether $value is a warning
+ */
+ function isWarning($value)
+ {
+ return false;
+ /*
+ return is_object($value) &&
+ (get_class( $value ) == "db_warning" ||
+ is_subclass_of($value, "db_warning"));*/
+ }
+
+ /**
+ * Parse a data source name
+ *
+ * @param $dsn string Data Source Name to be parsed
+ *
+ * @return array an associative array with the following keys:
+ *
+ * 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
+ *
+ * The format of the supplied DSN is in its fullest form:
+ *
+ * phptype(dbsyntax)://username:password@protocol+hostspec/database
+ *
+ * Most variations are allowed:
+ *
+ * phptype://username:password@protocol+hostspec:110//usr/db_file.db
+ * phptype://username:password@hostspec/database_name
+ * phptype://username:password@hostspec
+ * phptype://username@hostspec
+ * phptype://hostspec/database
+ * phptype://hostspec
+ * phptype(dbsyntax)
+ * phptype
+ *
+ * @author Tomas V.V.Cox <cox@idecnet.com>
+ */
+ function parseDSN($dsn)
+ {
+ if (is_array($dsn)) {
+ return $dsn;
+ }
+
+ $parsed = array(
+ 'phptype' => false,
+ 'dbsyntax' => false,
+ 'protocol' => false,
+ 'hostspec' => false,
+ 'database' => false,
+ 'username' => false,
+ 'password' => false
+ );
+
+ // Find phptype and dbsyntax
+ if (($pos = strpos($dsn, '://')) !== false) {
+ $str = substr($dsn, 0, $pos);
+ $dsn = substr($dsn, $pos + 3);
+ } else {
+ $str = $dsn;
+ $dsn = NULL;
+ }
+
+ // Get phptype and dbsyntax
+ // $str => phptype(dbsyntax)
+ if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) {
+ $parsed['phptype'] = $arr[1];
+ $parsed['dbsyntax'] = (empty($arr[2])) ? $arr[1] : $arr[2];
+ } else {
+ $parsed['phptype'] = $str;
+ $parsed['dbsyntax'] = $str;
+ }
+
+ if (empty($dsn)) {
+ return $parsed;
+ }
+
+ // Get (if found): username and password
+ // $dsn => username:password@protocol+hostspec/database
+ if (($at = strpos($dsn,'@')) !== false) {
+ $str = substr($dsn, 0, $at);
+ $dsn = substr($dsn, $at + 1);
+ if (($pos = strpos($str, ':')) !== false) {
+ $parsed['username'] = urldecode(substr($str, 0, $pos));
+ $parsed['password'] = urldecode(substr($str, $pos + 1));
+ } else {
+ $parsed['username'] = urldecode($str);
+ }
+ }
+
+ // Find protocol and hostspec
+ // $dsn => protocol+hostspec/database
+ if (($pos=strpos($dsn, '/')) !== false) {
+ $str = substr($dsn, 0, $pos);
+ $dsn = substr($dsn, $pos + 1);
+ } else {
+ $str = $dsn;
+ $dsn = NULL;
+ }
+
+ // Get protocol + hostspec
+ // $str => protocol+hostspec
+ if (($pos=strpos($str, '+')) !== false) {
+ $parsed['protocol'] = substr($str, 0, $pos);
+ $parsed['hostspec'] = urldecode(substr($str, $pos + 1));
+ } else {
+ $parsed['hostspec'] = urldecode($str);
+ }
+
+ // Get dabase if any
+ // $dsn => database
+ if (!empty($dsn)) {
+ $parsed['database'] = $dsn;
+ }
+
+ return $parsed;
+ }
+
+ /**
+ * Load a PHP database extension if it is not loaded already.
+ *
+ * @access public
+ *
+ * @param $name the base name of the extension (without the .so or
+ * .dll suffix)
+ *
+ * @return bool true if the extension was already or successfully
+ * loaded, false if it could not be loaded
+ */
+ function assertExtension($name)
+ {
+ if (!extension_loaded($name)) {
+ $dlext = (strncmp(PHP_OS,'WIN',3) === 0) ? '.dll' : '.so';
+ @dl($name . $dlext);
+ }
+ if (!extension_loaded($name)) {
+ return false;
+ }
+ return true;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-perf.inc.php b/lib/adodb/adodb-perf.inc.php
new file mode 100644
index 0000000..e00359f
--- /dev/null
+++ b/lib/adodb/adodb-perf.inc.php
@@ -0,0 +1,1068 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Library for basic performance monitoring and tuning.
+
+ My apologies if you see code mixed with presentation. The presentation suits
+ my needs. If you want to separate code from presentation, be my guest. Patches
+ are welcome.
+
+*/
+
+if (!defined('ADODB_DIR')) include_once(dirname(__FILE__).'/adodb.inc.php');
+include_once(ADODB_DIR.'/tohtml.inc.php');
+
+define( 'ADODB_OPT_HIGH', 2);
+define( 'ADODB_OPT_LOW', 1);
+
+// returns in K the memory of current process, or 0 if not known
+function adodb_getmem()
+{
+ if (function_exists('memory_get_usage'))
+ return (integer) ((memory_get_usage()+512)/1024);
+
+ $pid = getmypid();
+
+ if ( strncmp(strtoupper(PHP_OS),'WIN',3)==0) {
+ $output = array();
+
+ exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output);
+ return substr($output[5], strpos($output[5], ':') + 1);
+ }
+
+ /* Hopefully UNIX */
+ exec("ps --pid $pid --no-headers -o%mem,size", $output);
+ if (sizeof($output) == 0) return 0;
+
+ $memarr = explode(' ',$output[0]);
+ if (sizeof($memarr)>=2) return (integer) $memarr[1];
+
+ return 0;
+}
+
+// avoids localization problems where , is used instead of .
+function adodb_round($n,$prec)
+{
+ return number_format($n, $prec, '.', '');
+}
+
+/* return microtime value as a float */
+function adodb_microtime()
+{
+ $t = microtime();
+ $t = explode(' ',$t);
+ return (float)$t[1]+ (float)$t[0];
+}
+
+/* sql code timing */
+function& adodb_log_sql(&$connx,$sql,$inputarr)
+{
+ $perf_table = adodb_perf::table();
+ $connx->fnExecute = false;
+ $t0 = microtime();
+ $rs =& $connx->Execute($sql,$inputarr);
+ $t1 = microtime();
+
+ if (!empty($connx->_logsql) && (empty($connx->_logsqlErrors) || !$rs)) {
+ global $ADODB_LOG_CONN;
+
+ if (!empty($ADODB_LOG_CONN)) {
+ $conn = &$ADODB_LOG_CONN;
+ if ($conn->databaseType != $connx->databaseType)
+ $prefix = '/*dbx='.$connx->databaseType .'*/ ';
+ else
+ $prefix = '';
+ } else {
+ $conn =& $connx;
+ $prefix = '';
+ }
+
+ $conn->_logsql = false; // disable logsql error simulation
+ $dbT = $conn->databaseType;
+
+ $a0 = split(' ',$t0);
+ $a0 = (float)$a0[1]+(float)$a0[0];
+
+ $a1 = split(' ',$t1);
+ $a1 = (float)$a1[1]+(float)$a1[0];
+
+ $time = $a1 - $a0;
+
+ if (!$rs) {
+ $errM = $connx->ErrorMsg();
+ $errN = $connx->ErrorNo();
+ $conn->lastInsID = 0;
+ $tracer = substr('ERROR: '.htmlspecialchars($errM),0,250);
+ } else {
+ $tracer = '';
+ $errM = '';
+ $errN = 0;
+ $dbg = $conn->debug;
+ $conn->debug = false;
+ if (!is_object($rs) || $rs->dataProvider == 'empty')
+ $conn->_affected = $conn->affected_rows(true);
+ $conn->lastInsID = @$conn->Insert_ID();
+ $conn->debug = $dbg;
+ }
+ if (isset($_SERVER['HTTP_HOST'])) {
+ $tracer .= '<br>'.$_SERVER['HTTP_HOST'];
+ if (isset($_SERVER['PHP_SELF'])) $tracer .= $_SERVER['PHP_SELF'];
+ } else
+ if (isset($_SERVER['PHP_SELF'])) $tracer .= '<br>'.$_SERVER['PHP_SELF'];
+ //$tracer .= (string) adodb_backtrace(false);
+
+ $tracer = (string) substr($tracer,0,500);
+
+ if (is_array($inputarr)) {
+ if (is_array(reset($inputarr))) $params = 'Array sizeof='.sizeof($inputarr);
+ else {
+ // Quote string parameters so we can see them in the
+ // performance stats. This helps spot disabled indexes.
+ $xar_params = $inputarr;
+ foreach ($xar_params as $xar_param_key => $xar_param) {
+ if (gettype($xar_param) == 'string')
+ $xar_params[$xar_param_key] = '"' . $xar_param . '"';
+ }
+ $params = implode(', ', $xar_params);
+ if (strlen($params) >= 3000) $params = substr($params, 0, 3000);
+ }
+ } else {
+ $params = '';
+ }
+
+ if (is_array($sql)) $sql = $sql[0];
+ if ($prefix) $sql = $prefix.$sql;
+ $arr = array('b'=>strlen($sql).'.'.crc32($sql),
+ 'c'=>substr($sql,0,3900), 'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6));
+ //var_dump($arr);
+ $saved = $conn->debug;
+ $conn->debug = 0;
+
+ $d = $conn->sysTimeStamp;
+ if (empty($d)) $d = date("'Y-m-d H:i:s'");
+ if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') {
+ $isql = "insert into $perf_table values($d,:b,:c,:d,:e,:f)";
+ } else if ($dbT == 'odbc_mssql' || $dbT == 'informix' || strncmp($dbT,'odbtp',4)==0) {
+ $timer = $arr['f'];
+ if ($dbT == 'informix') $sql2 = substr($sql2,0,230);
+
+ $sql1 = $conn->qstr($arr['b']);
+ $sql2 = $conn->qstr($arr['c']);
+ $params = $conn->qstr($arr['d']);
+ $tracer = $conn->qstr($arr['e']);
+
+ $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values($d,$sql1,$sql2,$params,$tracer,$timer)";
+ if ($dbT == 'informix') $isql = str_replace(chr(10),' ',$isql);
+ $arr = false;
+ } else {
+ if ($dbT == 'db2') $arr['f'] = (float) $arr['f'];
+ $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)";
+ }
+ $ok = $conn->Execute($isql,$arr);
+ $conn->debug = $saved;
+
+ if ($ok) {
+ $conn->_logsql = true;
+ } else {
+ $err2 = $conn->ErrorMsg();
+ $conn->_logsql = true; // enable logsql error simulation
+ $perf =& NewPerfMonitor($conn);
+ if ($perf) {
+ if ($perf->CreateLogTable()) $ok = $conn->Execute($isql,$arr);
+ } else {
+ $ok = $conn->Execute("create table $perf_table (
+ created varchar(50),
+ sql0 varchar(250),
+ sql1 varchar(4000),
+ params varchar(3000),
+ tracer varchar(500),
+ timer decimal(16,6))");
+ }
+ if (!$ok) {
+ ADOConnection::outp( "<p><b>LOGSQL Insert Failed</b>: $isql<br>$err2</p>");
+ $conn->_logsql = false;
+ }
+ }
+ $connx->_errorMsg = $errM;
+ $connx->_errorCode = $errN;
+ }
+ $connx->fnExecute = 'adodb_log_sql';
+ return $rs;
+}
+
+
+/*
+The settings data structure is an associative array that database parameter per element.
+
+Each database parameter element in the array is itself an array consisting of:
+
+0: category code, used to group related db parameters
+1: either
+ a. sql string to retrieve value, eg. "select value from v\$parameter where name='db_block_size'",
+ b. array holding sql string and field to look for, e.g. array('show variables','table_cache'),
+ c. a string prefixed by =, then a PHP method of the class is invoked,
+ e.g. to invoke $this->GetIndexValue(), set this array element to '=GetIndexValue',
+2: description of the database parameter
+*/
+
+class adodb_perf {
+ var $conn;
+ var $color = '#F0F0F0';
+ var $table = '<table border=1 bgcolor=white>';
+ var $titles = '<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Description</b></td></tr>';
+ var $warnRatio = 90;
+ var $tablesSQL = false;
+ var $cliFormat = "%32s => %s \r\n";
+ var $sql1 = 'sql1'; // used for casting sql1 to text for mssql
+ var $explain = true;
+ var $helpurl = "<a href=http://phplens.com/adodb/reference.functions.fnexecute.and.fncacheexecute.properties.html#logsql>LogSQL help</a>";
+ var $createTableSQL = false;
+ var $maxLength = 2000;
+
+ // Sets the tablename to be used
+ function table($newtable = false)
+ {
+ static $_table;
+
+ if (!empty($newtable)) $_table = $newtable;
+ if (empty($_table)) $_table = 'adodb_logsql';
+ return $_table;
+ }
+
+ // returns array with info to calculate CPU Load
+ function _CPULoad()
+ {
+/*
+
+cpu 524152 2662 2515228 336057010
+cpu0 264339 1408 1257951 168025827
+cpu1 259813 1254 1257277 168031181
+page 622307 25475680
+swap 24 1891
+intr 890153570 868093576 6 0 4 4 0 6 1 2 0 0 0 124 0 8098760 2 13961053 0 0 0 0 0 0 0 0 0 0 0 0 0 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+disk_io: (3,0):(3144904,54369,610378,3090535,50936192) (3,1):(3630212,54097,633016,3576115,50951320)
+ctxt 66155838
+btime 1062315585
+processes 69293
+
+*/
+ // Algorithm is taken from
+ // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/example__obtaining_raw_performance_data.asp
+ if (strncmp(PHP_OS,'WIN',3)==0) {
+ if (PHP_VERSION == '5.0.0') return false;
+ if (PHP_VERSION == '5.0.1') return false;
+ if (PHP_VERSION == '5.0.2') return false;
+ if (PHP_VERSION == '5.0.3') return false;
+ if (PHP_VERSION == '4.3.10') return false; # see http://bugs.php.net/bug.php?id=31737
+
+ @$c = new COM("WinMgmts:{impersonationLevel=impersonate}!Win32_PerfRawData_PerfOS_Processor.Name='_Total'");
+ if (!$c) return false;
+
+ $info[0] = $c->PercentProcessorTime;
+ $info[1] = 0;
+ $info[2] = 0;
+ $info[3] = $c->TimeStamp_Sys100NS;
+ //print_r($info);
+ return $info;
+ }
+
+ // Algorithm - Steve Blinch (BlitzAffe Online, http://www.blitzaffe.com)
+ $statfile = '/proc/stat';
+ if (!file_exists($statfile)) return false;
+
+ $fd = fopen($statfile,"r");
+ if (!$fd) return false;
+
+ $statinfo = explode("\n",fgets($fd, 1024));
+ fclose($fd);
+ foreach($statinfo as $line) {
+ $info = explode(" ",$line);
+ if($info[0]=="cpu") {
+ array_shift($info); // pop off "cpu"
+ if(!$info[0]) array_shift($info); // pop off blank space (if any)
+ return $info;
+ }
+ }
+
+ return false;
+
+ }
+
+ /* NOT IMPLEMENTED */
+ function MemInfo()
+ {
+ /*
+
+ total: used: free: shared: buffers: cached:
+Mem: 1055289344 917299200 137990144 0 165437440 599773184
+Swap: 2146775040 11055104 2135719936
+MemTotal: 1030556 kB
+MemFree: 134756 kB
+MemShared: 0 kB
+Buffers: 161560 kB
+Cached: 581384 kB
+SwapCached: 4332 kB
+Active: 494468 kB
+Inact_dirty: 322856 kB
+Inact_clean: 24256 kB
+Inact_target: 168316 kB
+HighTotal: 131064 kB
+HighFree: 1024 kB
+LowTotal: 899492 kB
+LowFree: 133732 kB
+SwapTotal: 2096460 kB
+SwapFree: 2085664 kB
+Committed_AS: 348732 kB
+ */
+ }
+
+
+ /*
+ Remember that this is client load, not db server load!
+ */
+ var $_lastLoad;
+ function CPULoad()
+ {
+ $info = $this->_CPULoad();
+ if (!$info) return false;
+
+ if (empty($this->_lastLoad)) {
+ sleep(1);
+ $this->_lastLoad = $info;
+ $info = $this->_CPULoad();
+ }
+
+ $last = $this->_lastLoad;
+ $this->_lastLoad = $info;
+
+ $d_user = $info[0] - $last[0];
+ $d_nice = $info[1] - $last[1];
+ $d_system = $info[2] - $last[2];
+ $d_idle = $info[3] - $last[3];
+
+ //printf("Delta - User: %f Nice: %f System: %f Idle: %f<br>",$d_user,$d_nice,$d_system,$d_idle);
+
+ if (strncmp(PHP_OS,'WIN',3)==0) {
+ if ($d_idle < 1) $d_idle = 1;
+ return 100*(1-$d_user/$d_idle);
+ }else {
+ $total=$d_user+$d_nice+$d_system+$d_idle;
+ if ($total<1) $total=1;
+ return 100*($d_user+$d_nice+$d_system)/$total;
+ }
+ }
+
+ function Tracer($sql)
+ {
+ $perf_table = adodb_perf::table();
+ $saveE = $this->conn->fnExecute;
+ $this->conn->fnExecute = false;
+
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $sqlq = $this->conn->qstr($sql);
+ $arr = $this->conn->GetArray(
+"select count(*),tracer
+ from $perf_table where sql1=$sqlq
+ group by tracer
+ order by 1 desc");
+ $s = '';
+ if ($arr) {
+ $s .= '<h3>Scripts Affected</h3>';
+ foreach($arr as $k) {
+ $s .= sprintf("%4d",$k[0]).' &nbsp; '.strip_tags($k[1]).'<br>';
+ }
+ }
+
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_CACHE_MODE = $save;
+ $this->conn->fnExecute = $saveE;
+ return $s;
+ }
+
+ /*
+ Explain Plan for $sql.
+ If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the
+ actual sql.
+ */
+ function Explain($sql,$partial=false)
+ {
+ return false;
+ }
+
+ function InvalidSQL($numsql = 10)
+ {
+
+ if (isset($_GET['sql'])) return;
+ $s = '<h3>Invalid SQL</h3>';
+ $saveE = $this->conn->fnExecute;
+ $this->conn->fnExecute = false;
+ $perf_table = adodb_perf::table();
+ $rs =& $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
+ $this->conn->fnExecute = $saveE;
+ if ($rs) {
+ $s .= rs2html($rs,false,false,false,false);
+ } else
+ return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
+
+ return $s;
+ }
+
+
+ /*
+ This script identifies the longest running SQL
+ */
+ function _SuspiciousSQL($numsql = 10)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $perf_table = adodb_perf::table();
+ $saveE = $this->conn->fnExecute;
+ $this->conn->fnExecute = false;
+
+ if (isset($_GET['exps']) && isset($_GET['sql'])) {
+ $partial = !empty($_GET['part']);
+ echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
+ }
+
+ if (isset($_GET['sql'])) return;
+ $sql1 = $this->sql1;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+ //$this->conn->debug=1;
+ $rs =& $this->conn->SelectLimit(
+ "select avg(timer) as avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
+ from $perf_table
+ where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
+ and (tracer is null or tracer not like 'ERROR:%')
+ group by sql1
+ order by 1 desc",$numsql);
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ $this->conn->fnExecute = $saveE;
+
+ if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
+ $s = "<h3>Suspicious SQL</h3>
+<font size=1>The following SQL have high average execution times</font><br>
+<table border=1 bgcolor=white><tr><td><b>Avg Time</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
+ $max = $this->maxLength;
+ while (!$rs->EOF) {
+ $sql = $rs->fields[1];
+ $raw = urlencode($sql);
+ if (strlen($raw)>$max-100) {
+ $sql2 = substr($sql,0,$max-500);
+ $raw = urlencode($sql2).'&part='.crc32($sql);
+ }
+ $prefix = "<a target=sql".rand()." href=\"?hidem=1&exps=1&sql=".$raw."&x#explain\">";
+ $suffix = "</a>";
+ if ($this->explain == false || strlen($prefix)>$max) {
+ $suffix = ' ... <i>String too long for GET parameter: '.strlen($prefix).'</i>';
+ $prefix = '';
+ }
+ $s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
+ "<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
+ $rs->MoveNext();
+ }
+ return $s."</table>";
+
+ }
+
+ function CheckMemory()
+ {
+ return '';
+ }
+
+
+ function SuspiciousSQL($numsql=10)
+ {
+ return adodb_perf::_SuspiciousSQL($numsql);
+ }
+
+ function ExpensiveSQL($numsql=10)
+ {
+ return adodb_perf::_ExpensiveSQL($numsql);
+ }
+
+
+ /*
+ This reports the percentage of load on the instance due to the most
+ expensive few SQL statements. Tuning these statements can often
+ make huge improvements in overall system performance.
+ */
+ function _ExpensiveSQL($numsql = 10)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $perf_table = adodb_perf::table();
+ $saveE = $this->conn->fnExecute;
+ $this->conn->fnExecute = false;
+
+ if (isset($_GET['expe']) && isset($_GET['sql'])) {
+ $partial = !empty($_GET['part']);
+ echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
+ }
+
+ if (isset($_GET['sql'])) return;
+
+ $sql1 = $this->sql1;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $rs =& $this->conn->SelectLimit(
+ "select sum(timer) as total,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
+ from $perf_table
+ where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
+ and (tracer is null or tracer not like 'ERROR:%')
+ group by sql1
+ having count(*)>1
+ order by 1 desc",$numsql);
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $this->conn->fnExecute = $saveE;
+ $ADODB_FETCH_MODE = $save;
+ if (!$rs) return "<p>$this->helpurl. ".$this->conn->ErrorMsg()."</p>";
+ $s = "<h3>Expensive SQL</h3>
+<font size=1>Tuning the following SQL could reduce the server load substantially</font><br>
+<table border=1 bgcolor=white><tr><td><b>Load</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
+ $max = $this->maxLength;
+ while (!$rs->EOF) {
+ $sql = $rs->fields[1];
+ $raw = urlencode($sql);
+ if (strlen($raw)>$max-100) {
+ $sql2 = substr($sql,0,$max-500);
+ $raw = urlencode($sql2).'&part='.crc32($sql);
+ }
+ $prefix = "<a target=sqle".rand()." href=\"?hidem=1&expe=1&sql=".$raw."&x#explain\">";
+ $suffix = "</a>";
+ if($this->explain == false || strlen($prefix>$max)) {
+ $prefix = '';
+ $suffix = '';
+ }
+ $s .= "<tr><td>".adodb_round($rs->fields[0],6)."<td align=right>".$rs->fields[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
+ "<td>".$rs->fields[3]."<td>".$rs->fields[4]."</tr>";
+ $rs->MoveNext();
+ }
+ return $s."</table>";
+ }
+
+ /*
+ Raw function to return parameter value from $settings.
+ */
+ function DBParameter($param)
+ {
+ if (empty($this->settings[$param])) return false;
+ $sql = $this->settings[$param][1];
+ return $this->_DBParameter($sql);
+ }
+
+ /*
+ Raw function returning array of poll paramters
+ */
+ function &PollParameters()
+ {
+ $arr[0] = (float)$this->DBParameter('data cache hit ratio');
+ $arr[1] = (float)$this->DBParameter('data reads');
+ $arr[2] = (float)$this->DBParameter('data writes');
+ $arr[3] = (integer) $this->DBParameter('current connections');
+ return $arr;
+ }
+
+ /*
+ Low-level Get Database Parameter
+ */
+ function _DBParameter($sql)
+ {
+ $savelog = $this->conn->LogSQL(false);
+ if (is_array($sql)) {
+ global $ADODB_FETCH_MODE;
+
+ $sql1 = $sql[0];
+ $key = $sql[1];
+ if (sizeof($sql)>2) $pos = $sql[2];
+ else $pos = 1;
+ if (sizeof($sql)>3) $coef = $sql[3];
+ else $coef = false;
+ $ret = false;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $rs = $this->conn->Execute($sql1);
+
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ if ($rs) {
+ while (!$rs->EOF) {
+ $keyf = reset($rs->fields);
+ if (trim($keyf) == $key) {
+ $ret = $rs->fields[$pos];
+ if ($coef) $ret *= $coef;
+ break;
+ }
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ }
+ $this->conn->LogSQL($savelog);
+ return $ret;
+ } else {
+ if (strncmp($sql,'=',1) == 0) {
+ $fn = substr($sql,1);
+ return $this->$fn();
+ }
+ $sql = str_replace('$DATABASE',$this->conn->database,$sql);
+ $ret = $this->conn->GetOne($sql);
+ $this->conn->LogSQL($savelog);
+
+ return $ret;
+ }
+ }
+
+ /*
+ Warn if cache ratio falls below threshold. Displayed in "Description" column.
+ */
+ function WarnCacheRatio($val)
+ {
+ if ($val < $this->warnRatio)
+ return '<font color=red><b>Cache ratio should be at least '.$this->warnRatio.'%</b></font>';
+ else return '';
+ }
+
+ /***********************************************************************************************/
+ // HIGH LEVEL UI FUNCTIONS
+ /***********************************************************************************************/
+
+
+ function UI($pollsecs=5)
+ {
+
+ $perf_table = adodb_perf::table();
+ $conn = $this->conn;
+
+ $app = $conn->host;
+ if ($conn->host && $conn->database) $app .= ', db=';
+ $app .= $conn->database;
+
+ if ($app) $app .= ', ';
+ $savelog = $this->conn->LogSQL(false);
+ $info = $conn->ServerInfo();
+ if (isset($_GET['clearsql'])) {
+ $this->conn->Execute("delete from $perf_table");
+ }
+ $this->conn->LogSQL($savelog);
+
+ // magic quotes
+
+ if (isset($_GET['sql']) && get_magic_quotes_gpc()) {
+ $_GET['sql'] = $_GET['sql'] = str_replace(array("\\'",'\"'),array("'",'"'),$_GET['sql']);
+ }
+
+ if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = $_SESSION['ADODB_PERF_SQL'] = 10;
+ else $nsql = $_SESSION['ADODB_PERF_SQL'];
+
+ $app .= $info['description'];
+
+
+ if (isset($_GET['do'])) $do = $_GET['do'];
+ else if (isset($_POST['do'])) $do = $_POST['do'];
+ else if (isset($_GET['sql'])) $do = 'viewsql';
+ else $do = 'stats';
+
+ if (isset($_GET['nsql'])) {
+ if ($_GET['nsql'] > 0) $nsql = $_SESSION['ADODB_PERF_SQL'] = (integer) $_GET['nsql'];
+ }
+ echo "<title>ADOdb Performance Monitor on $app</title><body bgcolor=white>";
+ if ($do == 'viewsql') $form = "<td><form># SQL:<input type=hidden value=viewsql name=do> <input type=text size=4 name=nsql value=$nsql><input type=submit value=Go></td></form>";
+ else $form = "<td>&nbsp;</td>";
+
+ $allowsql = !defined('ADODB_PERF_NO_RUN_SQL');
+
+ if (empty($_GET['hidem']))
+ echo "<table border=1 width=100% bgcolor=lightyellow><tr><td colspan=2>
+ <b><a href=http://adodb.sourceforge.net/?perf=1>ADOdb</a> Performance Monitor</b> <font size=1>for $app</font></tr><tr><td>
+ <a href=?do=stats><b>Performance Stats</b></a> &nbsp; <a href=?do=viewsql><b>View SQL</b></a>
+ &nbsp; <a href=?do=tables><b>View Tables</b></a> &nbsp; <a href=?do=poll><b>Poll Stats</b></a>",
+ $allowsql ? ' &nbsp; <a href=?do=dosql><b>Run SQL</b></a>' : '',
+ "$form",
+ "</tr></table>";
+
+
+ switch ($do) {
+ default:
+ case 'stats':
+ echo $this->HealthCheck();
+ //$this->conn->debug=1;
+ echo $this->CheckMemory();
+ break;
+ case 'poll':
+ echo "<iframe width=720 height=80%
+ src=\"{$_SERVER['PHP_SELF']}?do=poll2&hidem=1\"></iframe>";
+ break;
+ case 'poll2':
+ echo "<pre>";
+ $this->Poll($pollsecs);
+ break;
+
+ case 'dosql':
+ if (!$allowsql) break;
+
+ $this->DoSQLForm();
+ break;
+ case 'viewsql':
+ if (empty($_GET['hidem']))
+ echo "&nbsp; <a href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
+ echo($this->SuspiciousSQL($nsql));
+ echo($this->ExpensiveSQL($nsql));
+ echo($this->InvalidSQL($nsql));
+ break;
+ case 'tables':
+ echo $this->Tables(); break;
+ }
+ global $ADODB_vers;
+ echo "<p><div align=center><font size=1>$ADODB_vers Sponsored by <a href=http://phplens.com/>phpLens</a></font></div>";
+ }
+
+ /*
+ Runs in infinite loop, returning real-time statistics
+ */
+ function Poll($secs=5)
+ {
+ $this->conn->fnExecute = false;
+ //$this->conn->debug=1;
+ if ($secs <= 1) $secs = 1;
+ echo "Accumulating statistics, every $secs seconds...\n";flush();
+ $arro =& $this->PollParameters();
+ $cnt = 0;
+ set_time_limit(0);
+ sleep($secs);
+ while (1) {
+
+ $arr =& $this->PollParameters();
+
+ $hits = sprintf('%2.2f',$arr[0]);
+ $reads = sprintf('%12.4f',($arr[1]-$arro[1])/$secs);
+ $writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs);
+ $sess = sprintf('%5d',$arr[3]);
+
+ $load = $this->CPULoad();
+ if ($load !== false) {
+ $oslabel = 'WS-CPU%';
+ $osval = sprintf(" %2.1f ",(float) $load);
+ }else {
+ $oslabel = '';
+ $osval = '';
+ }
+ if ($cnt % 10 == 0) echo " Time ".$oslabel." Hit% Sess Reads/s Writes/s\n";
+ $cnt += 1;
+ echo date('H:i:s').' '.$osval."$hits $sess $reads $writes\n";
+ flush();
+
+ if (connection_aborted()) return;
+
+ sleep($secs);
+ $arro = $arr;
+ }
+ }
+
+ /*
+ Returns basic health check in a command line interface
+ */
+ function HealthCheckCLI()
+ {
+ return $this->HealthCheck(true);
+ }
+
+
+ /*
+ Returns basic health check as HTML
+ */
+ function HealthCheck($cli=false)
+ {
+ $saveE = $this->conn->fnExecute;
+ $this->conn->fnExecute = false;
+ if ($cli) $html = '';
+ else $html = $this->table.'<tr><td colspan=3><h3>'.$this->conn->databaseType.'</h3></td></tr>'.$this->titles;
+
+ $oldc = false;
+ $bgc = '';
+ foreach($this->settings as $name => $arr) {
+ if ($arr === false) break;
+
+ if (!is_string($name)) {
+ if ($cli) $html .= " -- $arr -- \n";
+ else $html .= "<tr bgcolor=$this->color><td colspan=3><i>$arr</i> &nbsp;</td></tr>";
+ continue;
+ }
+
+ if (!is_array($arr)) break;
+ $category = $arr[0];
+ $how = $arr[1];
+ if (sizeof($arr)>2) $desc = $arr[2];
+ else $desc = ' &nbsp; ';
+
+
+ if ($category == 'HIDE') continue;
+
+ $val = $this->_DBParameter($how);
+
+ if ($desc && strncmp($desc,"=",1) === 0) {
+ $fn = substr($desc,1);
+ $desc = $this->$fn($val);
+ }
+
+ if ($val === false) {
+ $m = $this->conn->ErrorMsg();
+ $val = "Error: $m";
+ } else {
+ if (is_numeric($val) && $val >= 256*1024) {
+ if ($val % (1024*1024) == 0) {
+ $val /= (1024*1024);
+ $val .= 'M';
+ } else if ($val % 1024 == 0) {
+ $val /= 1024;
+ $val .= 'K';
+ }
+ //$val = htmlspecialchars($val);
+ }
+ }
+ if ($category != $oldc) {
+ $oldc = $category;
+ //$bgc = ($bgc == ' bgcolor='.$this->color) ? ' bgcolor=white' : ' bgcolor='.$this->color;
+ }
+ if (strlen($desc)==0) $desc = '&nbsp;';
+ if (strlen($val)==0) $val = '&nbsp;';
+ if ($cli) {
+ $html .= str_replace('&nbsp;','',sprintf($this->cliFormat,strip_tags($name),strip_tags($val),strip_tags($desc)));
+
+ }else {
+ $html .= "<tr$bgc><td>".$name.'</td><td>'.$val.'</td><td>'.$desc."</td></tr>\n";
+ }
+ }
+
+ if (!$cli) $html .= "</table>\n";
+ $this->conn->fnExecute = $saveE;
+
+ return $html;
+ }
+
+ function Tables($orderby='1')
+ {
+ if (!$this->tablesSQL) return false;
+
+ $savelog = $this->conn->LogSQL(false);
+ $rs = $this->conn->Execute($this->tablesSQL.' order by '.$orderby);
+ $this->conn->LogSQL($savelog);
+ $html = rs2html($rs,false,false,false,false);
+ return $html;
+ }
+
+
+ function CreateLogTable()
+ {
+ if (!$this->createTableSQL) return false;
+
+ $table = $this->table();
+ $sql = str_replace('adodb_logsql',$table,$this->createTableSQL);
+ $savelog = $this->conn->LogSQL(false);
+ $ok = $this->conn->Execute($sql);
+ $this->conn->LogSQL($savelog);
+ return ($ok) ? true : false;
+ }
+
+ function DoSQLForm()
+ {
+
+
+ $PHP_SELF = $_SERVER['PHP_SELF'];
+ $sql = isset($_REQUEST['sql']) ? $_REQUEST['sql'] : '';
+
+ if (isset($_SESSION['phplens_sqlrows'])) $rows = $_SESSION['phplens_sqlrows'];
+ else $rows = 3;
+
+ if (isset($_REQUEST['SMALLER'])) {
+ $rows /= 2;
+ if ($rows < 3) $rows = 3;
+ $_SESSION['phplens_sqlrows'] = $rows;
+ }
+ if (isset($_REQUEST['BIGGER'])) {
+ $rows *= 2;
+ $_SESSION['phplens_sqlrows'] = $rows;
+ }
+
+?>
+
+<form method="POST" action="<?php echo $PHP_SELF ?>">
+<table><tr>
+<td> Form size: <input type="submit" value=" &lt; " name="SMALLER"><input type="submit" value=" &gt; &gt; " name="BIGGER">
+</td>
+<td align=right>
+<input type="submit" value=" Run SQL Below " name="RUN"><input type=hidden name=do value=dosql>
+</td></tr>
+ <tr>
+ <td colspan=2><textarea rows=<?php print $rows; ?> name="sql" cols="80"><?php print htmlspecialchars($sql) ?></textarea>
+ </td>
+ </tr>
+ </table>
+</form>
+
+<?php
+ if (!isset($_REQUEST['sql'])) return;
+
+ $sql = $this->undomq(trim($sql));
+ if (substr($sql,strlen($sql)-1) === ';') {
+ $print = true;
+ $sqla = $this->SplitSQL($sql);
+ } else {
+ $print = false;
+ $sqla = array($sql);
+ }
+ foreach($sqla as $sqls) {
+
+ if (!$sqls) continue;
+
+ if ($print) {
+ print "<p>".htmlspecialchars($sqls)."</p>";
+ flush();
+ }
+ $savelog = $this->conn->LogSQL(false);
+ $rs = $this->conn->Execute($sqls);
+ $this->conn->LogSQL($savelog);
+ if ($rs && is_object($rs) && !$rs->EOF) {
+ rs2html($rs);
+ while ($rs->NextRecordSet()) {
+ print "<table width=98% bgcolor=#C0C0FF><tr><td>&nbsp;</td></tr></table>";
+ rs2html($rs);
+ }
+ } else {
+ $e1 = (integer) $this->conn->ErrorNo();
+ $e2 = $this->conn->ErrorMsg();
+ if (($e1) || ($e2)) {
+ if (empty($e1)) $e1 = '-1'; // postgresql fix
+ print ' &nbsp; '.$e1.': '.$e2;
+ } else {
+ print "<p>No Recordset returned<br></p>";
+ }
+ }
+ } // foreach
+ }
+
+ function SplitSQL($sql)
+ {
+ $arr = explode(';',$sql);
+ return $arr;
+ }
+
+ function undomq($m)
+ {
+ if (get_magic_quotes_gpc()) {
+ // undo the damage
+ $m = str_replace('\\\\','\\',$m);
+ $m = str_replace('\"','"',$m);
+ $m = str_replace('\\\'','\'',$m);
+ }
+ return $m;
+}
+
+
+ /************************************************************************/
+
+ /**
+ * Reorganise multiple table-indices/statistics/..
+ * OptimizeMode could be given by last Parameter
+ *
+ * @example
+ * <pre>
+ * optimizeTables( 'tableA');
+ * </pre>
+ * <pre>
+ * optimizeTables( 'tableA', 'tableB', 'tableC');
+ * </pre>
+ * <pre>
+ * optimizeTables( 'tableA', 'tableB', ADODB_OPT_LOW);
+ * </pre>
+ *
+ * @param string table name of the table to optimize
+ * @param int mode optimization-mode
+ * <code>ADODB_OPT_HIGH</code> for full optimization
+ * <code>ADODB_OPT_LOW</code> for CPU-less optimization
+ * Default is LOW <code>ADODB_OPT_LOW</code>
+ * @author Markus Staab
+ * @return Returns <code>true</code> on success and <code>false</code> on error
+ */
+ function OptimizeTables()
+ {
+ $args = func_get_args();
+ $numArgs = func_num_args();
+
+ if ( $numArgs == 0) return false;
+
+ $mode = ADODB_OPT_LOW;
+ $lastArg = $args[ $numArgs - 1];
+ if ( !is_string($lastArg)) {
+ $mode = $lastArg;
+ unset( $args[ $numArgs - 1]);
+ }
+
+ foreach( $args as $table) {
+ $this->optimizeTable( $table, $mode);
+ }
+ }
+
+ /**
+ * Reorganise the table-indices/statistics/.. depending on the given mode.
+ * Default Implementation throws an error.
+ *
+ * @param string table name of the table to optimize
+ * @param int mode optimization-mode
+ * <code>ADODB_OPT_HIGH</code> for full optimization
+ * <code>ADODB_OPT_LOW</code> for CPU-less optimization
+ * Default is LOW <code>ADODB_OPT_LOW</code>
+ * @author Markus Staab
+ * @return Returns <code>true</code> on success and <code>false</code> on error
+ */
+ function OptimizeTable( $table, $mode = ADODB_OPT_LOW)
+ {
+ ADOConnection::outp( sprintf( "<p>%s: '%s' not implemented for driver '%s'</p>", __CLASS__, __FUNCTION__, $this->conn->databaseType));
+ return false;
+ }
+
+ /**
+ * Reorganise current database.
+ * Default implementation loops over all <code>MetaTables()</code> and
+ * optimize each using <code>optmizeTable()</code>
+ *
+ * @author Markus Staab
+ * @return Returns <code>true</code> on success and <code>false</code> on error
+ */
+ function optimizeDatabase()
+ {
+ $conn = $this->conn;
+ if ( !$conn) return false;
+
+ $tables = $conn->MetaTables( 'TABLES');
+ if ( !$tables ) return false;
+
+ foreach( $tables as $table) {
+ if ( !$this->optimizeTable( $table)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ // end hack
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-php4.inc.php b/lib/adodb/adodb-php4.inc.php
new file mode 100644
index 0000000..99fda17
--- /dev/null
+++ b/lib/adodb/adodb-php4.inc.php
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4.
+*/
+
+
+class ADODB_BASE_RS {
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-time.inc.php b/lib/adodb/adodb-time.inc.php
new file mode 100644
index 0000000..51f69f7
--- /dev/null
+++ b/lib/adodb/adodb-time.inc.php
@@ -0,0 +1,1337 @@
+<?php
+/**
+ADOdb Date Library, part of the ADOdb abstraction library
+Download: http://phplens.com/phpeverywhere/
+
+PHP native date functions use integer timestamps for computations.
+Because of this, dates are restricted to the years 1901-2038 on Unix
+and 1970-2038 on Windows due to integer overflow for dates beyond
+those years. This library overcomes these limitations by replacing the
+native function's signed integers (normally 32-bits) with PHP floating
+point numbers (normally 64-bits).
+
+Dates from 100 A.D. to 3000 A.D. and later
+have been tested. The minimum is 100 A.D. as <100 will invoke the
+2 => 4 digit year conversion. The maximum is billions of years in the
+future, but this is a theoretical limit as the computation of that year
+would take too long with the current implementation of adodb_mktime().
+
+This library replaces native functions as follows:
+
+<pre>
+ getdate() with adodb_getdate()
+ date() with adodb_date()
+ gmdate() with adodb_gmdate()
+ mktime() with adodb_mktime()
+ gmmktime() with adodb_gmmktime()
+ strftime() with adodb_strftime()
+ strftime() with adodb_gmstrftime()
+</pre>
+
+The parameters are identical, except that adodb_date() accepts a subset
+of date()'s field formats. Mktime() will convert from local time to GMT,
+and date() will convert from GMT to local time, but daylight savings is
+not handled currently.
+
+This library is independant of the rest of ADOdb, and can be used
+as standalone code.
+
+PERFORMANCE
+
+For high speed, this library uses the native date functions where
+possible, and only switches to PHP code when the dates fall outside
+the 32-bit signed integer range.
+
+GREGORIAN CORRECTION
+
+Pope Gregory shortened October of A.D. 1582 by ten days. Thursday,
+October 4, 1582 (Julian) was followed immediately by Friday, October 15,
+1582 (Gregorian).
+
+Since 0.06, we handle this correctly, so:
+
+adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582)
+ == 24 * 3600 (1 day)
+
+=============================================================================
+
+COPYRIGHT
+
+(c) 2003-2005 John Lim and released under BSD-style license except for code by
+jackbbs, which includes adodb_mktime, adodb_get_gmt_diff, adodb_is_leap_year
+and originally found at http://www.php.net/manual/en/function.mktime.php
+
+=============================================================================
+
+BUG REPORTS
+
+These should be posted to the ADOdb forums at
+
+ http://phplens.com/lens/lensforum/topics.php?id=4
+
+=============================================================================
+
+FUNCTION DESCRIPTIONS
+
+
+** FUNCTION adodb_getdate($date=false)
+
+Returns an array containing date information, as getdate(), but supports
+dates greater than 1901 to 2038. The local date/time format is derived from a
+heuristic the first time adodb_getdate is called.
+
+
+** FUNCTION adodb_date($fmt, $timestamp = false)
+
+Convert a timestamp to a formatted local date. If $timestamp is not defined, the
+current timestamp is used. Unlike the function date(), it supports dates
+outside the 1901 to 2038 range.
+
+The format fields that adodb_date supports:
+
+<pre>
+ a - "am" or "pm"
+ A - "AM" or "PM"
+ d - day of the month, 2 digits with leading zeros; i.e. "01" to "31"
+ D - day of the week, textual, 3 letters; e.g. "Fri"
+ F - month, textual, long; e.g. "January"
+ g - hour, 12-hour format without leading zeros; i.e. "1" to "12"
+ G - hour, 24-hour format without leading zeros; i.e. "0" to "23"
+ h - hour, 12-hour format; i.e. "01" to "12"
+ H - hour, 24-hour format; i.e. "00" to "23"
+ i - minutes; i.e. "00" to "59"
+ j - day of the month without leading zeros; i.e. "1" to "31"
+ l (lowercase 'L') - day of the week, textual, long; e.g. "Friday"
+ L - boolean for whether it is a leap year; i.e. "0" or "1"
+ m - month; i.e. "01" to "12"
+ M - month, textual, 3 letters; e.g. "Jan"
+ n - month without leading zeros; i.e. "1" to "12"
+ O - Difference to Greenwich time in hours; e.g. "+0200"
+ Q - Quarter, as in 1, 2, 3, 4
+ r - RFC 2822 formatted date; e.g. "Thu, 21 Dec 2000 16:01:07 +0200"
+ s - seconds; i.e. "00" to "59"
+ S - English ordinal suffix for the day of the month, 2 characters;
+ i.e. "st", "nd", "rd" or "th"
+ t - number of days in the given month; i.e. "28" to "31"
+ T - Timezone setting of this machine; e.g. "EST" or "MDT"
+ U - seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
+ w - day of the week, numeric, i.e. "0" (Sunday) to "6" (Saturday)
+ Y - year, 4 digits; e.g. "1999"
+ y - year, 2 digits; e.g. "99"
+ z - day of the year; i.e. "0" to "365"
+ Z - timezone offset in seconds (i.e. "-43200" to "43200").
+ The offset for timezones west of UTC is always negative,
+ and for those east of UTC is always positive.
+</pre>
+
+Unsupported:
+<pre>
+ B - Swatch Internet time
+ I (capital i) - "1" if Daylight Savings Time, "0" otherwise.
+ W - ISO-8601 week number of year, weeks starting on Monday
+
+</pre>
+
+
+** FUNCTION adodb_date2($fmt, $isoDateString = false)
+Same as adodb_date, but 2nd parameter accepts iso date, eg.
+
+ adodb_date2('d-M-Y H:i','2003-12-25 13:01:34');
+
+
+** FUNCTION adodb_gmdate($fmt, $timestamp = false)
+
+Convert a timestamp to a formatted GMT date. If $timestamp is not defined, the
+current timestamp is used. Unlike the function date(), it supports dates
+outside the 1901 to 2038 range.
+
+
+** FUNCTION adodb_mktime($hr, $min, $sec[, $month, $day, $year])
+
+Converts a local date to a unix timestamp. Unlike the function mktime(), it supports
+dates outside the 1901 to 2038 range. All parameters are optional.
+
+
+** FUNCTION adodb_gmmktime($hr, $min, $sec [, $month, $day, $year])
+
+Converts a gmt date to a unix timestamp. Unlike the function gmmktime(), it supports
+dates outside the 1901 to 2038 range. Differs from gmmktime() in that all parameters
+are currently compulsory.
+
+** FUNCTION adodb_gmstrftime($fmt, $timestamp = false)
+Convert a timestamp to a formatted GMT date.
+
+** FUNCTION adodb_strftime($fmt, $timestamp = false)
+
+Convert a timestamp to a formatted local date. Internally converts $fmt into
+adodb_date format, then echo result.
+
+For best results, you can define the local date format yourself. Define a global
+variable $ADODB_DATE_LOCALE which is an array, 1st element is date format using
+adodb_date syntax, and 2nd element is the time format, also in adodb_date syntax.
+
+ eg. $ADODB_DATE_LOCALE = array('d/m/Y','H:i:s');
+
+ Supported format codes:
+
+<pre>
+ %a - abbreviated weekday name according to the current locale
+ %A - full weekday name according to the current locale
+ %b - abbreviated month name according to the current locale
+ %B - full month name according to the current locale
+ %c - preferred date and time representation for the current locale
+ %d - day of the month as a decimal number (range 01 to 31)
+ %D - same as %m/%d/%y
+ %e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31')
+ %h - same as %b
+ %H - hour as a decimal number using a 24-hour clock (range 00 to 23)
+ %I - hour as a decimal number using a 12-hour clock (range 01 to 12)
+ %m - month as a decimal number (range 01 to 12)
+ %M - minute as a decimal number
+ %n - newline character
+ %p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale
+ %r - time in a.m. and p.m. notation
+ %R - time in 24 hour notation
+ %S - second as a decimal number
+ %t - tab character
+ %T - current time, equal to %H:%M:%S
+ %x - preferred date representation for the current locale without the time
+ %X - preferred time representation for the current locale without the date
+ %y - year as a decimal number without a century (range 00 to 99)
+ %Y - year as a decimal number including the century
+ %Z - time zone or name or abbreviation
+ %% - a literal `%' character
+</pre>
+
+ Unsupported codes:
+<pre>
+ %C - century number (the year divided by 100 and truncated to an integer, range 00 to 99)
+ %g - like %G, but without the century.
+ %G - The 4-digit year corresponding to the ISO week number (see %V).
+ This has the same format and value as %Y, except that if the ISO week number belongs
+ to the previous or next year, that year is used instead.
+ %j - day of the year as a decimal number (range 001 to 366)
+ %u - weekday as a decimal number [1,7], with 1 representing Monday
+ %U - week number of the current year as a decimal number, starting
+ with the first Sunday as the first day of the first week
+ %V - The ISO 8601:1988 week number of the current year as a decimal number,
+ range 01 to 53, where week 1 is the first week that has at least 4 days in the
+ current year, and with Monday as the first day of the week. (Use %G or %g for
+ the year component that corresponds to the week number for the specified timestamp.)
+ %w - day of the week as a decimal, Sunday being 0
+ %W - week number of the current year as a decimal number, starting with the
+ first Monday as the first day of the first week
+</pre>
+
+=============================================================================
+
+NOTES
+
+Useful url for generating test timestamps:
+ http://www.4webhelp.net/us/timestamp.php
+
+Possible future optimizations include
+
+a. Using an algorithm similar to Plauger's in "The Standard C Library"
+(page 428, xttotm.c _Ttotm() function). Plauger's algorithm will not
+work outside 32-bit signed range, so i decided not to implement it.
+
+b. Implement daylight savings, which looks awfully complicated, see
+ http://webexhibits.org/daylightsaving/
+
+
+CHANGELOG
+- 19 March 2006 0.24
+Changed strftime() locale detection, because some locales prepend the day of week to the date when %c is used.
+
+- 10 Feb 2006 0.23
+PHP5 compat: when we detect PHP5, the RFC2822 format for gmt 0000hrs is changed from -0000 to +0000.
+ In PHP4, we will still use -0000 for 100% compat with PHP4.
+
+- 08 Sept 2005 0.22
+In adodb_date2(), $is_gmt not supported properly. Fixed.
+
+- 18 July 2005 0.21
+In PHP 4.3.11, the 'r' format has changed. Leading 0 in day is added. Changed for compat.
+Added support for negative months in adodb_mktime().
+
+- 24 Feb 2005 0.20
+Added limited strftime/gmstrftime support. x10 improvement in performance of adodb_date().
+
+- 21 Dec 2004 0.17
+In adodb_getdate(), the timestamp was accidentally converted to gmt when $is_gmt is false.
+Also adodb_mktime(0,0,0) did not work properly. Both fixed thx Mauro.
+
+- 17 Nov 2004 0.16
+Removed intval typecast in adodb_mktime() for secs, allowing:
+ adodb_mktime(0,0,0 + 2236672153,1,1,1934);
+Suggested by Ryan.
+
+- 18 July 2004 0.15
+All params in adodb_mktime were formerly compulsory. Now only the hour, min, secs is compulsory.
+This brings it more in line with mktime (still not identical).
+
+- 23 June 2004 0.14
+
+Allow you to define your own daylights savings function, adodb_daylight_sv.
+If the function is defined (somewhere in an include), then you can correct for daylights savings.
+
+In this example, we apply daylights savings in June or July, adding one hour. This is extremely
+unrealistic as it does not take into account time-zone, geographic location, current year.
+
+function adodb_daylight_sv(&$arr, $is_gmt)
+{
+ if ($is_gmt) return;
+ $m = $arr['mon'];
+ if ($m == 6 || $m == 7) $arr['hours'] += 1;
+}
+
+This is only called by adodb_date() and not by adodb_mktime().
+
+The format of $arr is
+Array (
+ [seconds] => 0
+ [minutes] => 0
+ [hours] => 0
+ [mday] => 1 # day of month, eg 1st day of the month
+ [mon] => 2 # month (eg. Feb)
+ [year] => 2102
+ [yday] => 31 # days in current year
+ [leap] => # true if leap year
+ [ndays] => 28 # no of days in current month
+ )
+
+
+- 28 Apr 2004 0.13
+Fixed adodb_date to properly support $is_gmt. Thx to Dimitar Angelov.
+
+- 20 Mar 2004 0.12
+Fixed month calculation error in adodb_date. 2102-June-01 appeared as 2102-May-32.
+
+- 26 Oct 2003 0.11
+Because of daylight savings problems (some systems apply daylight savings to
+January!!!), changed adodb_get_gmt_diff() to ignore daylight savings.
+
+- 9 Aug 2003 0.10
+Fixed bug with dates after 2038.
+See http://phplens.com/lens/lensforum/msgs.php?id=6980
+
+- 1 July 2003 0.09
+Added support for Q (Quarter).
+Added adodb_date2(), which accepts ISO date in 2nd param
+
+- 3 March 2003 0.08
+Added support for 'S' adodb_date() format char. Added constant ADODB_ALLOW_NEGATIVE_TS
+if you want PHP to handle negative timestamps between 1901 to 1969.
+
+- 27 Feb 2003 0.07
+All negative numbers handled by adodb now because of RH 7.3+ problems.
+See http://bugs.php.net/bug.php?id=20048&edit=2
+
+- 4 Feb 2003 0.06
+Fixed a typo, 1852 changed to 1582! This means that pre-1852 dates
+are now correctly handled.
+
+- 29 Jan 2003 0.05
+
+Leap year checking differs under Julian calendar (pre 1582). Also
+leap year code optimized by checking for most common case first.
+
+We also handle month overflow correctly in mktime (eg month set to 13).
+
+Day overflow for less than one month's days is supported.
+
+- 28 Jan 2003 0.04
+
+Gregorian correction handled. In PHP5, we might throw an error if
+mktime uses invalid dates around 5-14 Oct 1582. Released with ADOdb 3.10.
+Added limbo 5-14 Oct 1582 check, when we set to 15 Oct 1582.
+
+- 27 Jan 2003 0.03
+
+Fixed some more month problems due to gmt issues. Added constant ADODB_DATE_VERSION.
+Fixed calculation of days since start of year for <1970.
+
+- 27 Jan 2003 0.02
+
+Changed _adodb_getdate() to inline leap year checking for better performance.
+Fixed problem with time-zones west of GMT +0000.
+
+- 24 Jan 2003 0.01
+
+First implementation.
+*/
+
+
+/* Initialization */
+
+/*
+ Version Number
+*/
+define('ADODB_DATE_VERSION',0.24);
+
+/*
+ This code was originally for windows. But apparently this problem happens
+ also with Linux, RH 7.3 and later!
+
+ glibc-2.2.5-34 and greater has been changed to return -1 for dates <
+ 1970. This used to work. The problem exists with RedHat 7.3 and 8.0
+ echo (mktime(0, 0, 0, 1, 1, 1960)); // prints -1
+
+ References:
+ http://bugs.php.net/bug.php?id=20048&edit=2
+ http://lists.debian.org/debian-glibc/2002/debian-glibc-200205/msg00010.html
+*/
+
+if (!defined('ADODB_ALLOW_NEGATIVE_TS')) define('ADODB_NO_NEGATIVE_TS',1);
+
+function adodb_date_test_date($y1,$m,$d=13)
+{
+ $t = adodb_mktime(0,0,0,$m,$d,$y1);
+ $rez = adodb_date('Y-n-j H:i:s',$t);
+ if ("$y1-$m-$d 00:00:00" != $rez) {
+ print "<b>$y1 error, expected=$y1-$m-$d 00:00:00, adodb=$rez</b><br>";
+ return false;
+ }
+ return true;
+}
+
+function adodb_date_test_strftime($fmt)
+{
+ $s1 = strftime($fmt);
+ $s2 = adodb_strftime($fmt);
+
+ if ($s1 == $s2) return true;
+
+ echo "error for $fmt, strftime=$s1, $adodb=$s2<br>";
+ return false;
+}
+
+/**
+ Test Suite
+*/
+function adodb_date_test()
+{
+
+ error_reporting(E_ALL);
+ print "<h4>Testing adodb_date and adodb_mktime. version=".ADODB_DATE_VERSION.' PHP='.PHP_VERSION."</h4>";
+ @set_time_limit(0);
+ $fail = false;
+
+ // This flag disables calling of PHP native functions, so we can properly test the code
+ if (!defined('ADODB_TEST_DATES')) define('ADODB_TEST_DATES',1);
+
+ adodb_date_test_strftime('%Y %m %x %X');
+ adodb_date_test_strftime("%A %d %B %Y");
+ adodb_date_test_strftime("%H %M S");
+
+ $t = adodb_mktime(0,0,0);
+ if (!(adodb_date('Y-m-d') == date('Y-m-d'))) print 'Error in '.adodb_mktime(0,0,0).'<br>';
+
+ $t = adodb_mktime(0,0,0,6,1,2102);
+ if (!(adodb_date('Y-m-d',$t) == '2102-06-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
+
+ $t = adodb_mktime(0,0,0,2,1,2102);
+ if (!(adodb_date('Y-m-d',$t) == '2102-02-01')) print 'Error in '.adodb_date('Y-m-d',$t).'<br>';
+
+
+ print "<p>Testing gregorian <=> julian conversion<p>";
+ $t = adodb_mktime(0,0,0,10,11,1492);
+ //http://www.holidayorigins.com/html/columbus_day.html - Friday check
+ if (!(adodb_date('D Y-m-d',$t) == 'Fri 1492-10-11')) print 'Error in Columbus landing<br>';
+
+ $t = adodb_mktime(0,0,0,2,29,1500);
+ if (!(adodb_date('Y-m-d',$t) == '1500-02-29')) print 'Error in julian leap years<br>';
+
+ $t = adodb_mktime(0,0,0,2,29,1700);
+ if (!(adodb_date('Y-m-d',$t) == '1700-03-01')) print 'Error in gregorian leap years<br>';
+
+ print adodb_mktime(0,0,0,10,4,1582).' ';
+ print adodb_mktime(0,0,0,10,15,1582);
+ $diff = (adodb_mktime(0,0,0,10,15,1582) - adodb_mktime(0,0,0,10,4,1582));
+ if ($diff != 3600*24) print " <b>Error in gregorian correction = ".($diff/3600/24)." days </b><br>";
+
+ print " 15 Oct 1582, Fri=".(adodb_dow(1582,10,15) == 5 ? 'Fri' : '<b>Error</b>')."<br>";
+ print " 4 Oct 1582, Thu=".(adodb_dow(1582,10,4) == 4 ? 'Thu' : '<b>Error</b>')."<br>";
+
+ print "<p>Testing overflow<p>";
+
+ $t = adodb_mktime(0,0,0,3,33,1965);
+ if (!(adodb_date('Y-m-d',$t) == '1965-04-02')) print 'Error in day overflow 1 <br>';
+ $t = adodb_mktime(0,0,0,4,33,1971);
+ if (!(adodb_date('Y-m-d',$t) == '1971-05-03')) print 'Error in day overflow 2 <br>';
+ $t = adodb_mktime(0,0,0,1,60,1965);
+ if (!(adodb_date('Y-m-d',$t) == '1965-03-01')) print 'Error in day overflow 3 '.adodb_date('Y-m-d',$t).' <br>';
+ $t = adodb_mktime(0,0,0,12,32,1965);
+ if (!(adodb_date('Y-m-d',$t) == '1966-01-01')) print 'Error in day overflow 4 '.adodb_date('Y-m-d',$t).' <br>';
+ $t = adodb_mktime(0,0,0,12,63,1965);
+ if (!(adodb_date('Y-m-d',$t) == '1966-02-01')) print 'Error in day overflow 5 '.adodb_date('Y-m-d',$t).' <br>';
+ $t = adodb_mktime(0,0,0,13,3,1965);
+ if (!(adodb_date('Y-m-d',$t) == '1966-01-03')) print 'Error in mth overflow 1 <br>';
+
+ print "Testing 2-digit => 4-digit year conversion<p>";
+ if (adodb_year_digit_check(00) != 2000) print "Err 2-digit 2000<br>";
+ if (adodb_year_digit_check(10) != 2010) print "Err 2-digit 2010<br>";
+ if (adodb_year_digit_check(20) != 2020) print "Err 2-digit 2020<br>";
+ if (adodb_year_digit_check(30) != 2030) print "Err 2-digit 2030<br>";
+ if (adodb_year_digit_check(40) != 1940) print "Err 2-digit 1940<br>";
+ if (adodb_year_digit_check(50) != 1950) print "Err 2-digit 1950<br>";
+ if (adodb_year_digit_check(90) != 1990) print "Err 2-digit 1990<br>";
+
+ // Test string formating
+ print "<p>Testing date formating</p>";
+ $fmt = '\d\a\t\e T Y-m-d H:i:s a A d D F g G h H i j l L m M n O \R\F\C2822 r s t U w y Y z Z 2003';
+ $s1 = date($fmt,0);
+ $s2 = adodb_date($fmt,0);
+ if ($s1 != $s2) {
+ print " date() 0 failed<br>$s1<br>$s2<br>";
+ }
+ flush();
+ for ($i=100; --$i > 0; ) {
+
+ $ts = 3600.0*((rand()%60000)+(rand()%60000))+(rand()%60000);
+ $s1 = date($fmt,$ts);
+ $s2 = adodb_date($fmt,$ts);
+ //print "$s1 <br>$s2 <p>";
+ $pos = strcmp($s1,$s2);
+
+ if (($s1) != ($s2)) {
+ for ($j=0,$k=strlen($s1); $j < $k; $j++) {
+ if ($s1[$j] != $s2[$j]) {
+ print substr($s1,$j).' ';
+ break;
+ }
+ }
+ print "<b>Error date(): $ts<br><pre>
+&nbsp; \"$s1\" (date len=".strlen($s1).")
+&nbsp; \"$s2\" (adodb_date len=".strlen($s2).")</b></pre><br>";
+ $fail = true;
+ }
+
+ $a1 = getdate($ts);
+ $a2 = adodb_getdate($ts);
+ $rez = array_diff($a1,$a2);
+ if (sizeof($rez)>0) {
+ print "<b>Error getdate() $ts</b><br>";
+ print_r($a1);
+ print "<br>";
+ print_r($a2);
+ print "<p>";
+ $fail = true;
+ }
+ }
+
+ // Test generation of dates outside 1901-2038
+ print "<p>Testing random dates between 100 and 4000</p>";
+ adodb_date_test_date(100,1);
+ for ($i=100; --$i >= 0;) {
+ $y1 = 100+rand(0,1970-100);
+ $m = rand(1,12);
+ adodb_date_test_date($y1,$m);
+
+ $y1 = 3000-rand(0,3000-1970);
+ adodb_date_test_date($y1,$m);
+ }
+ print '<p>';
+ $start = 1960+rand(0,10);
+ $yrs = 12;
+ $i = 365.25*86400*($start-1970);
+ $offset = 36000+rand(10000,60000);
+ $max = 365*$yrs*86400;
+ $lastyear = 0;
+
+ // we generate a timestamp, convert it to a date, and convert it back to a timestamp
+ // and check if the roundtrip broke the original timestamp value.
+ print "Testing $start to ".($start+$yrs).", or $max seconds, offset=$offset: ";
+ $cnt = 0;
+ for ($max += $i; $i < $max; $i += $offset) {
+ $ret = adodb_date('m,d,Y,H,i,s',$i);
+ $arr = explode(',',$ret);
+ if ($lastyear != $arr[2]) {
+ $lastyear = $arr[2];
+ print " $lastyear ";
+ flush();
+ }
+ $newi = adodb_mktime($arr[3],$arr[4],$arr[5],$arr[0],$arr[1],$arr[2]);
+ if ($i != $newi) {
+ print "Error at $i, adodb_mktime returned $newi ($ret)";
+ $fail = true;
+ break;
+ }
+ $cnt += 1;
+ }
+ echo "Tested $cnt dates<br>";
+ if (!$fail) print "<p>Passed !</p>";
+ else print "<p><b>Failed</b> :-(</p>";
+}
+
+/**
+ Returns day of week, 0 = Sunday,... 6=Saturday.
+ Algorithm from PEAR::Date_Calc
+*/
+function adodb_dow($year, $month, $day)
+{
+/*
+Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and
+proclaimed that from that time onwards 3 days would be dropped from the calendar
+every 400 years.
+
+Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).
+*/
+ if ($year <= 1582) {
+ if ($year < 1582 ||
+ ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15)))) $greg_correction = 3;
+ else
+ $greg_correction = 0;
+ } else
+ $greg_correction = 0;
+
+ if($month > 2)
+ $month -= 2;
+ else {
+ $month += 10;
+ $year--;
+ }
+
+ $day = floor((13 * $month - 1) / 5) +
+ $day + ($year % 100) +
+ floor(($year % 100) / 4) +
+ floor(($year / 100) / 4) - 2 *
+ floor($year / 100) + 77 + $greg_correction;
+
+ return $day - 7 * floor($day / 7);
+}
+
+
+/**
+ Checks for leap year, returns true if it is. No 2-digit year check. Also
+ handles julian calendar correctly.
+*/
+function _adodb_is_leap_year($year)
+{
+ if ($year % 4 != 0) return false;
+
+ if ($year % 400 == 0) {
+ return true;
+ // if gregorian calendar (>1582), century not-divisible by 400 is not leap
+ } else if ($year > 1582 && $year % 100 == 0 ) {
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ checks for leap year, returns true if it is. Has 2-digit year check
+*/
+function adodb_is_leap_year($year)
+{
+ return _adodb_is_leap_year(adodb_year_digit_check($year));
+}
+
+/**
+ Fix 2-digit years. Works for any century.
+ Assumes that if 2-digit is more than 30 years in future, then previous century.
+*/
+function adodb_year_digit_check($y)
+{
+ if ($y < 100) {
+
+ $yr = (integer) date("Y");
+ $century = (integer) ($yr /100);
+
+ if ($yr%100 > 50) {
+ $c1 = $century + 1;
+ $c0 = $century;
+ } else {
+ $c1 = $century;
+ $c0 = $century - 1;
+ }
+ $c1 *= 100;
+ // if 2-digit year is less than 30 years in future, set it to this century
+ // otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
+ if (($y + $c1) < $yr+30) $y = $y + $c1;
+ else $y = $y + $c0*100;
+ }
+ return $y;
+}
+
+/**
+ get local time zone offset from GMT
+*/
+function adodb_get_gmt_diff()
+{
+static $TZ;
+ if (isset($TZ)) return $TZ;
+
+ $TZ = mktime(0,0,0,1,2,1970,0) - gmmktime(0,0,0,1,2,1970,0);
+ return $TZ;
+}
+
+/**
+ Returns an array with date info.
+*/
+function adodb_getdate($d=false,$fast=false)
+{
+ if ($d === false) return getdate();
+ if (!defined('ADODB_TEST_DATES')) {
+ if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
+ if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
+ return @getdate($d);
+ }
+ }
+ return _adodb_getdate($d);
+}
+
+/*
+// generate $YRS table for _adodb_getdate()
+function adodb_date_gentable($out=true)
+{
+
+ for ($i=1970; $i >= 1600; $i-=10) {
+ $s = adodb_gmmktime(0,0,0,1,1,$i);
+ echo "$i => $s,<br>";
+ }
+}
+adodb_date_gentable();
+
+for ($i=1970; $i > 1500; $i--) {
+
+echo "<hr />$i ";
+ adodb_date_test_date($i,1,1);
+}
+
+*/
+
+
+$_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
+$_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
+
+function adodb_validdate($y,$m,$d)
+{
+global $_month_table_normal,$_month_table_leaf;
+
+ if (_adodb_is_leap_year($y)) $marr =& $_month_table_leaf;
+ else $marr =& $_month_table_normal;
+
+ if ($m > 12 || $m < 1) return false;
+
+ if ($d > 31 || $d < 1) return false;
+
+ if ($marr[$m] < $d) return false;
+
+ if ($y < 1000 && $y > 3000) return false;
+
+ return true;
+}
+
+/**
+ Low-level function that returns the getdate() array. We have a special
+ $fast flag, which if set to true, will return fewer array values,
+ and is much faster as it does not calculate dow, etc.
+*/
+function _adodb_getdate($origd=false,$fast=false,$is_gmt=false)
+{
+static $YRS;
+global $_month_table_normal,$_month_table_leaf;
+
+ $d = $origd - ($is_gmt ? 0 : adodb_get_gmt_diff());
+
+ $_day_power = 86400;
+ $_hour_power = 3600;
+ $_min_power = 60;
+
+ if ($d < -12219321600) $d -= 86400*10; // if 15 Oct 1582 or earlier, gregorian correction
+
+ $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
+ $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
+
+ $d366 = $_day_power * 366;
+ $d365 = $_day_power * 365;
+
+ if ($d < 0) {
+
+ if (empty($YRS)) $YRS = array(
+ 1970 => 0,
+ 1960 => -315619200,
+ 1950 => -631152000,
+ 1940 => -946771200,
+ 1930 => -1262304000,
+ 1920 => -1577923200,
+ 1910 => -1893456000,
+ 1900 => -2208988800,
+ 1890 => -2524521600,
+ 1880 => -2840140800,
+ 1870 => -3155673600,
+ 1860 => -3471292800,
+ 1850 => -3786825600,
+ 1840 => -4102444800,
+ 1830 => -4417977600,
+ 1820 => -4733596800,
+ 1810 => -5049129600,
+ 1800 => -5364662400,
+ 1790 => -5680195200,
+ 1780 => -5995814400,
+ 1770 => -6311347200,
+ 1760 => -6626966400,
+ 1750 => -6942499200,
+ 1740 => -7258118400,
+ 1730 => -7573651200,
+ 1720 => -7889270400,
+ 1710 => -8204803200,
+ 1700 => -8520336000,
+ 1690 => -8835868800,
+ 1680 => -9151488000,
+ 1670 => -9467020800,
+ 1660 => -9782640000,
+ 1650 => -10098172800,
+ 1640 => -10413792000,
+ 1630 => -10729324800,
+ 1620 => -11044944000,
+ 1610 => -11360476800,
+ 1600 => -11676096000);
+
+ if ($is_gmt) $origd = $d;
+ // The valid range of a 32bit signed timestamp is typically from
+ // Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT
+ //
+
+ # old algorithm iterates through all years. new algorithm does it in
+ # 10 year blocks
+
+ /*
+ # old algo
+ for ($a = 1970 ; --$a >= 0;) {
+ $lastd = $d;
+
+ if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
+ else $d += $d365;
+
+ if ($d >= 0) {
+ $year = $a;
+ break;
+ }
+ }
+ */
+
+ $lastsecs = 0;
+ $lastyear = 1970;
+ foreach($YRS as $year => $secs) {
+ if ($d >= $secs) {
+ $a = $lastyear;
+ break;
+ }
+ $lastsecs = $secs;
+ $lastyear = $year;
+ }
+
+ $d -= $lastsecs;
+ if (!isset($a)) $a = $lastyear;
+
+ //echo ' yr=',$a,' ', $d,'.';
+
+ for (; --$a >= 0;) {
+ $lastd = $d;
+
+ if ($leaf = _adodb_is_leap_year($a)) $d += $d366;
+ else $d += $d365;
+
+ if ($d >= 0) {
+ $year = $a;
+ break;
+ }
+ }
+ /**/
+
+ $secsInYear = 86400 * ($leaf ? 366 : 365) + $lastd;
+
+ $d = $lastd;
+ $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
+ for ($a = 13 ; --$a > 0;) {
+ $lastd = $d;
+ $d += $mtab[$a] * $_day_power;
+ if ($d >= 0) {
+ $month = $a;
+ $ndays = $mtab[$a];
+ break;
+ }
+ }
+
+ $d = $lastd;
+ $day = $ndays + ceil(($d+1) / ($_day_power));
+
+ $d += ($ndays - $day+1)* $_day_power;
+ $hour = floor($d/$_hour_power);
+
+ } else {
+ for ($a = 1970 ;; $a++) {
+ $lastd = $d;
+
+ if ($leaf = _adodb_is_leap_year($a)) $d -= $d366;
+ else $d -= $d365;
+ if ($d < 0) {
+ $year = $a;
+ break;
+ }
+ }
+ $secsInYear = $lastd;
+ $d = $lastd;
+ $mtab = ($leaf) ? $_month_table_leaf : $_month_table_normal;
+ for ($a = 1 ; $a <= 12; $a++) {
+ $lastd = $d;
+ $d -= $mtab[$a] * $_day_power;
+ if ($d < 0) {
+ $month = $a;
+ $ndays = $mtab[$a];
+ break;
+ }
+ }
+ $d = $lastd;
+ $day = ceil(($d+1) / $_day_power);
+ $d = $d - ($day-1) * $_day_power;
+ $hour = floor($d /$_hour_power);
+ }
+
+ $d -= $hour * $_hour_power;
+ $min = floor($d/$_min_power);
+ $secs = $d - $min * $_min_power;
+ if ($fast) {
+ return array(
+ 'seconds' => $secs,
+ 'minutes' => $min,
+ 'hours' => $hour,
+ 'mday' => $day,
+ 'mon' => $month,
+ 'year' => $year,
+ 'yday' => floor($secsInYear/$_day_power),
+ 'leap' => $leaf,
+ 'ndays' => $ndays
+ );
+ }
+
+
+ $dow = adodb_dow($year,$month,$day);
+
+ return array(
+ 'seconds' => $secs,
+ 'minutes' => $min,
+ 'hours' => $hour,
+ 'mday' => $day,
+ 'wday' => $dow,
+ 'mon' => $month,
+ 'year' => $year,
+ 'yday' => floor($secsInYear/$_day_power),
+ 'weekday' => gmdate('l',$_day_power*(3+$dow)),
+ 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)),
+ 0 => $origd
+ );
+}
+
+function adodb_gmdate($fmt,$d=false)
+{
+ return adodb_date($fmt,$d,true);
+}
+
+// accepts unix timestamp and iso date format in $d
+function adodb_date2($fmt, $d=false, $is_gmt=false)
+{
+ if ($d !== false) {
+ 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}))?|",
+ ($d), $rr)) return adodb_date($fmt,false,$is_gmt);
+
+ if ($rr[1] <= 100 && $rr[2]<= 1) return adodb_date($fmt,false,$is_gmt);
+
+ // h-m-s-MM-DD-YY
+ if (!isset($rr[5])) $d = adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1],false,$is_gmt);
+ else $d = @adodb_mktime($rr[5],$rr[6],$rr[7],$rr[2],$rr[3],$rr[1],false,$is_gmt);
+ }
+
+ return adodb_date($fmt,$d,$is_gmt);
+}
+
+
+/**
+ Return formatted date based on timestamp $d
+*/
+function adodb_date($fmt,$d=false,$is_gmt=false)
+{
+static $daylight;
+
+ if ($d === false) return ($is_gmt)? @gmdate($fmt): @date($fmt);
+ if (!defined('ADODB_TEST_DATES')) {
+ if ((abs($d) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
+ if (!defined('ADODB_NO_NEGATIVE_TS') || $d >= 0) // if windows, must be +ve integer
+ return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d);
+
+ }
+ }
+ $_day_power = 86400;
+
+ $arr = _adodb_getdate($d,true,$is_gmt);
+
+ if (!isset($daylight)) $daylight = function_exists('adodb_daylight_sv');
+ if ($daylight) adodb_daylight_sv($arr, $is_gmt);
+
+ $year = $arr['year'];
+ $month = $arr['mon'];
+ $day = $arr['mday'];
+ $hour = $arr['hours'];
+ $min = $arr['minutes'];
+ $secs = $arr['seconds'];
+
+ $max = strlen($fmt);
+ $dates = '';
+
+ $isphp5 = PHP_VERSION >= 5;
+
+ /*
+ at this point, we have the following integer vars to manipulate:
+ $year, $month, $day, $hour, $min, $secs
+ */
+ for ($i=0; $i < $max; $i++) {
+ switch($fmt[$i]) {
+ case 'T': $dates .= date('T');break;
+ // YEAR
+ case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
+ case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
+
+ // 4.3.11 uses '04 Jun 2004'
+ // 4.3.8 uses ' 4 Jun 2004'
+ $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))).', '
+ . ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
+
+ if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour;
+
+ if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;
+
+ if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
+
+ $gmt = adodb_get_gmt_diff();
+ if ($isphp5)
+ $dates .= sprintf(' %s%04d',($gmt<=0)?'+':'-',abs($gmt)/36);
+ else
+ $dates .= sprintf(' %s%04d',($gmt<0)?'+':'-',abs($gmt)/36);
+ break;
+
+ case 'Y': $dates .= $year; break;
+ case 'y': $dates .= substr($year,strlen($year)-2,2); break;
+ // MONTH
+ case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
+ case 'Q': $dates .= ($month+3)>>2; break;
+ case 'n': $dates .= $month; break;
+ case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
+ case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
+ // DAY
+ case 't': $dates .= $arr['ndays']; break;
+ case 'z': $dates .= $arr['yday']; break;
+ case 'w': $dates .= adodb_dow($year,$month,$day); break;
+ case 'l': $dates .= gmdate('l',$_day_power*(3+adodb_dow($year,$month,$day))); break;
+ case 'D': $dates .= gmdate('D',$_day_power*(3+adodb_dow($year,$month,$day))); break;
+ case 'j': $dates .= $day; break;
+ case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;
+ case 'S':
+ $d10 = $day % 10;
+ if ($d10 == 1) $dates .= 'st';
+ else if ($d10 == 2 && $day != 12) $dates .= 'nd';
+ else if ($d10 == 3) $dates .= 'rd';
+ else $dates .= 'th';
+ break;
+
+ // HOUR
+ case 'Z':
+ $dates .= ($is_gmt) ? 0 : -adodb_get_gmt_diff(); break;
+ case 'O':
+ $gmt = ($is_gmt) ? 0 : adodb_get_gmt_diff();
+
+ if ($isphp5)
+ $dates .= sprintf('%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36);
+ else
+ $dates .= sprintf('%s%04d',($gmt<0)?'+':'-',abs($gmt)/36);
+ break;
+
+ case 'H':
+ if ($hour < 10) $dates .= '0'.$hour;
+ else $dates .= $hour;
+ break;
+ case 'h':
+ if ($hour > 12) $hh = $hour - 12;
+ else {
+ if ($hour == 0) $hh = '12';
+ else $hh = $hour;
+ }
+
+ if ($hh < 10) $dates .= '0'.$hh;
+ else $dates .= $hh;
+ break;
+
+ case 'G':
+ $dates .= $hour;
+ break;
+
+ case 'g':
+ if ($hour > 12) $hh = $hour - 12;
+ else {
+ if ($hour == 0) $hh = '12';
+ else $hh = $hour;
+ }
+ $dates .= $hh;
+ break;
+ // MINUTES
+ case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
+ // SECONDS
+ case 'U': $dates .= $d; break;
+ case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
+ // AM/PM
+ // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
+ case 'a':
+ if ($hour>=12) $dates .= 'pm';
+ else $dates .= 'am';
+ break;
+ case 'A':
+ if ($hour>=12) $dates .= 'PM';
+ else $dates .= 'AM';
+ break;
+ default:
+ $dates .= $fmt[$i]; break;
+ // ESCAPE
+ case "\\":
+ $i++;
+ if ($i < $max) $dates .= $fmt[$i];
+ break;
+ }
+ }
+ return $dates;
+}
+
+/**
+ Returns a timestamp given a GMT/UTC time.
+ Note that $is_dst is not implemented and is ignored.
+*/
+function adodb_gmmktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false)
+{
+ return adodb_mktime($hr,$min,$sec,$mon,$day,$year,$is_dst,true);
+}
+
+/**
+ Return a timestamp given a local time. Originally by jackbbs.
+ Note that $is_dst is not implemented and is ignored.
+
+ Not a very fast algorithm - O(n) operation. Could be optimized to O(1).
+*/
+function adodb_mktime($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_dst=false,$is_gmt=false)
+{
+ if (!defined('ADODB_TEST_DATES')) {
+
+ if ($mon === false) {
+ return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec);
+ }
+
+ // for windows, we don't check 1970 because with timezone differences,
+ // 1 Jan 1970 could generate negative timestamp, which is illegal
+ if (1971 < $year && $year < 2038
+ || !defined('ADODB_NO_NEGATIVE_TS') && (1901 < $year && $year < 2038)
+ ) {
+ return $is_gmt ?
+ @gmmktime($hr,$min,$sec,$mon,$day,$year):
+ @mktime($hr,$min,$sec,$mon,$day,$year);
+ }
+ }
+
+ $gmt_different = ($is_gmt) ? 0 : adodb_get_gmt_diff();
+
+ /*
+ # disabled because some people place large values in $sec.
+ # however we need it for $mon because we use an array...
+ $hr = intval($hr);
+ $min = intval($min);
+ $sec = intval($sec);
+ */
+ $mon = intval($mon);
+ $day = intval($day);
+ $year = intval($year);
+
+
+ $year = adodb_year_digit_check($year);
+
+ if ($mon > 12) {
+ $y = floor($mon / 12);
+ $year += $y;
+ $mon -= $y*12;
+ } else if ($mon < 1) {
+ $y = ceil((1-$mon) / 12);
+ $year -= $y;
+ $mon += $y*12;
+ }
+
+ $_day_power = 86400;
+ $_hour_power = 3600;
+ $_min_power = 60;
+
+ $_month_table_normal = array("",31,28,31,30,31,30,31,31,30,31,30,31);
+ $_month_table_leaf = array("",31,29,31,30,31,30,31,31,30,31,30,31);
+
+ $_total_date = 0;
+ if ($year >= 1970) {
+ for ($a = 1970 ; $a <= $year; $a++) {
+ $leaf = _adodb_is_leap_year($a);
+ if ($leaf == true) {
+ $loop_table = $_month_table_leaf;
+ $_add_date = 366;
+ } else {
+ $loop_table = $_month_table_normal;
+ $_add_date = 365;
+ }
+ if ($a < $year) {
+ $_total_date += $_add_date;
+ } else {
+ for($b=1;$b<$mon;$b++) {
+ $_total_date += $loop_table[$b];
+ }
+ }
+ }
+ $_total_date +=$day-1;
+ $ret = $_total_date * $_day_power + $hr * $_hour_power + $min * $_min_power + $sec + $gmt_different;
+
+ } else {
+ for ($a = 1969 ; $a >= $year; $a--) {
+ $leaf = _adodb_is_leap_year($a);
+ if ($leaf == true) {
+ $loop_table = $_month_table_leaf;
+ $_add_date = 366;
+ } else {
+ $loop_table = $_month_table_normal;
+ $_add_date = 365;
+ }
+ if ($a > $year) { $_total_date += $_add_date;
+ } else {
+ for($b=12;$b>$mon;$b--) {
+ $_total_date += $loop_table[$b];
+ }
+ }
+ }
+ $_total_date += $loop_table[$mon] - $day;
+
+ $_day_time = $hr * $_hour_power + $min * $_min_power + $sec;
+ $_day_time = $_day_power - $_day_time;
+ $ret = -( $_total_date * $_day_power + $_day_time - $gmt_different);
+ if ($ret < -12220185600) $ret += 10*86400; // if earlier than 5 Oct 1582 - gregorian correction
+ else if ($ret < -12219321600) $ret = -12219321600; // if in limbo, reset to 15 Oct 1582.
+ }
+ //print " dmy=$day/$mon/$year $hr:$min:$sec => " .$ret;
+ return $ret;
+}
+
+function adodb_gmstrftime($fmt, $ts=false)
+{
+ return adodb_strftime($fmt,$ts,true);
+}
+
+// hack - convert to adodb_date
+function adodb_strftime($fmt, $ts=false,$is_gmt=false)
+{
+global $ADODB_DATE_LOCALE;
+
+ if (!defined('ADODB_TEST_DATES')) {
+ if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
+ if (!defined('ADODB_NO_NEGATIVE_TS') || $ts >= 0) // if windows, must be +ve integer
+ return ($is_gmt)? @gmstrftime($fmt,$ts): @strftime($fmt,$ts);
+
+ }
+ }
+
+ if (empty($ADODB_DATE_LOCALE)) {
+ /*
+ $tstr = strtoupper(gmstrftime('%c',31366800)); // 30 Dec 1970, 1 am
+ $sep = substr($tstr,2,1);
+ $hasAM = strrpos($tstr,'M') !== false;
+ */
+ # see http://phplens.com/lens/lensforum/msgs.php?id=14865 for reasoning, and changelog for version 0.24
+ $dstr = gmstrftime('%x',31366800); // 30 Dec 1970, 1 am
+ $sep = substr($dstr,2,1);
+ $tstr = strtoupper(gmstrftime('%X',31366800)); // 30 Dec 1970, 1 am
+ $hasAM = strrpos($tstr,'M') !== false;
+
+ $ADODB_DATE_LOCALE = array();
+ $ADODB_DATE_LOCALE[] = strncmp($tstr,'30',2) == 0 ? 'd'.$sep.'m'.$sep.'y' : 'm'.$sep.'d'.$sep.'y';
+ $ADODB_DATE_LOCALE[] = ($hasAM) ? 'h:i:s a' : 'H:i:s';
+
+ }
+ $inpct = false;
+ $fmtdate = '';
+ for ($i=0,$max = strlen($fmt); $i < $max; $i++) {
+ $ch = $fmt[$i];
+ if ($ch == '%') {
+ if ($inpct) {
+ $fmtdate .= '%';
+ $inpct = false;
+ } else
+ $inpct = true;
+ } else if ($inpct) {
+
+ $inpct = false;
+ switch($ch) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'E':
+ case 'O':
+ /* ignore format modifiers */
+ $inpct = true;
+ break;
+
+ case 'a': $fmtdate .= 'D'; break;
+ case 'A': $fmtdate .= 'l'; break;
+ case 'h':
+ case 'b': $fmtdate .= 'M'; break;
+ case 'B': $fmtdate .= 'F'; break;
+ case 'c': $fmtdate .= $ADODB_DATE_LOCALE[0].$ADODB_DATE_LOCALE[1]; break;
+ case 'C': $fmtdate .= '\C?'; break; // century
+ case 'd': $fmtdate .= 'd'; break;
+ case 'D': $fmtdate .= 'm/d/y'; break;
+ case 'e': $fmtdate .= 'j'; break;
+ case 'g': $fmtdate .= '\g?'; break; //?
+ case 'G': $fmtdate .= '\G?'; break; //?
+ case 'H': $fmtdate .= 'H'; break;
+ case 'I': $fmtdate .= 'h'; break;
+ case 'j': $fmtdate .= '?z'; $parsej = true; break; // wrong as j=1-based, z=0-basd
+ case 'm': $fmtdate .= 'm'; break;
+ case 'M': $fmtdate .= 'i'; break;
+ case 'n': $fmtdate .= "\n"; break;
+ case 'p': $fmtdate .= 'a'; break;
+ case 'r': $fmtdate .= 'h:i:s a'; break;
+ case 'R': $fmtdate .= 'H:i:s'; break;
+ case 'S': $fmtdate .= 's'; break;
+ case 't': $fmtdate .= "\t"; break;
+ case 'T': $fmtdate .= 'H:i:s'; break;
+ case 'u': $fmtdate .= '?u'; $parseu = true; break; // wrong strftime=1-based, date=0-based
+ case 'U': $fmtdate .= '?U'; $parseU = true; break;// wrong strftime=1-based, date=0-based
+ case 'x': $fmtdate .= $ADODB_DATE_LOCALE[0]; break;
+ case 'X': $fmtdate .= $ADODB_DATE_LOCALE[1]; break;
+ case 'w': $fmtdate .= '?w'; $parseu = true; break; // wrong strftime=1-based, date=0-based
+ case 'W': $fmtdate .= '?W'; $parseU = true; break;// wrong strftime=1-based, date=0-based
+ case 'y': $fmtdate .= 'y'; break;
+ case 'Y': $fmtdate .= 'Y'; break;
+ case 'Z': $fmtdate .= 'T'; break;
+ }
+ } else if (('A' <= ($ch) && ($ch) <= 'Z' ) || ('a' <= ($ch) && ($ch) <= 'z' ))
+ $fmtdate .= "\\".$ch;
+ else
+ $fmtdate .= $ch;
+ }
+ //echo "fmt=",$fmtdate,"<br>";
+ if ($ts === false) $ts = time();
+ $ret = adodb_date($fmtdate, $ts, $is_gmt);
+ return $ret;
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-xmlschema.inc.php b/lib/adodb/adodb-xmlschema.inc.php
new file mode 100644
index 0000000..388e3d8
--- /dev/null
+++ b/lib/adodb/adodb-xmlschema.inc.php
@@ -0,0 +1,2221 @@
+<?php
+// Copyright (c) 2004 ars Cognita Inc., all rights reserved
+/* ******************************************************************************
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+*******************************************************************************/
+/**
+ * xmlschema is a class that allows the user to quickly and easily
+ * build a database on any ADOdb-supported platform using a simple
+ * XML schema.
+ *
+ * Last Editor: $Author: jlim $
+ * @author Richard Tango-Lowy & Dan Cech
+ * @version $Revision: 1.12 $
+ *
+ * @package axmls
+ * @tutorial getting_started.pkg
+ */
+
+function _file_get_contents($file)
+{
+ if (function_exists('file_get_contents')) return file_get_contents($file);
+
+ $f = fopen($file,'r');
+ if (!$f) return '';
+ $t = '';
+
+ while ($s = fread($f,100000)) $t .= $s;
+ fclose($f);
+ return $t;
+}
+
+
+/**
+* Debug on or off
+*/
+if( !defined( 'XMLS_DEBUG' ) ) {
+ define( 'XMLS_DEBUG', FALSE );
+}
+
+/**
+* Default prefix key
+*/
+if( !defined( 'XMLS_PREFIX' ) ) {
+ define( 'XMLS_PREFIX', '%%P' );
+}
+
+/**
+* Maximum length allowed for object prefix
+*/
+if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
+ define( 'XMLS_PREFIX_MAXLEN', 10 );
+}
+
+/**
+* Execute SQL inline as it is generated
+*/
+if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
+ define( 'XMLS_EXECUTE_INLINE', FALSE );
+}
+
+/**
+* Continue SQL Execution if an error occurs?
+*/
+if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
+ define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
+}
+
+/**
+* Current Schema Version
+*/
+if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
+ define( 'XMLS_SCHEMA_VERSION', '0.2' );
+}
+
+/**
+* Default Schema Version. Used for Schemas without an explicit version set.
+*/
+if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
+ define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
+}
+
+/**
+* Default Schema Version. Used for Schemas without an explicit version set.
+*/
+if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
+ define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
+}
+
+/**
+* Include the main ADODB library
+*/
+if( !defined( '_ADODB_LAYER' ) ) {
+ require( 'adodb.inc.php' );
+ require( 'adodb-datadict.inc.php' );
+}
+
+/**
+* Abstract DB Object. This class provides basic methods for database objects, such
+* as tables and indexes.
+*
+* @package axmls
+* @access private
+*/
+class dbObject {
+
+ /**
+ * var object Parent
+ */
+ var $parent;
+
+ /**
+ * var string current element
+ */
+ var $currentElement;
+
+ /**
+ * NOP
+ */
+ function dbObject( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+ }
+
+ /**
+ * XML Callback to process start elements
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+
+ }
+
+ function create() {
+ return array();
+ }
+
+ /**
+ * Destroys the object
+ */
+ function destroy() {
+ unset( $this );
+ }
+
+ /**
+ * Checks whether the specified RDBMS is supported by the current
+ * database object or its ranking ancestor.
+ *
+ * @param string $platform RDBMS platform name (from ADODB platform list).
+ * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
+ */
+ function supportedPlatform( $platform = NULL ) {
+ return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
+ }
+
+ /**
+ * Returns the prefix set by the ranking ancestor of the database object.
+ *
+ * @param string $name Prefix string.
+ * @return string Prefix.
+ */
+ function prefix( $name = '' ) {
+ return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
+ }
+
+ /**
+ * Extracts a field ID from the specified field.
+ *
+ * @param string $field Field.
+ * @return string Field ID.
+ */
+ function FieldID( $field ) {
+ return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
+ }
+}
+
+/**
+* Creates a table object in ADOdb's datadict format
+*
+* This class stores information about a database table. As charactaristics
+* of the table are loaded from the external source, methods and properties
+* of this class are used to build up the table description in ADOdb's
+* datadict format.
+*
+* @package axmls
+* @access private
+*/
+class dbTable extends dbObject {
+
+ /**
+ * @var string Table name
+ */
+ var $name;
+
+ /**
+ * @var array Field specifier: Meta-information about each field
+ */
+ var $fields = array();
+
+ /**
+ * @var array List of table indexes.
+ */
+ var $indexes = array();
+
+ /**
+ * @var array Table options: Table-level options
+ */
+ var $opts = array();
+
+ /**
+ * @var string Field index: Keeps track of which field is currently being processed
+ */
+ var $current_field;
+
+ /**
+ * @var boolean Mark table for destruction
+ * @access private
+ */
+ var $drop_table;
+
+ /**
+ * @var boolean Mark field for destruction (not yet implemented)
+ * @access private
+ */
+ var $drop_field = array();
+
+ /**
+ * Iniitializes a new table object.
+ *
+ * @param string $prefix DB Object prefix
+ * @param array $attributes Array of table attributes.
+ */
+ function dbTable( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+ $this->name = $this->prefix($attributes['NAME']);
+ }
+
+ /**
+ * XML Callback to process start elements. Elements currently
+ * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT.
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ $this->currentElement = strtoupper( $tag );
+
+ switch( $this->currentElement ) {
+ case 'INDEX':
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ xml_set_object( $parser, $this->addIndex( $attributes ) );
+ }
+ break;
+ case 'DATA':
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ xml_set_object( $parser, $this->addData( $attributes ) );
+ }
+ break;
+ case 'DROP':
+ $this->drop();
+ break;
+ case 'FIELD':
+ // Add a field
+ $fieldName = $attributes['NAME'];
+ $fieldType = $attributes['TYPE'];
+ $fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL;
+ $fieldOpts = isset( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL;
+
+ $this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
+ break;
+ case 'KEY':
+ case 'NOTNULL':
+ case 'AUTOINCREMENT':
+ // Add a field option
+ $this->addFieldOpt( $this->current_field, $this->currentElement );
+ break;
+ case 'DEFAULT':
+ // Add a field option to the table object
+
+ // Work around ADOdb datadict issue that misinterprets empty strings.
+ if( $attributes['VALUE'] == '' ) {
+ $attributes['VALUE'] = " '' ";
+ }
+
+ $this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] );
+ break;
+ case 'DEFDATE':
+ case 'DEFTIMESTAMP':
+ // Add a field option to the table object
+ $this->addFieldOpt( $this->current_field, $this->currentElement );
+ break;
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ switch( $this->currentElement ) {
+ // Table constraint
+ case 'CONSTRAINT':
+ if( isset( $this->current_field ) ) {
+ $this->addFieldOpt( $this->current_field, $this->currentElement, $cdata );
+ } else {
+ $this->addTableOpt( $cdata );
+ }
+ break;
+ // Table option
+ case 'OPT':
+ $this->addTableOpt( $cdata );
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+ $this->currentElement = '';
+
+ switch( strtoupper( $tag ) ) {
+ case 'TABLE':
+ $this->parent->addSQL( $this->create( $this->parent ) );
+ xml_set_object( $parser, $this->parent );
+ $this->destroy();
+ break;
+ case 'FIELD':
+ unset($this->current_field);
+ break;
+
+ }
+ }
+
+ /**
+ * Adds an index to a table object
+ *
+ * @param array $attributes Index attributes
+ * @return object dbIndex object
+ */
+ function &addIndex( $attributes ) {
+ $name = strtoupper( $attributes['NAME'] );
+ $this->indexes[$name] =& new dbIndex( $this, $attributes );
+ return $this->indexes[$name];
+ }
+
+ /**
+ * Adds data to a table object
+ *
+ * @param array $attributes Data attributes
+ * @return object dbData object
+ */
+ function &addData( $attributes ) {
+ if( !isset( $this->data ) ) {
+ $this->data =& new dbData( $this, $attributes );
+ }
+ return $this->data;
+ }
+
+ /**
+ * Adds a field to a table object
+ *
+ * $name is the name of the table to which the field should be added.
+ * $type is an ADODB datadict field type. The following field types
+ * are supported as of ADODB 3.40:
+ * - C: varchar
+ * - X: CLOB (character large object) or largest varchar size
+ * if CLOB is not supported
+ * - C2: Multibyte varchar
+ * - X2: Multibyte CLOB
+ * - B: BLOB (binary large object)
+ * - D: Date (some databases do not support this, and we return a datetime type)
+ * - T: Datetime or Timestamp
+ * - L: Integer field suitable for storing booleans (0 or 1)
+ * - I: Integer (mapped to I4)
+ * - I1: 1-byte integer
+ * - I2: 2-byte integer
+ * - I4: 4-byte integer
+ * - I8: 8-byte integer
+ * - F: Floating point number
+ * - N: Numeric or decimal number
+ *
+ * @param string $name Name of the table to which the field will be added.
+ * @param string $type ADODB datadict field type.
+ * @param string $size Field size
+ * @param array $opts Field options array
+ * @return array Field specifier array
+ */
+ function addField( $name, $type, $size = NULL, $opts = NULL ) {
+ $field_id = $this->FieldID( $name );
+
+ // Set the field index so we know where we are
+ $this->current_field = $field_id;
+
+ // Set the field name (required)
+ $this->fields[$field_id]['NAME'] = $name;
+
+ // Set the field type (required)
+ $this->fields[$field_id]['TYPE'] = $type;
+
+ // Set the field size (optional)
+ if( isset( $size ) ) {
+ $this->fields[$field_id]['SIZE'] = $size;
+ }
+
+ // Set the field options
+ if( isset( $opts ) ) {
+ $this->fields[$field_id]['OPTS'][] = $opts;
+ }
+ }
+
+ /**
+ * Adds a field option to the current field specifier
+ *
+ * This method adds a field option allowed by the ADOdb datadict
+ * and appends it to the given field.
+ *
+ * @param string $field Field name
+ * @param string $opt ADOdb field option
+ * @param mixed $value Field option value
+ * @return array Field specifier array
+ */
+ function addFieldOpt( $field, $opt, $value = NULL ) {
+ if( !isset( $value ) ) {
+ $this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
+ // Add the option and value
+ } else {
+ $this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value );
+ }
+ }
+
+ /**
+ * Adds an option to the table
+ *
+ * This method takes a comma-separated list of table-level options
+ * and appends them to the table object.
+ *
+ * @param string $opt Table option
+ * @return array Options
+ */
+ function addTableOpt( $opt ) {
+ $this->opts[] = $opt;
+
+ return $this->opts;
+ }
+
+ /**
+ * Generates the SQL that will create the table in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing table creation SQL
+ */
+ function create( &$xmls ) {
+ $sql = array();
+
+ // drop any existing indexes
+ if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
+ foreach( $legacy_indexes as $index => $index_details ) {
+ $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
+ }
+ }
+
+ // remove fields to be dropped from table object
+ foreach( $this->drop_field as $field ) {
+ unset( $this->fields[$field] );
+ }
+
+ // if table exists
+ if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
+ // drop table
+ if( $this->drop_table ) {
+ $sql[] = $xmls->dict->DropTableSQL( $this->name );
+
+ return $sql;
+ }
+
+ // drop any existing fields not in schema
+ foreach( $legacy_fields as $field_id => $field ) {
+ if( !isset( $this->fields[$field_id] ) ) {
+ $sql[] = $xmls->dict->DropColumnSQL( $this->name, '`'.$field->name.'`' );
+ }
+ }
+ // if table doesn't exist
+ } else {
+ if( $this->drop_table ) {
+ return $sql;
+ }
+
+ $legacy_fields = array();
+ }
+
+ // Loop through the field specifier array, building the associative array for the field options
+ $fldarray = array();
+
+ foreach( $this->fields as $field_id => $finfo ) {
+ // Set an empty size if it isn't supplied
+ if( !isset( $finfo['SIZE'] ) ) {
+ $finfo['SIZE'] = '';
+ }
+
+ // Initialize the field array with the type and size
+ $fldarray[$field_id] = array(
+ 'NAME' => $finfo['NAME'],
+ 'TYPE' => $finfo['TYPE'],
+ 'SIZE' => $finfo['SIZE']
+ );
+
+ // Loop through the options array and add the field options.
+ if( isset( $finfo['OPTS'] ) ) {
+ foreach( $finfo['OPTS'] as $opt ) {
+ // Option has an argument.
+ if( is_array( $opt ) ) {
+ $key = key( $opt );
+ $value = $opt[key( $opt )];
+ @$fldarray[$field_id][$key] .= $value;
+ // Option doesn't have arguments
+ } else {
+ $fldarray[$field_id][$opt] = $opt;
+ }
+ }
+ }
+ }
+
+ if( empty( $legacy_fields ) ) {
+ // Create the new table
+ $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
+ logMsg( end( $sql ), 'Generated CreateTableSQL' );
+ } else {
+ // Upgrade an existing table
+ logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
+ switch( $xmls->upgrade ) {
+ // Use ChangeTableSQL
+ case 'ALTER':
+ logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
+ $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
+ break;
+ case 'REPLACE':
+ logMsg( 'Doing upgrade REPLACE (testing)' );
+ $sql[] = $xmls->dict->DropTableSQL( $this->name );
+ $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
+ break;
+ // ignore table
+ default:
+ return array();
+ }
+ }
+
+ foreach( $this->indexes as $index ) {
+ $sql[] = $index->create( $xmls );
+ }
+
+ if( isset( $this->data ) ) {
+ $sql[] = $this->data->create( $xmls );
+ }
+
+ return $sql;
+ }
+
+ /**
+ * Marks a field or table for destruction
+ */
+ function drop() {
+ if( isset( $this->current_field ) ) {
+ // Drop the current field
+ logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
+ // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
+ $this->drop_field[$this->current_field] = $this->current_field;
+ } else {
+ // Drop the current table
+ logMsg( "Dropping table '{$this->name}'" );
+ // $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
+ $this->drop_table = TRUE;
+ }
+ }
+}
+
+/**
+* Creates an index object in ADOdb's datadict format
+*
+* This class stores information about a database index. As charactaristics
+* of the index are loaded from the external source, methods and properties
+* of this class are used to build up the index description in ADOdb's
+* datadict format.
+*
+* @package axmls
+* @access private
+*/
+class dbIndex extends dbObject {
+
+ /**
+ * @var string Index name
+ */
+ var $name;
+
+ /**
+ * @var array Index options: Index-level options
+ */
+ var $opts = array();
+
+ /**
+ * @var array Indexed fields: Table columns included in this index
+ */
+ var $columns = array();
+
+ /**
+ * @var boolean Mark index for destruction
+ * @access private
+ */
+ var $drop = FALSE;
+
+ /**
+ * Initializes the new dbIndex object.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ *
+ * @internal
+ */
+ function dbIndex( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+
+ $this->name = $this->prefix ($attributes['NAME']);
+ }
+
+ /**
+ * XML Callback to process start elements
+ *
+ * Processes XML opening tags.
+ * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ $this->currentElement = strtoupper( $tag );
+
+ switch( $this->currentElement ) {
+ case 'DROP':
+ $this->drop();
+ break;
+ case 'CLUSTERED':
+ case 'BITMAP':
+ case 'UNIQUE':
+ case 'FULLTEXT':
+ case 'HASH':
+ // Add index Option
+ $this->addIndexOpt( $this->currentElement );
+ break;
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * Processes XML cdata.
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ switch( $this->currentElement ) {
+ // Index field name
+ case 'COL':
+ $this->addField( $cdata );
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+ $this->currentElement = '';
+
+ switch( strtoupper( $tag ) ) {
+ case 'INDEX':
+ xml_set_object( $parser, $this->parent );
+ break;
+ }
+ }
+
+ /**
+ * Adds a field to the index
+ *
+ * @param string $name Field name
+ * @return string Field list
+ */
+ function addField( $name ) {
+ $this->columns[$this->FieldID( $name )] = $name;
+
+ // Return the field list
+ return $this->columns;
+ }
+
+ /**
+ * Adds options to the index
+ *
+ * @param string $opt Comma-separated list of index options.
+ * @return string Option list
+ */
+ function addIndexOpt( $opt ) {
+ $this->opts[] = $opt;
+
+ // Return the options list
+ return $this->opts;
+ }
+
+ /**
+ * Generates the SQL that will create the index in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing index creation SQL
+ */
+ function create( &$xmls ) {
+ if( $this->drop ) {
+ return NULL;
+ }
+
+ // eliminate any columns that aren't in the table
+ foreach( $this->columns as $id => $col ) {
+ if( !isset( $this->parent->fields[$id] ) ) {
+ unset( $this->columns[$id] );
+ }
+ }
+
+ return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
+ }
+
+ /**
+ * Marks an index for destruction
+ */
+ function drop() {
+ $this->drop = TRUE;
+ }
+}
+
+/**
+* Creates a data object in ADOdb's datadict format
+*
+* This class stores information about table data.
+*
+* @package axmls
+* @access private
+*/
+class dbData extends dbObject {
+
+ var $data = array();
+
+ var $row;
+
+ /**
+ * Initializes the new dbIndex object.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ *
+ * @internal
+ */
+ function dbData( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+ }
+
+ /**
+ * XML Callback to process start elements
+ *
+ * Processes XML opening tags.
+ * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ $this->currentElement = strtoupper( $tag );
+
+ switch( $this->currentElement ) {
+ case 'ROW':
+ $this->row = count( $this->data );
+ $this->data[$this->row] = array();
+ break;
+ case 'F':
+ $this->addField($attributes);
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * Processes XML cdata.
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ switch( $this->currentElement ) {
+ // Index field name
+ case 'F':
+ $this->addData( $cdata );
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+ $this->currentElement = '';
+
+ switch( strtoupper( $tag ) ) {
+ case 'DATA':
+ xml_set_object( $parser, $this->parent );
+ break;
+ }
+ }
+
+ /**
+ * Adds a field to the index
+ *
+ * @param string $name Field name
+ * @return string Field list
+ */
+ function addField( $attributes ) {
+ if( isset( $attributes['NAME'] ) ) {
+ $name = $attributes['NAME'];
+ } else {
+ $name = count($this->data[$this->row]);
+ }
+
+ // Set the field index so we know where we are
+ $this->current_field = $this->FieldID( $name );
+ }
+
+ /**
+ * Adds options to the index
+ *
+ * @param string $opt Comma-separated list of index options.
+ * @return string Option list
+ */
+ function addData( $cdata ) {
+ if( !isset( $this->data[$this->row] ) ) {
+ $this->data[$this->row] = array();
+ }
+
+ if( !isset( $this->data[$this->row][$this->current_field] ) ) {
+ $this->data[$this->row][$this->current_field] = '';
+ }
+
+ $this->data[$this->row][$this->current_field] .= $cdata;
+ }
+
+ /**
+ * Generates the SQL that will create the index in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing index creation SQL
+ */
+ function create( &$xmls ) {
+ $table = $xmls->dict->TableName($this->parent->name);
+ $table_field_count = count($this->parent->fields);
+ $sql = array();
+
+ // eliminate any columns that aren't in the table
+ foreach( $this->data as $row ) {
+ $table_fields = $this->parent->fields;
+ $fields = array();
+
+ foreach( $row as $field_id => $field_data ) {
+ if( !array_key_exists( $field_id, $table_fields ) ) {
+ if( is_numeric( $field_id ) ) {
+ $field_id = reset( array_keys( $table_fields ) );
+ } else {
+ continue;
+ }
+ }
+
+ $name = $table_fields[$field_id]['NAME'];
+
+ switch( $table_fields[$field_id]['TYPE'] ) {
+ case 'C':
+ case 'C2':
+ case 'X':
+ case 'X2':
+ $fields[$name] = $xmls->db->qstr( $field_data );
+ break;
+ case 'I':
+ case 'I1':
+ case 'I2':
+ case 'I4':
+ case 'I8':
+ $fields[$name] = intval($field_data);
+ break;
+ default:
+ $fields[$name] = $field_data;
+ }
+
+ unset($table_fields[$field_id]);
+ }
+
+ // check that at least 1 column is specified
+ if( empty( $fields ) ) {
+ continue;
+ }
+
+ // check that no required columns are missing
+ if( count( $fields ) < $table_field_count ) {
+ foreach( $table_fields as $field ) {
+ if (isset( $field['OPTS'] ))
+ if( ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
+ continue(2);
+ }
+ }
+ }
+
+ $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
+ }
+
+ return $sql;
+ }
+}
+
+/**
+* Creates the SQL to execute a list of provided SQL queries
+*
+* @package axmls
+* @access private
+*/
+class dbQuerySet extends dbObject {
+
+ /**
+ * @var array List of SQL queries
+ */
+ var $queries = array();
+
+ /**
+ * @var string String used to build of a query line by line
+ */
+ var $query;
+
+ /**
+ * @var string Query prefix key
+ */
+ var $prefixKey = '';
+
+ /**
+ * @var boolean Auto prefix enable (TRUE)
+ */
+ var $prefixMethod = 'AUTO';
+
+ /**
+ * Initializes the query set.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ */
+ function dbQuerySet( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+
+ // Overrides the manual prefix key
+ if( isset( $attributes['KEY'] ) ) {
+ $this->prefixKey = $attributes['KEY'];
+ }
+
+ $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
+
+ // Enables or disables automatic prefix prepending
+ switch( $prefixMethod ) {
+ case 'AUTO':
+ $this->prefixMethod = 'AUTO';
+ break;
+ case 'MANUAL':
+ $this->prefixMethod = 'MANUAL';
+ break;
+ case 'NONE':
+ $this->prefixMethod = 'NONE';
+ break;
+ }
+ }
+
+ /**
+ * XML Callback to process start elements. Elements currently
+ * processed are: QUERY.
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ $this->currentElement = strtoupper( $tag );
+
+ switch( $this->currentElement ) {
+ case 'QUERY':
+ // Create a new query in a SQL queryset.
+ // Ignore this query set if a platform is specified and it's different than the
+ // current connection platform.
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ $this->newQuery();
+ } else {
+ $this->discardQuery();
+ }
+ break;
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ switch( $this->currentElement ) {
+ // Line of queryset SQL data
+ case 'QUERY':
+ $this->buildQuery( $cdata );
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+ $this->currentElement = '';
+
+ switch( strtoupper( $tag ) ) {
+ case 'QUERY':
+ // Add the finished query to the open query set.
+ $this->addQuery();
+ break;
+ case 'SQL':
+ $this->parent->addSQL( $this->create( $this->parent ) );
+ xml_set_object( $parser, $this->parent );
+ $this->destroy();
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * Re-initializes the query.
+ *
+ * @return boolean TRUE
+ */
+ function newQuery() {
+ $this->query = '';
+
+ return TRUE;
+ }
+
+ /**
+ * Discards the existing query.
+ *
+ * @return boolean TRUE
+ */
+ function discardQuery() {
+ unset( $this->query );
+
+ return TRUE;
+ }
+
+ /**
+ * Appends a line to a query that is being built line by line
+ *
+ * @param string $data Line of SQL data or NULL to initialize a new query
+ * @return string SQL query string.
+ */
+ function buildQuery( $sql = NULL ) {
+ if( !isset( $this->query ) OR empty( $sql ) ) {
+ return FALSE;
+ }
+
+ $this->query .= $sql;
+
+ return $this->query;
+ }
+
+ /**
+ * Adds a completed query to the query list
+ *
+ * @return string SQL of added query
+ */
+ function addQuery() {
+ if( !isset( $this->query ) ) {
+ return FALSE;
+ }
+
+ $this->queries[] = $return = trim($this->query);
+
+ unset( $this->query );
+
+ return $return;
+ }
+
+ /**
+ * Creates and returns the current query set
+ *
+ * @param object $xmls adoSchema object
+ * @return array Query set
+ */
+ function create( &$xmls ) {
+ foreach( $this->queries as $id => $query ) {
+ switch( $this->prefixMethod ) {
+ case 'AUTO':
+ // Enable auto prefix replacement
+
+ // Process object prefix.
+ // Evaluate SQL statements to prepend prefix to objects
+ $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+ $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+ $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+
+ // SELECT statements aren't working yet
+ #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
+
+ case 'MANUAL':
+ // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
+ // If prefixKey is not set, we use the default constant XMLS_PREFIX
+ if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
+ // Enable prefix override
+ $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
+ } else {
+ // Use default replacement
+ $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
+ }
+ }
+
+ $this->queries[$id] = trim( $query );
+ }
+
+ // Return the query set array
+ return $this->queries;
+ }
+
+ /**
+ * Rebuilds the query with the prefix attached to any objects
+ *
+ * @param string $regex Regex used to add prefix
+ * @param string $query SQL query string
+ * @param string $prefix Prefix to be appended to tables, indices, etc.
+ * @return string Prefixed SQL query string.
+ */
+ function prefixQuery( $regex, $query, $prefix = NULL ) {
+ if( !isset( $prefix ) ) {
+ return $query;
+ }
+
+ if( preg_match( $regex, $query, $match ) ) {
+ $preamble = $match[1];
+ $postamble = $match[5];
+ $objectList = explode( ',', $match[3] );
+ // $prefix = $prefix . '_';
+
+ $prefixedList = '';
+
+ foreach( $objectList as $object ) {
+ if( $prefixedList !== '' ) {
+ $prefixedList .= ', ';
+ }
+
+ $prefixedList .= $prefix . trim( $object );
+ }
+
+ $query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
+ }
+
+ return $query;
+ }
+}
+
+/**
+* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
+*
+* This class is used to load and parse the XML file, to create an array of SQL statements
+* that can be used to build a database, and to build the database using the SQL array.
+*
+* @tutorial getting_started.pkg
+*
+* @author Richard Tango-Lowy & Dan Cech
+* @version $Revision: 1.12 $
+*
+* @package axmls
+*/
+class adoSchema {
+
+ /**
+ * @var array Array containing SQL queries to generate all objects
+ * @access private
+ */
+ var $sqlArray;
+
+ /**
+ * @var object ADOdb connection object
+ * @access private
+ */
+ var $db;
+
+ /**
+ * @var object ADOdb Data Dictionary
+ * @access private
+ */
+ var $dict;
+
+ /**
+ * @var string Current XML element
+ * @access private
+ */
+ var $currentElement = '';
+
+ /**
+ * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
+ * @access private
+ */
+ var $upgrade = '';
+
+ /**
+ * @var string Optional object prefix
+ * @access private
+ */
+ var $objectPrefix = '';
+
+ /**
+ * @var long Original Magic Quotes Runtime value
+ * @access private
+ */
+ var $mgq;
+
+ /**
+ * @var long System debug
+ * @access private
+ */
+ var $debug;
+
+ /**
+ * @var string Regular expression to find schema version
+ * @access private
+ */
+ var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
+
+ /**
+ * @var string Current schema version
+ * @access private
+ */
+ var $schemaVersion;
+
+ /**
+ * @var int Success of last Schema execution
+ */
+ var $success;
+
+ /**
+ * @var bool Execute SQL inline as it is generated
+ */
+ var $executeInline;
+
+ /**
+ * @var bool Continue SQL execution if errors occur
+ */
+ var $continueOnError;
+
+ /**
+ * Creates an adoSchema object
+ *
+ * Creating an adoSchema object is the first step in processing an XML schema.
+ * The only parameter is an ADOdb database connection object, which must already
+ * have been created.
+ *
+ * @param object $db ADOdb database connection object.
+ */
+ function adoSchema( &$db ) {
+ // Initialize the environment
+ $this->mgq = get_magic_quotes_runtime();
+ set_magic_quotes_runtime(0);
+
+ $this->db =& $db;
+ $this->debug = $this->db->debug;
+ $this->dict = NewDataDictionary( $this->db );
+ $this->sqlArray = array();
+ $this->schemaVersion = XMLS_SCHEMA_VERSION;
+ $this->executeInline( XMLS_EXECUTE_INLINE );
+ $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
+ $this->setUpgradeMethod();
+ }
+
+ /**
+ * Sets the method to be used for upgrading an existing database
+ *
+ * Use this method to specify how existing database objects should be upgraded.
+ * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
+ * alter each database object directly, REPLACE attempts to rebuild each object
+ * from scratch, BEST attempts to determine the best upgrade method for each
+ * object, and NONE disables upgrading.
+ *
+ * This method is not yet used by AXMLS, but exists for backward compatibility.
+ * The ALTER method is automatically assumed when the adoSchema object is
+ * instantiated; other upgrade methods are not currently supported.
+ *
+ * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
+ * @returns string Upgrade method used
+ */
+ function SetUpgradeMethod( $method = '' ) {
+ if( !is_string( $method ) ) {
+ return FALSE;
+ }
+
+ $method = strtoupper( $method );
+
+ // Handle the upgrade methods
+ switch( $method ) {
+ case 'ALTER':
+ $this->upgrade = $method;
+ break;
+ case 'REPLACE':
+ $this->upgrade = $method;
+ break;
+ case 'BEST':
+ $this->upgrade = 'ALTER';
+ break;
+ case 'NONE':
+ $this->upgrade = 'NONE';
+ break;
+ default:
+ // Use default if no legitimate method is passed.
+ $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
+ }
+
+ return $this->upgrade;
+ }
+
+ /**
+ * Enables/disables inline SQL execution.
+ *
+ * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
+ * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
+ * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
+ * to apply the schema to the database.
+ *
+ * @param bool $mode execute
+ * @return bool current execution mode
+ *
+ * @see ParseSchema(), ExecuteSchema()
+ */
+ function ExecuteInline( $mode = NULL ) {
+ if( is_bool( $mode ) ) {
+ $this->executeInline = $mode;
+ }
+
+ return $this->executeInline;
+ }
+
+ /**
+ * Enables/disables SQL continue on error.
+ *
+ * Call this method to enable or disable continuation of SQL execution if an error occurs.
+ * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
+ * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
+ * of the schema will continue.
+ *
+ * @param bool $mode execute
+ * @return bool current continueOnError mode
+ *
+ * @see addSQL(), ExecuteSchema()
+ */
+ function ContinueOnError( $mode = NULL ) {
+ if( is_bool( $mode ) ) {
+ $this->continueOnError = $mode;
+ }
+
+ return $this->continueOnError;
+ }
+
+ /**
+ * Loads an XML schema from a file and converts it to SQL.
+ *
+ * Call this method to load the specified schema (see the DTD for the proper format) from
+ * the filesystem and generate the SQL necessary to create the database described.
+ * @see ParseSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute
+ */
+ function ParseSchema( $filename, $returnSchema = FALSE ) {
+ return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
+ }
+
+ /**
+ * Loads an XML schema from a file and converts it to SQL.
+ *
+ * Call this method to load the specified schema from a file (see the DTD for the proper format)
+ * and generate the SQL necessary to create the database described by the schema.
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ *
+ * @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString()
+ * @see ParseSchema(), ParseSchemaString()
+ */
+ function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
+ // Open the file
+ if( !($fp = fopen( $filename, 'r' )) ) {
+ // die( 'Unable to open file' );
+ return FALSE;
+ }
+
+ // do version detection here
+ if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) {
+ return FALSE;
+ }
+
+ if ( $returnSchema )
+ {
+ $xmlstring = '';
+ while( $data = fread( $fp, 100000 ) ) {
+ $xmlstring .= $data;
+ }
+ return $xmlstring;
+ }
+
+ $this->success = 2;
+
+ $xmlParser = $this->create_parser();
+
+ // Process the file
+ while( $data = fread( $fp, 4096 ) ) {
+ if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
+ die( sprintf(
+ "XML error: %s at line %d",
+ xml_error_string( xml_get_error_code( $xmlParser) ),
+ xml_get_current_line_number( $xmlParser)
+ ) );
+ }
+ }
+
+ xml_parser_free( $xmlParser );
+
+ return $this->sqlArray;
+ }
+
+ /**
+ * Converts an XML schema string to SQL.
+ *
+ * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+ * and generate the SQL necessary to create the database described by the schema.
+ * @see ParseSchema()
+ *
+ * @param string $xmlstring XML schema string.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ */
+ function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
+ if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
+ return FALSE;
+ }
+
+ // do version detection here
+ if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) {
+ return FALSE;
+ }
+
+ if ( $returnSchema )
+ {
+ return $xmlstring;
+ }
+
+ $this->success = 2;
+
+ $xmlParser = $this->create_parser();
+
+ if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
+ die( sprintf(
+ "XML error: %s at line %d",
+ xml_error_string( xml_get_error_code( $xmlParser) ),
+ xml_get_current_line_number( $xmlParser)
+ ) );
+ }
+
+ xml_parser_free( $xmlParser );
+
+ return $this->sqlArray;
+ }
+
+ /**
+ * Loads an XML schema from a file and converts it to uninstallation SQL.
+ *
+ * Call this method to load the specified schema (see the DTD for the proper format) from
+ * the filesystem and generate the SQL necessary to remove the database described.
+ * @see RemoveSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute
+ */
+ function RemoveSchema( $filename, $returnSchema = FALSE ) {
+ return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
+ }
+
+ /**
+ * Converts an XML schema string to uninstallation SQL.
+ *
+ * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+ * and generate the SQL necessary to uninstall the database described by the schema.
+ * @see RemoveSchema()
+ *
+ * @param string $schema XML schema string.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ */
+ function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
+
+ // grab current version
+ if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
+ return FALSE;
+ }
+
+ return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema );
+ }
+
+ /**
+ * Applies the current XML schema to the database (post execution).
+ *
+ * Call this method to apply the current schema (generally created by calling
+ * ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes,
+ * and executing other SQL specified in the schema) after parsing.
+ * @see ParseSchema(), ParseSchemaString(), ExecuteInline()
+ *
+ * @param array $sqlArray Array of SQL statements that will be applied rather than
+ * the current schema.
+ * @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
+ * @returns integer 0 if failure, 1 if errors, 2 if successful.
+ */
+ function ExecuteSchema( $sqlArray = NULL, $continueOnErr = NULL ) {
+ if( !is_bool( $continueOnErr ) ) {
+ $continueOnErr = $this->ContinueOnError();
+ }
+
+ if( !isset( $sqlArray ) ) {
+ $sqlArray = $this->sqlArray;
+ }
+
+ if( !is_array( $sqlArray ) ) {
+ $this->success = 0;
+ } else {
+ $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
+ }
+
+ return $this->success;
+ }
+
+ /**
+ * Returns the current SQL array.
+ *
+ * Call this method to fetch the array of SQL queries resulting from
+ * ParseSchema() or ParseSchemaString().
+ *
+ * @param string $format Format: HTML, TEXT, or NONE (PHP array)
+ * @return array Array of SQL statements or FALSE if an error occurs
+ */
+ function PrintSQL( $format = 'NONE' ) {
+ $sqlArray = null;
+ return $this->getSQL( $format, $sqlArray );
+ }
+
+ /**
+ * Saves the current SQL array to the local filesystem as a list of SQL queries.
+ *
+ * Call this method to save the array of SQL queries (generally resulting from a
+ * parsed XML schema) to the filesystem.
+ *
+ * @param string $filename Path and name where the file should be saved.
+ * @return boolean TRUE if save is successful, else FALSE.
+ */
+ function SaveSQL( $filename = './schema.sql' ) {
+
+ if( !isset( $sqlArray ) ) {
+ $sqlArray = $this->sqlArray;
+ }
+ if( !isset( $sqlArray ) ) {
+ return FALSE;
+ }
+
+ $fp = fopen( $filename, "w" );
+
+ foreach( $sqlArray as $key => $query ) {
+ fwrite( $fp, $query . ";\n" );
+ }
+ fclose( $fp );
+ }
+
+ /**
+ * Create an xml parser
+ *
+ * @return object PHP XML parser object
+ *
+ * @access private
+ */
+ function &create_parser() {
+ // Create the parser
+ $xmlParser = xml_parser_create();
+ xml_set_object( $xmlParser, $this );
+
+ // Initialize the XML callback functions
+ xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' );
+ xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
+
+ return $xmlParser;
+ }
+
+ /**
+ * XML Callback to process start elements
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ switch( strtoupper( $tag ) ) {
+ case 'TABLE':
+ $this->obj = new dbTable( $this, $attributes );
+ xml_set_object( $parser, $this->obj );
+ break;
+ case 'SQL':
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ $this->obj = new dbQuerySet( $this, $attributes );
+ xml_set_object( $parser, $this->obj );
+ }
+ break;
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ * @internal
+ */
+ function _tag_close( &$parser, $tag ) {
+
+ }
+
+ /**
+ * Converts an XML schema string to the specified DTD version.
+ *
+ * Call this method to convert a string containing an XML schema to a different AXMLS
+ * DTD version. For instance, to convert a schema created for an pre-1.0 version for
+ * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
+ * parameter is specified, the schema will be converted to the current DTD version.
+ * If the newFile parameter is provided, the converted schema will be written to the specified
+ * file.
+ * @see ConvertSchemaFile()
+ *
+ * @param string $schema String containing XML schema that will be converted.
+ * @param string $newVersion DTD version to convert to.
+ * @param string $newFile File name of (converted) output file.
+ * @return string Converted XML schema or FALSE if an error occurs.
+ */
+ function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
+
+ // grab current version
+ if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
+ return FALSE;
+ }
+
+ if( !isset ($newVersion) ) {
+ $newVersion = $this->schemaVersion;
+ }
+
+ if( $version == $newVersion ) {
+ $result = $schema;
+ } else {
+ $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion);
+ }
+
+ if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
+ fwrite( $fp, $result );
+ fclose( $fp );
+ }
+
+ return $result;
+ }
+
+ // compat for pre-4.3 - jlim
+ function _file_get_contents($path)
+ {
+ if (function_exists('file_get_contents')) return file_get_contents($path);
+ return join('',file($path));
+ }
+
+ /**
+ * Converts an XML schema file to the specified DTD version.
+ *
+ * Call this method to convert the specified XML schema file to a different AXMLS
+ * DTD version. For instance, to convert a schema created for an pre-1.0 version for
+ * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
+ * parameter is specified, the schema will be converted to the current DTD version.
+ * If the newFile parameter is provided, the converted schema will be written to the specified
+ * file.
+ * @see ConvertSchemaString()
+ *
+ * @param string $filename Name of XML schema file that will be converted.
+ * @param string $newVersion DTD version to convert to.
+ * @param string $newFile File name of (converted) output file.
+ * @return string Converted XML schema or FALSE if an error occurs.
+ */
+ function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
+
+ // grab current version
+ if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
+ return FALSE;
+ }
+
+ if( !isset ($newVersion) ) {
+ $newVersion = $this->schemaVersion;
+ }
+
+ if( $version == $newVersion ) {
+ $result = _file_get_contents( $filename );
+
+ // remove unicode BOM if present
+ if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
+ $result = substr( $result, 3 );
+ }
+ } else {
+ $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' );
+ }
+
+ if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
+ fwrite( $fp, $result );
+ fclose( $fp );
+ }
+
+ return $result;
+ }
+
+ function TransformSchema( $schema, $xsl, $schematype='string' )
+ {
+ // Fail if XSLT extension is not available
+ if( ! function_exists( 'xslt_create' ) ) {
+ return FALSE;
+ }
+
+ $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
+
+ // look for xsl
+ if( !is_readable( $xsl_file ) ) {
+ return FALSE;
+ }
+
+ switch( $schematype )
+ {
+ case 'file':
+ if( !is_readable( $schema ) ) {
+ return FALSE;
+ }
+
+ $schema = _file_get_contents( $schema );
+ break;
+ case 'string':
+ default:
+ if( !is_string( $schema ) ) {
+ return FALSE;
+ }
+ }
+
+ $arguments = array (
+ '/_xml' => $schema,
+ '/_xsl' => _file_get_contents( $xsl_file )
+ );
+
+ // create an XSLT processor
+ $xh = xslt_create ();
+
+ // set error handler
+ xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
+
+ // process the schema
+ $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments);
+
+ xslt_free ($xh);
+
+ return $result;
+ }
+
+ /**
+ * Processes XSLT transformation errors
+ *
+ * @param object $parser XML parser object
+ * @param integer $errno Error number
+ * @param integer $level Error level
+ * @param array $fields Error information fields
+ *
+ * @access private
+ */
+ function xslt_error_handler( $parser, $errno, $level, $fields ) {
+ if( is_array( $fields ) ) {
+ $msg = array(
+ 'Message Type' => ucfirst( $fields['msgtype'] ),
+ 'Message Code' => $fields['code'],
+ 'Message' => $fields['msg'],
+ 'Error Number' => $errno,
+ 'Level' => $level
+ );
+
+ switch( $fields['URI'] ) {
+ case 'arg:/_xml':
+ $msg['Input'] = 'XML';
+ break;
+ case 'arg:/_xsl':
+ $msg['Input'] = 'XSL';
+ break;
+ default:
+ $msg['Input'] = $fields['URI'];
+ }
+
+ $msg['Line'] = $fields['line'];
+ } else {
+ $msg = array(
+ 'Message Type' => 'Error',
+ 'Error Number' => $errno,
+ 'Level' => $level,
+ 'Fields' => var_export( $fields, TRUE )
+ );
+ }
+
+ $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n"
+ . '<table>' . "\n";
+
+ foreach( $msg as $label => $details ) {
+ $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
+ }
+
+ $error_details .= '</table>';
+
+ trigger_error( $error_details, E_USER_ERROR );
+ }
+
+ /**
+ * Returns the AXMLS Schema Version of the requested XML schema file.
+ *
+ * Call this method to obtain the AXMLS DTD version of the requested XML schema file.
+ * @see SchemaStringVersion()
+ *
+ * @param string $filename AXMLS schema file
+ * @return string Schema version number or FALSE on error
+ */
+ function SchemaFileVersion( $filename ) {
+ // Open the file
+ if( !($fp = fopen( $filename, 'r' )) ) {
+ // die( 'Unable to open file' );
+ return FALSE;
+ }
+
+ // Process the file
+ while( $data = fread( $fp, 4096 ) ) {
+ if( preg_match( $this->versionRegex, $data, $matches ) ) {
+ return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
+ }
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * Returns the AXMLS Schema Version of the provided XML schema string.
+ *
+ * Call this method to obtain the AXMLS DTD version of the provided XML schema string.
+ * @see SchemaFileVersion()
+ *
+ * @param string $xmlstring XML schema string
+ * @return string Schema version number or FALSE on error
+ */
+ function SchemaStringVersion( $xmlstring ) {
+ if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
+ return FALSE;
+ }
+
+ if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
+ return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * Extracts an XML schema from an existing database.
+ *
+ * Call this method to create an XML schema string from an existing database.
+ * If the data parameter is set to TRUE, AXMLS will include the data from the database
+ * in the schema.
+ *
+ * @param boolean $data Include data in schema dump
+ * @return string Generated XML schema
+ */
+ function ExtractSchema( $data = FALSE ) {
+ $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
+
+ $schema = '<?xml version="1.0"?>' . "\n"
+ . '<schema version="' . $this->schemaVersion . '">' . "\n";
+
+ if( is_array( $tables = $this->db->MetaTables( 'TABLES' ) ) ) {
+ foreach( $tables as $table ) {
+ $schema .= ' <table name="' . $table . '">' . "\n";
+
+ // grab details from database
+ $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE 1=1' );
+ $fields = $this->db->MetaColumns( $table );
+ $indexes = $this->db->MetaIndexes( $table );
+
+ if( is_array( $fields ) ) {
+ foreach( $fields as $details ) {
+ $extra = '';
+ $content = array();
+
+ if( $details->max_length > 0 ) {
+ $extra .= ' size="' . $details->max_length . '"';
+ }
+
+ if( $details->primary_key ) {
+ $content[] = '<KEY/>';
+ } elseif( $details->not_null ) {
+ $content[] = '<NOTNULL/>';
+ }
+
+ if( $details->has_default ) {
+ $content[] = '<DEFAULT value="' . $details->default_value . '"/>';
+ }
+
+ if( $details->auto_increment ) {
+ $content[] = '<AUTOINCREMENT/>';
+ }
+
+ // this stops the creation of 'R' columns,
+ // AUTOINCREMENT is used to create auto columns
+ $details->primary_key = 0;
+ $type = $rs->MetaType( $details );
+
+ $schema .= ' <field name="' . $details->name . '" type="' . $type . '"' . $extra . '>';
+
+ if( !empty( $content ) ) {
+ $schema .= "\n " . implode( "\n ", $content ) . "\n ";
+ }
+
+ $schema .= '</field>' . "\n";
+ }
+ }
+
+ if( is_array( $indexes ) ) {
+ foreach( $indexes as $index => $details ) {
+ $schema .= ' <index name="' . $index . '">' . "\n";
+
+ if( $details['unique'] ) {
+ $schema .= ' <UNIQUE/>' . "\n";
+ }
+
+ foreach( $details['columns'] as $column ) {
+ $schema .= ' <col>' . $column . '</col>' . "\n";
+ }
+
+ $schema .= ' </index>' . "\n";
+ }
+ }
+
+ if( $data ) {
+ $rs = $this->db->Execute( 'SELECT * FROM ' . $table );
+
+ if( is_object( $rs ) ) {
+ $schema .= ' <data>' . "\n";
+
+ while( $row = $rs->FetchRow() ) {
+ foreach( $row as $key => $val ) {
+ $row[$key] = htmlentities($val);
+ }
+
+ $schema .= ' <row><f>' . implode( '</f><f>', $row ) . '</f></row>' . "\n";
+ }
+
+ $schema .= ' </data>' . "\n";
+ }
+ }
+
+ $schema .= ' </table>' . "\n";
+ }
+ }
+
+ $this->db->SetFetchMode( $old_mode );
+
+ $schema .= '</schema>';
+ return $schema;
+ }
+
+ /**
+ * Sets a prefix for database objects
+ *
+ * Call this method to set a standard prefix that will be prepended to all database tables
+ * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
+ *
+ * @param string $prefix Prefix that will be prepended.
+ * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
+ * @return boolean TRUE if successful, else FALSE
+ */
+ function SetPrefix( $prefix = '', $underscore = TRUE ) {
+ switch( TRUE ) {
+ // clear prefix
+ case empty( $prefix ):
+ logMsg( 'Cleared prefix' );
+ $this->objectPrefix = '';
+ return TRUE;
+ // prefix too long
+ case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
+ // prefix contains invalid characters
+ case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
+ logMsg( 'Invalid prefix: ' . $prefix );
+ return FALSE;
+ }
+
+ if( $underscore AND substr( $prefix, -1 ) != '_' ) {
+ $prefix .= '_';
+ }
+
+ // prefix valid
+ logMsg( 'Set prefix: ' . $prefix );
+ $this->objectPrefix = $prefix;
+ return TRUE;
+ }
+
+ /**
+ * Returns an object name with the current prefix prepended.
+ *
+ * @param string $name Name
+ * @return string Prefixed name
+ *
+ * @access private
+ */
+ function prefix( $name = '' ) {
+ // if prefix is set
+ if( !empty( $this->objectPrefix ) ) {
+ // Prepend the object prefix to the table name
+ // prepend after quote if used
+ return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name );
+ }
+
+ // No prefix set. Use name provided.
+ return $name;
+ }
+
+ /**
+ * Checks if element references a specific platform
+ *
+ * @param string $platform Requested platform
+ * @returns boolean TRUE if platform check succeeds
+ *
+ * @access private
+ */
+ function supportedPlatform( $platform = NULL ) {
+ $regex = '/^(\w*\|)*' . $this->db->databaseType . '(\|\w*)*$/';
+
+ if( !isset( $platform ) OR preg_match( $regex, $platform ) ) {
+ logMsg( "Platform $platform is supported" );
+ return TRUE;
+ } else {
+ logMsg( "Platform $platform is NOT supported" );
+ return FALSE;
+ }
+ }
+
+ /**
+ * Clears the array of generated SQL.
+ *
+ * @access private
+ */
+ function clearSQL() {
+ $this->sqlArray = array();
+ }
+
+ /**
+ * Adds SQL into the SQL array.
+ *
+ * @param mixed $sql SQL to Add
+ * @return boolean TRUE if successful, else FALSE.
+ *
+ * @access private
+ */
+ function addSQL( $sql = NULL ) {
+ if( is_array( $sql ) ) {
+ foreach( $sql as $line ) {
+ $this->addSQL( $line );
+ }
+
+ return TRUE;
+ }
+
+ if( is_string( $sql ) ) {
+ $this->sqlArray[] = $sql;
+
+ // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL.
+ if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) {
+ $saved = $this->db->debug;
+ $this->db->debug = $this->debug;
+ $ok = $this->db->Execute( $sql );
+ $this->db->debug = $saved;
+
+ if( !$ok ) {
+ if( $this->debug ) {
+ ADOConnection::outp( $this->db->ErrorMsg() );
+ }
+
+ $this->success = 1;
+ }
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * Gets the SQL array in the specified format.
+ *
+ * @param string $format Format
+ * @return mixed SQL
+ *
+ * @access private
+ */
+ function getSQL( $format = NULL, $sqlArray = NULL ) {
+ if( !is_array( $sqlArray ) ) {
+ $sqlArray = $this->sqlArray;
+ }
+
+ if( !is_array( $sqlArray ) ) {
+ return FALSE;
+ }
+
+ switch( strtolower( $format ) ) {
+ case 'string':
+ case 'text':
+ return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : '';
+ case'html':
+ return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
+ }
+
+ return $this->sqlArray;
+ }
+
+ /**
+ * Destroys an adoSchema object.
+ *
+ * Call this method to clean up after an adoSchema object that is no longer in use.
+ * @deprecated adoSchema now cleans up automatically.
+ */
+ function Destroy() {
+ set_magic_quotes_runtime( $this->mgq );
+ unset( $this );
+ }
+}
+
+/**
+* Message logging function
+*
+* @access private
+*/
+function logMsg( $msg, $title = NULL, $force = FALSE ) {
+ if( XMLS_DEBUG or $force ) {
+ echo '<pre>';
+
+ if( isset( $title ) ) {
+ echo '<h3>' . htmlentities( $title ) . '</h3>';
+ }
+
+ if( is_object( $this ) ) {
+ echo '[' . get_class( $this ) . '] ';
+ }
+
+ print_r( $msg );
+
+ echo '</pre>';
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb-xmlschema03.inc.php b/lib/adodb/adodb-xmlschema03.inc.php
new file mode 100644
index 0000000..ffd4460
--- /dev/null
+++ b/lib/adodb/adodb-xmlschema03.inc.php
@@ -0,0 +1,2403 @@
+<?php
+// Copyright (c) 2004-2005 ars Cognita Inc., all rights reserved
+/* ******************************************************************************
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+*******************************************************************************/
+/**
+ * xmlschema is a class that allows the user to quickly and easily
+ * build a database on any ADOdb-supported platform using a simple
+ * XML schema.
+ *
+ * Last Editor: $Author: jlim $
+ * @author Richard Tango-Lowy & Dan Cech
+ * @version $Revision: 1.62 $
+ *
+ * @package axmls
+ * @tutorial getting_started.pkg
+ */
+
+function _file_get_contents($file)
+{
+ if (function_exists('file_get_contents')) return file_get_contents($file);
+
+ $f = fopen($file,'r');
+ if (!$f) return '';
+ $t = '';
+
+ while ($s = fread($f,100000)) $t .= $s;
+ fclose($f);
+ return $t;
+}
+
+
+/**
+* Debug on or off
+*/
+if( !defined( 'XMLS_DEBUG' ) ) {
+ define( 'XMLS_DEBUG', FALSE );
+}
+
+/**
+* Default prefix key
+*/
+if( !defined( 'XMLS_PREFIX' ) ) {
+ define( 'XMLS_PREFIX', '%%P' );
+}
+
+/**
+* Maximum length allowed for object prefix
+*/
+if( !defined( 'XMLS_PREFIX_MAXLEN' ) ) {
+ define( 'XMLS_PREFIX_MAXLEN', 10 );
+}
+
+/**
+* Execute SQL inline as it is generated
+*/
+if( !defined( 'XMLS_EXECUTE_INLINE' ) ) {
+ define( 'XMLS_EXECUTE_INLINE', FALSE );
+}
+
+/**
+* Continue SQL Execution if an error occurs?
+*/
+if( !defined( 'XMLS_CONTINUE_ON_ERROR' ) ) {
+ define( 'XMLS_CONTINUE_ON_ERROR', FALSE );
+}
+
+/**
+* Current Schema Version
+*/
+if( !defined( 'XMLS_SCHEMA_VERSION' ) ) {
+ define( 'XMLS_SCHEMA_VERSION', '0.3' );
+}
+
+/**
+* Default Schema Version. Used for Schemas without an explicit version set.
+*/
+if( !defined( 'XMLS_DEFAULT_SCHEMA_VERSION' ) ) {
+ define( 'XMLS_DEFAULT_SCHEMA_VERSION', '0.1' );
+}
+
+/**
+* How to handle data rows that already exist in a database during and upgrade.
+* Options are INSERT (attempts to insert duplicate rows), UPDATE (updates existing
+* rows) and IGNORE (ignores existing rows).
+*/
+if( !defined( 'XMLS_MODE_INSERT' ) ) {
+ define( 'XMLS_MODE_INSERT', 0 );
+}
+if( !defined( 'XMLS_MODE_UPDATE' ) ) {
+ define( 'XMLS_MODE_UPDATE', 1 );
+}
+if( !defined( 'XMLS_MODE_IGNORE' ) ) {
+ define( 'XMLS_MODE_IGNORE', 2 );
+}
+if( !defined( 'XMLS_EXISTING_DATA' ) ) {
+ define( 'XMLS_EXISTING_DATA', XMLS_MODE_INSERT );
+}
+
+/**
+* Default Schema Version. Used for Schemas without an explicit version set.
+*/
+if( !defined( 'XMLS_DEFAULT_UPGRADE_METHOD' ) ) {
+ define( 'XMLS_DEFAULT_UPGRADE_METHOD', 'ALTER' );
+}
+
+/**
+* Include the main ADODB library
+*/
+if( !defined( '_ADODB_LAYER' ) ) {
+ require( 'adodb.inc.php' );
+ require( 'adodb-datadict.inc.php' );
+}
+
+/**
+* Abstract DB Object. This class provides basic methods for database objects, such
+* as tables and indexes.
+*
+* @package axmls
+* @access private
+*/
+class dbObject {
+
+ /**
+ * var object Parent
+ */
+ var $parent;
+
+ /**
+ * var string current element
+ */
+ var $currentElement;
+
+ /**
+ * NOP
+ */
+ function dbObject( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+ }
+
+ /**
+ * XML Callback to process start elements
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+
+ }
+
+ function create() {
+ return array();
+ }
+
+ /**
+ * Destroys the object
+ */
+ function destroy() {
+ unset( $this );
+ }
+
+ /**
+ * Checks whether the specified RDBMS is supported by the current
+ * database object or its ranking ancestor.
+ *
+ * @param string $platform RDBMS platform name (from ADODB platform list).
+ * @return boolean TRUE if RDBMS is supported; otherwise returns FALSE.
+ */
+ function supportedPlatform( $platform = NULL ) {
+ return is_object( $this->parent ) ? $this->parent->supportedPlatform( $platform ) : TRUE;
+ }
+
+ /**
+ * Returns the prefix set by the ranking ancestor of the database object.
+ *
+ * @param string $name Prefix string.
+ * @return string Prefix.
+ */
+ function prefix( $name = '' ) {
+ return is_object( $this->parent ) ? $this->parent->prefix( $name ) : $name;
+ }
+
+ /**
+ * Extracts a field ID from the specified field.
+ *
+ * @param string $field Field.
+ * @return string Field ID.
+ */
+ function FieldID( $field ) {
+ return strtoupper( preg_replace( '/^`(.+)`$/', '$1', $field ) );
+ }
+}
+
+/**
+* Creates a table object in ADOdb's datadict format
+*
+* This class stores information about a database table. As charactaristics
+* of the table are loaded from the external source, methods and properties
+* of this class are used to build up the table description in ADOdb's
+* datadict format.
+*
+* @package axmls
+* @access private
+*/
+class dbTable extends dbObject {
+
+ /**
+ * @var string Table name
+ */
+ var $name;
+
+ /**
+ * @var array Field specifier: Meta-information about each field
+ */
+ var $fields = array();
+
+ /**
+ * @var array List of table indexes.
+ */
+ var $indexes = array();
+
+ /**
+ * @var array Table options: Table-level options
+ */
+ var $opts = array();
+
+ /**
+ * @var string Field index: Keeps track of which field is currently being processed
+ */
+ var $current_field;
+
+ /**
+ * @var boolean Mark table for destruction
+ * @access private
+ */
+ var $drop_table;
+
+ /**
+ * @var boolean Mark field for destruction (not yet implemented)
+ * @access private
+ */
+ var $drop_field = array();
+
+ /**
+ * @var array Platform-specific options
+ * @access private
+ */
+ var $currentPlatform = true;
+
+
+ /**
+ * Iniitializes a new table object.
+ *
+ * @param string $prefix DB Object prefix
+ * @param array $attributes Array of table attributes.
+ */
+ function dbTable( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+ $this->name = $this->prefix($attributes['NAME']);
+ }
+
+ /**
+ * XML Callback to process start elements. Elements currently
+ * processed are: INDEX, DROP, FIELD, KEY, NOTNULL, AUTOINCREMENT & DEFAULT.
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ $this->currentElement = strtoupper( $tag );
+
+ switch( $this->currentElement ) {
+ case 'INDEX':
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ xml_set_object( $parser, $this->addIndex( $attributes ) );
+ }
+ break;
+ case 'DATA':
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ xml_set_object( $parser, $this->addData( $attributes ) );
+ }
+ break;
+ case 'DROP':
+ $this->drop();
+ break;
+ case 'FIELD':
+ // Add a field
+ $fieldName = $attributes['NAME'];
+ $fieldType = $attributes['TYPE'];
+ $fieldSize = isset( $attributes['SIZE'] ) ? $attributes['SIZE'] : NULL;
+ $fieldOpts = !empty( $attributes['OPTS'] ) ? $attributes['OPTS'] : NULL;
+
+ $this->addField( $fieldName, $fieldType, $fieldSize, $fieldOpts );
+ break;
+ case 'KEY':
+ case 'NOTNULL':
+ case 'AUTOINCREMENT':
+ case 'DEFDATE':
+ case 'DEFTIMESTAMP':
+ case 'UNSIGNED':
+ // Add a field option
+ $this->addFieldOpt( $this->current_field, $this->currentElement );
+ break;
+ case 'DEFAULT':
+ // Add a field option to the table object
+
+ // Work around ADOdb datadict issue that misinterprets empty strings.
+ if( $attributes['VALUE'] == '' ) {
+ $attributes['VALUE'] = " '' ";
+ }
+
+ $this->addFieldOpt( $this->current_field, $this->currentElement, $attributes['VALUE'] );
+ break;
+ case 'OPT':
+ case 'CONSTRAINT':
+ // Accept platform-specific options
+ $this->currentPlatform = ( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) );
+ break;
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ switch( $this->currentElement ) {
+ // Table/field constraint
+ case 'CONSTRAINT':
+ if( isset( $this->current_field ) ) {
+ $this->addFieldOpt( $this->current_field, $this->currentElement, $cdata );
+ } else {
+ $this->addTableOpt( $cdata );
+ }
+ break;
+ // Table/field option
+ case 'OPT':
+ if( isset( $this->current_field ) ) {
+ $this->addFieldOpt( $this->current_field, $cdata );
+ } else {
+ $this->addTableOpt( $cdata );
+ }
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+ $this->currentElement = '';
+
+ switch( strtoupper( $tag ) ) {
+ case 'TABLE':
+ $this->parent->addSQL( $this->create( $this->parent ) );
+ xml_set_object( $parser, $this->parent );
+ $this->destroy();
+ break;
+ case 'FIELD':
+ unset($this->current_field);
+ break;
+ case 'OPT':
+ case 'CONSTRAINT':
+ $this->currentPlatform = true;
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * Adds an index to a table object
+ *
+ * @param array $attributes Index attributes
+ * @return object dbIndex object
+ */
+ function &addIndex( $attributes ) {
+ $name = strtoupper( $attributes['NAME'] );
+ $this->indexes[$name] =& new dbIndex( $this, $attributes );
+ return $this->indexes[$name];
+ }
+
+ /**
+ * Adds data to a table object
+ *
+ * @param array $attributes Data attributes
+ * @return object dbData object
+ */
+ function &addData( $attributes ) {
+ if( !isset( $this->data ) ) {
+ $this->data =& new dbData( $this, $attributes );
+ }
+ return $this->data;
+ }
+
+ /**
+ * Adds a field to a table object
+ *
+ * $name is the name of the table to which the field should be added.
+ * $type is an ADODB datadict field type. The following field types
+ * are supported as of ADODB 3.40:
+ * - C: varchar
+ * - X: CLOB (character large object) or largest varchar size
+ * if CLOB is not supported
+ * - C2: Multibyte varchar
+ * - X2: Multibyte CLOB
+ * - B: BLOB (binary large object)
+ * - D: Date (some databases do not support this, and we return a datetime type)
+ * - T: Datetime or Timestamp
+ * - L: Integer field suitable for storing booleans (0 or 1)
+ * - I: Integer (mapped to I4)
+ * - I1: 1-byte integer
+ * - I2: 2-byte integer
+ * - I4: 4-byte integer
+ * - I8: 8-byte integer
+ * - F: Floating point number
+ * - N: Numeric or decimal number
+ *
+ * @param string $name Name of the table to which the field will be added.
+ * @param string $type ADODB datadict field type.
+ * @param string $size Field size
+ * @param array $opts Field options array
+ * @return array Field specifier array
+ */
+ function addField( $name, $type, $size = NULL, $opts = NULL ) {
+ $field_id = $this->FieldID( $name );
+
+ // Set the field index so we know where we are
+ $this->current_field = $field_id;
+
+ // Set the field name (required)
+ $this->fields[$field_id]['NAME'] = $name;
+
+ // Set the field type (required)
+ $this->fields[$field_id]['TYPE'] = $type;
+
+ // Set the field size (optional)
+ if( isset( $size ) ) {
+ $this->fields[$field_id]['SIZE'] = $size;
+ }
+
+ // Set the field options
+ if( isset( $opts ) ) {
+ $this->fields[$field_id]['OPTS'] = array($opts);
+ } else {
+ $this->fields[$field_id]['OPTS'] = array();
+ }
+ }
+
+ /**
+ * Adds a field option to the current field specifier
+ *
+ * This method adds a field option allowed by the ADOdb datadict
+ * and appends it to the given field.
+ *
+ * @param string $field Field name
+ * @param string $opt ADOdb field option
+ * @param mixed $value Field option value
+ * @return array Field specifier array
+ */
+ function addFieldOpt( $field, $opt, $value = NULL ) {
+ if( $this->currentPlatform ) {
+ if( !isset( $value ) ) {
+ $this->fields[$this->FieldID( $field )]['OPTS'][] = $opt;
+ // Add the option and value
+ } else {
+ $this->fields[$this->FieldID( $field )]['OPTS'][] = array( $opt => $value );
+ }
+ }
+ }
+
+ /**
+ * Adds an option to the table
+ *
+ * This method takes a comma-separated list of table-level options
+ * and appends them to the table object.
+ *
+ * @param string $opt Table option
+ * @return array Options
+ */
+ function addTableOpt( $opt ) {
+ if( $this->currentPlatform ) {
+ $this->opts[] = $opt;
+ }
+ return $this->opts;
+ }
+
+ /**
+ * Generates the SQL that will create the table in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing table creation SQL
+ */
+ function create( &$xmls ) {
+ $sql = array();
+
+ // drop any existing indexes
+ if( is_array( $legacy_indexes = $xmls->dict->MetaIndexes( $this->name ) ) ) {
+ foreach( $legacy_indexes as $index => $index_details ) {
+ $sql[] = $xmls->dict->DropIndexSQL( $index, $this->name );
+ }
+ }
+
+ // remove fields to be dropped from table object
+ foreach( $this->drop_field as $field ) {
+ unset( $this->fields[$field] );
+ }
+
+ // if table exists
+ if( is_array( $legacy_fields = $xmls->dict->MetaColumns( $this->name ) ) ) {
+ // drop table
+ if( $this->drop_table ) {
+ $sql[] = $xmls->dict->DropTableSQL( $this->name );
+
+ return $sql;
+ }
+
+ // drop any existing fields not in schema
+ foreach( $legacy_fields as $field_id => $field ) {
+ if( !isset( $this->fields[$field_id] ) ) {
+ $sql[] = $xmls->dict->DropColumnSQL( $this->name, $field->name );
+ }
+ }
+ // if table doesn't exist
+ } else {
+ if( $this->drop_table ) {
+ return $sql;
+ }
+
+ $legacy_fields = array();
+ }
+
+ // Loop through the field specifier array, building the associative array for the field options
+ $fldarray = array();
+
+ foreach( $this->fields as $field_id => $finfo ) {
+ // Set an empty size if it isn't supplied
+ if( !isset( $finfo['SIZE'] ) ) {
+ $finfo['SIZE'] = '';
+ }
+
+ // Initialize the field array with the type and size
+ $fldarray[$field_id] = array(
+ 'NAME' => $finfo['NAME'],
+ 'TYPE' => $finfo['TYPE'],
+ 'SIZE' => $finfo['SIZE']
+ );
+
+ // Loop through the options array and add the field options.
+ if( isset( $finfo['OPTS'] ) ) {
+ foreach( $finfo['OPTS'] as $opt ) {
+ // Option has an argument.
+ if( is_array( $opt ) ) {
+ $key = key( $opt );
+ $value = $opt[key( $opt )];
+ @$fldarray[$field_id][$key] .= $value;
+ // Option doesn't have arguments
+ } else {
+ $fldarray[$field_id][$opt] = $opt;
+ }
+ }
+ }
+ }
+
+ if( empty( $legacy_fields ) ) {
+ // Create the new table
+ $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
+ logMsg( end( $sql ), 'Generated CreateTableSQL' );
+ } else {
+ // Upgrade an existing table
+ logMsg( "Upgrading {$this->name} using '{$xmls->upgrade}'" );
+ switch( $xmls->upgrade ) {
+ // Use ChangeTableSQL
+ case 'ALTER':
+ logMsg( 'Generated ChangeTableSQL (ALTERing table)' );
+ $sql[] = $xmls->dict->ChangeTableSQL( $this->name, $fldarray, $this->opts );
+ break;
+ case 'REPLACE':
+ logMsg( 'Doing upgrade REPLACE (testing)' );
+ $sql[] = $xmls->dict->DropTableSQL( $this->name );
+ $sql[] = $xmls->dict->CreateTableSQL( $this->name, $fldarray, $this->opts );
+ break;
+ // ignore table
+ default:
+ return array();
+ }
+ }
+
+ foreach( $this->indexes as $index ) {
+ $sql[] = $index->create( $xmls );
+ }
+
+ if( isset( $this->data ) ) {
+ $sql[] = $this->data->create( $xmls );
+ }
+
+ return $sql;
+ }
+
+ /**
+ * Marks a field or table for destruction
+ */
+ function drop() {
+ if( isset( $this->current_field ) ) {
+ // Drop the current field
+ logMsg( "Dropping field '{$this->current_field}' from table '{$this->name}'" );
+ // $this->drop_field[$this->current_field] = $xmls->dict->DropColumnSQL( $this->name, $this->current_field );
+ $this->drop_field[$this->current_field] = $this->current_field;
+ } else {
+ // Drop the current table
+ logMsg( "Dropping table '{$this->name}'" );
+ // $this->drop_table = $xmls->dict->DropTableSQL( $this->name );
+ $this->drop_table = TRUE;
+ }
+ }
+}
+
+/**
+* Creates an index object in ADOdb's datadict format
+*
+* This class stores information about a database index. As charactaristics
+* of the index are loaded from the external source, methods and properties
+* of this class are used to build up the index description in ADOdb's
+* datadict format.
+*
+* @package axmls
+* @access private
+*/
+class dbIndex extends dbObject {
+
+ /**
+ * @var string Index name
+ */
+ var $name;
+
+ /**
+ * @var array Index options: Index-level options
+ */
+ var $opts = array();
+
+ /**
+ * @var array Indexed fields: Table columns included in this index
+ */
+ var $columns = array();
+
+ /**
+ * @var boolean Mark index for destruction
+ * @access private
+ */
+ var $drop = FALSE;
+
+ /**
+ * Initializes the new dbIndex object.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ *
+ * @internal
+ */
+ function dbIndex( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+
+ $this->name = $this->prefix ($attributes['NAME']);
+ }
+
+ /**
+ * XML Callback to process start elements
+ *
+ * Processes XML opening tags.
+ * Elements currently processed are: DROP, CLUSTERED, BITMAP, UNIQUE, FULLTEXT & HASH.
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ $this->currentElement = strtoupper( $tag );
+
+ switch( $this->currentElement ) {
+ case 'DROP':
+ $this->drop();
+ break;
+ case 'CLUSTERED':
+ case 'BITMAP':
+ case 'UNIQUE':
+ case 'FULLTEXT':
+ case 'HASH':
+ // Add index Option
+ $this->addIndexOpt( $this->currentElement );
+ break;
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * Processes XML cdata.
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ switch( $this->currentElement ) {
+ // Index field name
+ case 'COL':
+ $this->addField( $cdata );
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+ $this->currentElement = '';
+
+ switch( strtoupper( $tag ) ) {
+ case 'INDEX':
+ xml_set_object( $parser, $this->parent );
+ break;
+ }
+ }
+
+ /**
+ * Adds a field to the index
+ *
+ * @param string $name Field name
+ * @return string Field list
+ */
+ function addField( $name ) {
+ $this->columns[$this->FieldID( $name )] = $name;
+
+ // Return the field list
+ return $this->columns;
+ }
+
+ /**
+ * Adds options to the index
+ *
+ * @param string $opt Comma-separated list of index options.
+ * @return string Option list
+ */
+ function addIndexOpt( $opt ) {
+ $this->opts[] = $opt;
+
+ // Return the options list
+ return $this->opts;
+ }
+
+ /**
+ * Generates the SQL that will create the index in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing index creation SQL
+ */
+ function create( &$xmls ) {
+ if( $this->drop ) {
+ return NULL;
+ }
+
+ // eliminate any columns that aren't in the table
+ foreach( $this->columns as $id => $col ) {
+ if( !isset( $this->parent->fields[$id] ) ) {
+ unset( $this->columns[$id] );
+ }
+ }
+
+ return $xmls->dict->CreateIndexSQL( $this->name, $this->parent->name, $this->columns, $this->opts );
+ }
+
+ /**
+ * Marks an index for destruction
+ */
+ function drop() {
+ $this->drop = TRUE;
+ }
+}
+
+/**
+* Creates a data object in ADOdb's datadict format
+*
+* This class stores information about table data, and is called
+* when we need to load field data into a table.
+*
+* @package axmls
+* @access private
+*/
+class dbData extends dbObject {
+
+ var $data = array();
+
+ var $row;
+
+ /**
+ * Initializes the new dbData object.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ *
+ * @internal
+ */
+ function dbData( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+ }
+
+ /**
+ * XML Callback to process start elements
+ *
+ * Processes XML opening tags.
+ * Elements currently processed are: ROW and F (field).
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ $this->currentElement = strtoupper( $tag );
+
+ switch( $this->currentElement ) {
+ case 'ROW':
+ $this->row = count( $this->data );
+ $this->data[$this->row] = array();
+ break;
+ case 'F':
+ $this->addField($attributes);
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * Processes XML cdata.
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ switch( $this->currentElement ) {
+ // Index field name
+ case 'F':
+ $this->addData( $cdata );
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+ $this->currentElement = '';
+
+ switch( strtoupper( $tag ) ) {
+ case 'DATA':
+ xml_set_object( $parser, $this->parent );
+ break;
+ }
+ }
+
+ /**
+ * Adds a field to the insert
+ *
+ * @param string $name Field name
+ * @return string Field list
+ */
+ function addField( $attributes ) {
+ // check we're in a valid row
+ if( !isset( $this->row ) || !isset( $this->data[$this->row] ) ) {
+ return;
+ }
+
+ // Set the field index so we know where we are
+ if( isset( $attributes['NAME'] ) ) {
+ $this->current_field = $this->FieldID( $attributes['NAME'] );
+ } else {
+ $this->current_field = count( $this->data[$this->row] );
+ }
+
+ // initialise data
+ if( !isset( $this->data[$this->row][$this->current_field] ) ) {
+ $this->data[$this->row][$this->current_field] = '';
+ }
+ }
+
+ /**
+ * Adds options to the index
+ *
+ * @param string $opt Comma-separated list of index options.
+ * @return string Option list
+ */
+ function addData( $cdata ) {
+ // check we're in a valid field
+ if ( isset( $this->data[$this->row][$this->current_field] ) ) {
+ // add data to field
+ $this->data[$this->row][$this->current_field] .= $cdata;
+ }
+ }
+
+ /**
+ * Generates the SQL that will add/update the data in the database
+ *
+ * @param object $xmls adoSchema object
+ * @return array Array containing index creation SQL
+ */
+ function create( &$xmls ) {
+ $table = $xmls->dict->TableName($this->parent->name);
+ $table_field_count = count($this->parent->fields);
+ $tables = $xmls->db->MetaTables();
+ $sql = array();
+
+ $ukeys = $xmls->db->MetaPrimaryKeys( $table );
+ if( !empty( $this->parent->indexes ) and !empty( $ukeys ) ) {
+ foreach( $this->parent->indexes as $indexObj ) {
+ if( !in_array( $indexObj->name, $ukeys ) ) $ukeys[] = $indexObj->name;
+ }
+ }
+
+ // eliminate any columns that aren't in the table
+ foreach( $this->data as $row ) {
+ $table_fields = $this->parent->fields;
+ $fields = array();
+ $rawfields = array(); // Need to keep some of the unprocessed data on hand.
+
+ foreach( $row as $field_id => $field_data ) {
+ if( !array_key_exists( $field_id, $table_fields ) ) {
+ if( is_numeric( $field_id ) ) {
+ $field_id = reset( array_keys( $table_fields ) );
+ } else {
+ continue;
+ }
+ }
+
+ $name = $table_fields[$field_id]['NAME'];
+
+ switch( $table_fields[$field_id]['TYPE'] ) {
+ case 'I':
+ case 'I1':
+ case 'I2':
+ case 'I4':
+ case 'I8':
+ $fields[$name] = intval($field_data);
+ break;
+ case 'C':
+ case 'C2':
+ case 'X':
+ case 'X2':
+ default:
+ $fields[$name] = $xmls->db->qstr( $field_data );
+ $rawfields[$name] = $field_data;
+ }
+
+ unset($table_fields[$field_id]);
+
+ }
+
+ // check that at least 1 column is specified
+ if( empty( $fields ) ) {
+ continue;
+ }
+
+ // check that no required columns are missing
+ if( count( $fields ) < $table_field_count ) {
+ foreach( $table_fields as $field ) {
+ if( isset( $field['OPTS'] ) and ( in_array( 'NOTNULL', $field['OPTS'] ) || in_array( 'KEY', $field['OPTS'] ) ) && !in_array( 'AUTOINCREMENT', $field['OPTS'] ) ) {
+ continue(2);
+ }
+ }
+ }
+
+ // The rest of this method deals with updating existing data records.
+
+ if( !in_array( $table, $tables ) or ( $mode = $xmls->existingData() ) == XMLS_MODE_INSERT ) {
+ // Table doesn't yet exist, so it's safe to insert.
+ logMsg( "$table doesn't exist, inserting or mode is INSERT" );
+ $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
+ continue;
+ }
+
+ // Prepare to test for potential violations. Get primary keys and unique indexes
+ $mfields = array_merge( $fields, $rawfields );
+ $keyFields = array_intersect( $ukeys, array_keys( $mfields ) );
+
+ if( empty( $ukeys ) or count( $keyFields ) == 0 ) {
+ // No unique keys in schema, so safe to insert
+ logMsg( "Either schema or data has no unique keys, so safe to insert" );
+ $sql[] = 'INSERT INTO '. $table .' ('. implode( ',', array_keys( $fields ) ) .') VALUES ('. implode( ',', $fields ) .')';
+ continue;
+ }
+
+ // Select record containing matching unique keys.
+ $where = '';
+ foreach( $ukeys as $key ) {
+ if( isset( $mfields[$key] ) and $mfields[$key] ) {
+ if( $where ) $where .= ' AND ';
+ $where .= $key . ' = ' . $xmls->db->qstr( $mfields[$key] );
+ }
+ }
+ $records = $xmls->db->Execute( 'SELECT * FROM ' . $table . ' WHERE ' . $where );
+ switch( $records->RecordCount() ) {
+ case 0:
+ // No matching record, so safe to insert.
+ logMsg( "No matching records. Inserting new row with unique data" );
+ $sql[] = $xmls->db->GetInsertSQL( $records, $mfields );
+ break;
+ case 1:
+ // Exactly one matching record, so we can update if the mode permits.
+ logMsg( "One matching record..." );
+ if( $mode == XMLS_MODE_UPDATE ) {
+ logMsg( "...Updating existing row from unique data" );
+ $sql[] = $xmls->db->GetUpdateSQL( $records, $mfields );
+ }
+ break;
+ default:
+ // More than one matching record; the result is ambiguous, so we must ignore the row.
+ logMsg( "More than one matching record. Ignoring row." );
+ }
+ }
+ return $sql;
+ }
+}
+
+/**
+* Creates the SQL to execute a list of provided SQL queries
+*
+* @package axmls
+* @access private
+*/
+class dbQuerySet extends dbObject {
+
+ /**
+ * @var array List of SQL queries
+ */
+ var $queries = array();
+
+ /**
+ * @var string String used to build of a query line by line
+ */
+ var $query;
+
+ /**
+ * @var string Query prefix key
+ */
+ var $prefixKey = '';
+
+ /**
+ * @var boolean Auto prefix enable (TRUE)
+ */
+ var $prefixMethod = 'AUTO';
+
+ /**
+ * Initializes the query set.
+ *
+ * @param object $parent Parent object
+ * @param array $attributes Attributes
+ */
+ function dbQuerySet( &$parent, $attributes = NULL ) {
+ $this->parent =& $parent;
+
+ // Overrides the manual prefix key
+ if( isset( $attributes['KEY'] ) ) {
+ $this->prefixKey = $attributes['KEY'];
+ }
+
+ $prefixMethod = isset( $attributes['PREFIXMETHOD'] ) ? strtoupper( trim( $attributes['PREFIXMETHOD'] ) ) : '';
+
+ // Enables or disables automatic prefix prepending
+ switch( $prefixMethod ) {
+ case 'AUTO':
+ $this->prefixMethod = 'AUTO';
+ break;
+ case 'MANUAL':
+ $this->prefixMethod = 'MANUAL';
+ break;
+ case 'NONE':
+ $this->prefixMethod = 'NONE';
+ break;
+ }
+ }
+
+ /**
+ * XML Callback to process start elements. Elements currently
+ * processed are: QUERY.
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ $this->currentElement = strtoupper( $tag );
+
+ switch( $this->currentElement ) {
+ case 'QUERY':
+ // Create a new query in a SQL queryset.
+ // Ignore this query set if a platform is specified and it's different than the
+ // current connection platform.
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ $this->newQuery();
+ } else {
+ $this->discardQuery();
+ }
+ break;
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ switch( $this->currentElement ) {
+ // Line of queryset SQL data
+ case 'QUERY':
+ $this->buildQuery( $cdata );
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ */
+ function _tag_close( &$parser, $tag ) {
+ $this->currentElement = '';
+
+ switch( strtoupper( $tag ) ) {
+ case 'QUERY':
+ // Add the finished query to the open query set.
+ $this->addQuery();
+ break;
+ case 'SQL':
+ $this->parent->addSQL( $this->create( $this->parent ) );
+ xml_set_object( $parser, $this->parent );
+ $this->destroy();
+ break;
+ default:
+
+ }
+ }
+
+ /**
+ * Re-initializes the query.
+ *
+ * @return boolean TRUE
+ */
+ function newQuery() {
+ $this->query = '';
+
+ return TRUE;
+ }
+
+ /**
+ * Discards the existing query.
+ *
+ * @return boolean TRUE
+ */
+ function discardQuery() {
+ unset( $this->query );
+
+ return TRUE;
+ }
+
+ /**
+ * Appends a line to a query that is being built line by line
+ *
+ * @param string $data Line of SQL data or NULL to initialize a new query
+ * @return string SQL query string.
+ */
+ function buildQuery( $sql = NULL ) {
+ if( !isset( $this->query ) OR empty( $sql ) ) {
+ return FALSE;
+ }
+
+ $this->query .= $sql;
+
+ return $this->query;
+ }
+
+ /**
+ * Adds a completed query to the query list
+ *
+ * @return string SQL of added query
+ */
+ function addQuery() {
+ if( !isset( $this->query ) ) {
+ return FALSE;
+ }
+
+ $this->queries[] = $return = trim($this->query);
+
+ unset( $this->query );
+
+ return $return;
+ }
+
+ /**
+ * Creates and returns the current query set
+ *
+ * @param object $xmls adoSchema object
+ * @return array Query set
+ */
+ function create( &$xmls ) {
+ foreach( $this->queries as $id => $query ) {
+ switch( $this->prefixMethod ) {
+ case 'AUTO':
+ // Enable auto prefix replacement
+
+ // Process object prefix.
+ // Evaluate SQL statements to prepend prefix to objects
+ $query = $this->prefixQuery( '/^\s*((?is)INSERT\s+(INTO\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+ $query = $this->prefixQuery( '/^\s*((?is)UPDATE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+ $query = $this->prefixQuery( '/^\s*((?is)DELETE\s+(FROM\s+)?)((\w+\s*,?\s*)+)(\s.*$)/', $query, $xmls->objectPrefix );
+
+ // SELECT statements aren't working yet
+ #$data = preg_replace( '/(?ias)(^\s*SELECT\s+.*\s+FROM)\s+(\W\s*,?\s*)+((?i)\s+WHERE.*$)/', "\1 $prefix\2 \3", $data );
+
+ case 'MANUAL':
+ // If prefixKey is set and has a value then we use it to override the default constant XMLS_PREFIX.
+ // If prefixKey is not set, we use the default constant XMLS_PREFIX
+ if( isset( $this->prefixKey ) AND( $this->prefixKey !== '' ) ) {
+ // Enable prefix override
+ $query = str_replace( $this->prefixKey, $xmls->objectPrefix, $query );
+ } else {
+ // Use default replacement
+ $query = str_replace( XMLS_PREFIX , $xmls->objectPrefix, $query );
+ }
+ }
+
+ $this->queries[$id] = trim( $query );
+ }
+
+ // Return the query set array
+ return $this->queries;
+ }
+
+ /**
+ * Rebuilds the query with the prefix attached to any objects
+ *
+ * @param string $regex Regex used to add prefix
+ * @param string $query SQL query string
+ * @param string $prefix Prefix to be appended to tables, indices, etc.
+ * @return string Prefixed SQL query string.
+ */
+ function prefixQuery( $regex, $query, $prefix = NULL ) {
+ if( !isset( $prefix ) ) {
+ return $query;
+ }
+
+ if( preg_match( $regex, $query, $match ) ) {
+ $preamble = $match[1];
+ $postamble = $match[5];
+ $objectList = explode( ',', $match[3] );
+ // $prefix = $prefix . '_';
+
+ $prefixedList = '';
+
+ foreach( $objectList as $object ) {
+ if( $prefixedList !== '' ) {
+ $prefixedList .= ', ';
+ }
+
+ $prefixedList .= $prefix . trim( $object );
+ }
+
+ $query = $preamble . ' ' . $prefixedList . ' ' . $postamble;
+ }
+
+ return $query;
+ }
+}
+
+/**
+* Loads and parses an XML file, creating an array of "ready-to-run" SQL statements
+*
+* This class is used to load and parse the XML file, to create an array of SQL statements
+* that can be used to build a database, and to build the database using the SQL array.
+*
+* @tutorial getting_started.pkg
+*
+* @author Richard Tango-Lowy & Dan Cech
+* @version $Revision: 1.62 $
+*
+* @package axmls
+*/
+class adoSchema {
+
+ /**
+ * @var array Array containing SQL queries to generate all objects
+ * @access private
+ */
+ var $sqlArray;
+
+ /**
+ * @var object ADOdb connection object
+ * @access private
+ */
+ var $db;
+
+ /**
+ * @var object ADOdb Data Dictionary
+ * @access private
+ */
+ var $dict;
+
+ /**
+ * @var string Current XML element
+ * @access private
+ */
+ var $currentElement = '';
+
+ /**
+ * @var string If set (to 'ALTER' or 'REPLACE'), upgrade an existing database
+ * @access private
+ */
+ var $upgrade = '';
+
+ /**
+ * @var string Optional object prefix
+ * @access private
+ */
+ var $objectPrefix = '';
+
+ /**
+ * @var long Original Magic Quotes Runtime value
+ * @access private
+ */
+ var $mgq;
+
+ /**
+ * @var long System debug
+ * @access private
+ */
+ var $debug;
+
+ /**
+ * @var string Regular expression to find schema version
+ * @access private
+ */
+ var $versionRegex = '/<schema.*?( version="([^"]*)")?.*?>/';
+
+ /**
+ * @var string Current schema version
+ * @access private
+ */
+ var $schemaVersion;
+
+ /**
+ * @var int Success of last Schema execution
+ */
+ var $success;
+
+ /**
+ * @var bool Execute SQL inline as it is generated
+ */
+ var $executeInline;
+
+ /**
+ * @var bool Continue SQL execution if errors occur
+ */
+ var $continueOnError;
+
+ /**
+ * @var int How to handle existing data rows (insert, update, or ignore)
+ */
+ var $existingData;
+
+ /**
+ * Creates an adoSchema object
+ *
+ * Creating an adoSchema object is the first step in processing an XML schema.
+ * The only parameter is an ADOdb database connection object, which must already
+ * have been created.
+ *
+ * @param object $db ADOdb database connection object.
+ */
+ function adoSchema( &$db ) {
+ // Initialize the environment
+ $this->mgq = get_magic_quotes_runtime();
+ set_magic_quotes_runtime(0);
+
+ $this->db =& $db;
+ $this->debug = $this->db->debug;
+ $this->dict = NewDataDictionary( $this->db );
+ $this->sqlArray = array();
+ $this->schemaVersion = XMLS_SCHEMA_VERSION;
+ $this->executeInline( XMLS_EXECUTE_INLINE );
+ $this->continueOnError( XMLS_CONTINUE_ON_ERROR );
+ $this->existingData( XMLS_EXISTING_DATA );
+ $this->setUpgradeMethod();
+ }
+
+ /**
+ * Sets the method to be used for upgrading an existing database
+ *
+ * Use this method to specify how existing database objects should be upgraded.
+ * The method option can be set to ALTER, REPLACE, BEST, or NONE. ALTER attempts to
+ * alter each database object directly, REPLACE attempts to rebuild each object
+ * from scratch, BEST attempts to determine the best upgrade method for each
+ * object, and NONE disables upgrading.
+ *
+ * This method is not yet used by AXMLS, but exists for backward compatibility.
+ * The ALTER method is automatically assumed when the adoSchema object is
+ * instantiated; other upgrade methods are not currently supported.
+ *
+ * @param string $method Upgrade method (ALTER|REPLACE|BEST|NONE)
+ * @returns string Upgrade method used
+ */
+ function SetUpgradeMethod( $method = '' ) {
+ if( !is_string( $method ) ) {
+ return FALSE;
+ }
+
+ $method = strtoupper( $method );
+
+ // Handle the upgrade methods
+ switch( $method ) {
+ case 'ALTER':
+ $this->upgrade = $method;
+ break;
+ case 'REPLACE':
+ $this->upgrade = $method;
+ break;
+ case 'BEST':
+ $this->upgrade = 'ALTER';
+ break;
+ case 'NONE':
+ $this->upgrade = 'NONE';
+ break;
+ default:
+ // Use default if no legitimate method is passed.
+ $this->upgrade = XMLS_DEFAULT_UPGRADE_METHOD;
+ }
+
+ return $this->upgrade;
+ }
+
+ /**
+ * Specifies how to handle existing data row when there is a unique key conflict.
+ *
+ * The existingData setting specifies how the parser should handle existing rows
+ * when a unique key violation occurs during the insert. This can happen when inserting
+ * data into an existing table with one or more primary keys or unique indexes.
+ * The existingData method takes one of three options: XMLS_MODE_INSERT attempts
+ * to always insert the data as a new row. In the event of a unique key violation,
+ * the database will generate an error. XMLS_MODE_UPDATE attempts to update the
+ * any existing rows with the new data based upon primary or unique key fields in
+ * the schema. If the data row in the schema specifies no unique fields, the row
+ * data will be inserted as a new row. XMLS_MODE_IGNORE specifies that any data rows
+ * that would result in a unique key violation be ignored; no inserts or updates will
+ * take place. For backward compatibility, the default setting is XMLS_MODE_INSERT,
+ * but XMLS_MODE_UPDATE will generally be the most appropriate setting.
+ *
+ * @param int $mode XMLS_MODE_INSERT, XMLS_MODE_UPDATE, or XMLS_MODE_IGNORE
+ * @return int current mode
+ */
+ function ExistingData( $mode = NULL ) {
+ if( is_int( $mode ) ) {
+ switch( $mode ) {
+ case XMLS_MODE_UPDATE:
+ $mode = XMLS_MODE_UPDATE;
+ break;
+ case XMLS_MODE_IGNORE:
+ $mode = XMLS_MODE_IGNORE;
+ break;
+ case XMLS_MODE_INSERT:
+ $mode = XMLS_MODE_INSERT;
+ break;
+ default:
+ $mode = XMLS_EXISITNG_DATA;
+ break;
+ }
+ $this->existingData = $mode;
+ }
+
+ return $this->existingData;
+ }
+
+ /**
+ * Enables/disables inline SQL execution.
+ *
+ * Call this method to enable or disable inline execution of the schema. If the mode is set to TRUE (inline execution),
+ * AXMLS applies the SQL to the database immediately as each schema entity is parsed. If the mode
+ * is set to FALSE (post execution), AXMLS parses the entire schema and you will need to call adoSchema::ExecuteSchema()
+ * to apply the schema to the database.
+ *
+ * @param bool $mode execute
+ * @return bool current execution mode
+ *
+ * @see ParseSchema(), ExecuteSchema()
+ */
+ function ExecuteInline( $mode = NULL ) {
+ if( is_bool( $mode ) ) {
+ $this->executeInline = $mode;
+ }
+
+ return $this->executeInline;
+ }
+
+ /**
+ * Enables/disables SQL continue on error.
+ *
+ * Call this method to enable or disable continuation of SQL execution if an error occurs.
+ * If the mode is set to TRUE (continue), AXMLS will continue to apply SQL to the database, even if an error occurs.
+ * If the mode is set to FALSE (halt), AXMLS will halt execution of generated sql if an error occurs, though parsing
+ * of the schema will continue.
+ *
+ * @param bool $mode execute
+ * @return bool current continueOnError mode
+ *
+ * @see addSQL(), ExecuteSchema()
+ */
+ function ContinueOnError( $mode = NULL ) {
+ if( is_bool( $mode ) ) {
+ $this->continueOnError = $mode;
+ }
+
+ return $this->continueOnError;
+ }
+
+ /**
+ * Loads an XML schema from a file and converts it to SQL.
+ *
+ * Call this method to load the specified schema (see the DTD for the proper format) from
+ * the filesystem and generate the SQL necessary to create the database
+ * described. This method automatically converts the schema to the latest
+ * axmls schema version.
+ * @see ParseSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute
+ */
+ function ParseSchema( $filename, $returnSchema = FALSE ) {
+ return $this->ParseSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
+ }
+
+ /**
+ * Loads an XML schema from a file and converts it to SQL.
+ *
+ * Call this method to load the specified schema directly from a file (see
+ * the DTD for the proper format) and generate the SQL necessary to create
+ * the database described by the schema. Use this method when you are dealing
+ * with large schema files. Otherwise, ParseSchema() is faster.
+ * This method does not automatically convert the schema to the latest axmls
+ * schema version. You must convert the schema manually using either the
+ * ConvertSchemaFile() or ConvertSchemaString() method.
+ * @see ParseSchema()
+ * @see ConvertSchemaFile()
+ * @see ConvertSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ *
+ * @deprecated Replaced by adoSchema::ParseSchema() and adoSchema::ParseSchemaString()
+ * @see ParseSchema(), ParseSchemaString()
+ */
+ function ParseSchemaFile( $filename, $returnSchema = FALSE ) {
+ // Open the file
+ if( !($fp = fopen( $filename, 'r' )) ) {
+ logMsg( 'Unable to open file' );
+ return FALSE;
+ }
+
+ // do version detection here
+ if( $this->SchemaFileVersion( $filename ) != $this->schemaVersion ) {
+ logMsg( 'Invalid Schema Version' );
+ return FALSE;
+ }
+
+ if( $returnSchema ) {
+ $xmlstring = '';
+ while( $data = fread( $fp, 4096 ) ) {
+ $xmlstring .= $data . "\n";
+ }
+ return $xmlstring;
+ }
+
+ $this->success = 2;
+
+ $xmlParser = $this->create_parser();
+
+ // Process the file
+ while( $data = fread( $fp, 4096 ) ) {
+ if( !xml_parse( $xmlParser, $data, feof( $fp ) ) ) {
+ die( sprintf(
+ "XML error: %s at line %d",
+ xml_error_string( xml_get_error_code( $xmlParser) ),
+ xml_get_current_line_number( $xmlParser)
+ ) );
+ }
+ }
+
+ xml_parser_free( $xmlParser );
+
+ return $this->sqlArray;
+ }
+
+ /**
+ * Converts an XML schema string to SQL.
+ *
+ * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+ * and generate the SQL necessary to create the database described by the schema.
+ * @see ParseSchema()
+ *
+ * @param string $xmlstring XML schema string.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ */
+ function ParseSchemaString( $xmlstring, $returnSchema = FALSE ) {
+ if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
+ logMsg( 'Empty or Invalid Schema' );
+ return FALSE;
+ }
+
+ // do version detection here
+ if( $this->SchemaStringVersion( $xmlstring ) != $this->schemaVersion ) {
+ logMsg( 'Invalid Schema Version' );
+ return FALSE;
+ }
+
+ if( $returnSchema ) {
+ return $xmlstring;
+ }
+
+ $this->success = 2;
+
+ $xmlParser = $this->create_parser();
+
+ if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
+ die( sprintf(
+ "XML error: %s at line %d",
+ xml_error_string( xml_get_error_code( $xmlParser) ),
+ xml_get_current_line_number( $xmlParser)
+ ) );
+ }
+
+ xml_parser_free( $xmlParser );
+
+ return $this->sqlArray;
+ }
+
+ /**
+ * Loads an XML schema from a file and converts it to uninstallation SQL.
+ *
+ * Call this method to load the specified schema (see the DTD for the proper format) from
+ * the filesystem and generate the SQL necessary to remove the database described.
+ * @see RemoveSchemaString()
+ *
+ * @param string $file Name of XML schema file.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute
+ */
+ function RemoveSchema( $filename, $returnSchema = FALSE ) {
+ return $this->RemoveSchemaString( $this->ConvertSchemaFile( $filename ), $returnSchema );
+ }
+
+ /**
+ * Converts an XML schema string to uninstallation SQL.
+ *
+ * Call this method to parse a string containing an XML schema (see the DTD for the proper format)
+ * and generate the SQL necessary to uninstall the database described by the schema.
+ * @see RemoveSchema()
+ *
+ * @param string $schema XML schema string.
+ * @param bool $returnSchema Return schema rather than parsing.
+ * @return array Array of SQL queries, ready to execute.
+ */
+ function RemoveSchemaString( $schema, $returnSchema = FALSE ) {
+
+ // grab current version
+ if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
+ return FALSE;
+ }
+
+ return $this->ParseSchemaString( $this->TransformSchema( $schema, 'remove-' . $version), $returnSchema );
+ }
+
+ /**
+ * Applies the current XML schema to the database (post execution).
+ *
+ * Call this method to apply the current schema (generally created by calling
+ * ParseSchema() or ParseSchemaString() ) to the database (creating the tables, indexes,
+ * and executing other SQL specified in the schema) after parsing.
+ * @see ParseSchema(), ParseSchemaString(), ExecuteInline()
+ *
+ * @param array $sqlArray Array of SQL statements that will be applied rather than
+ * the current schema.
+ * @param boolean $continueOnErr Continue to apply the schema even if an error occurs.
+ * @returns integer 0 if failure, 1 if errors, 2 if successful.
+ */
+ function ExecuteSchema( $sqlArray = NULL, $continueOnErr = NULL ) {
+ if( !is_bool( $continueOnErr ) ) {
+ $continueOnErr = $this->ContinueOnError();
+ }
+
+ if( !isset( $sqlArray ) ) {
+ $sqlArray = $this->sqlArray;
+ }
+
+ if( !is_array( $sqlArray ) ) {
+ $this->success = 0;
+ } else {
+ $this->success = $this->dict->ExecuteSQLArray( $sqlArray, $continueOnErr );
+ }
+
+ return $this->success;
+ }
+
+ /**
+ * Returns the current SQL array.
+ *
+ * Call this method to fetch the array of SQL queries resulting from
+ * ParseSchema() or ParseSchemaString().
+ *
+ * @param string $format Format: HTML, TEXT, or NONE (PHP array)
+ * @return array Array of SQL statements or FALSE if an error occurs
+ */
+ function PrintSQL( $format = 'NONE' ) {
+ $sqlArray = null;
+ return $this->getSQL( $format, $sqlArray );
+ }
+
+ /**
+ * Saves the current SQL array to the local filesystem as a list of SQL queries.
+ *
+ * Call this method to save the array of SQL queries (generally resulting from a
+ * parsed XML schema) to the filesystem.
+ *
+ * @param string $filename Path and name where the file should be saved.
+ * @return boolean TRUE if save is successful, else FALSE.
+ */
+ function SaveSQL( $filename = './schema.sql' ) {
+
+ if( !isset( $sqlArray ) ) {
+ $sqlArray = $this->sqlArray;
+ }
+ if( !isset( $sqlArray ) ) {
+ return FALSE;
+ }
+
+ $fp = fopen( $filename, "w" );
+
+ foreach( $sqlArray as $key => $query ) {
+ fwrite( $fp, $query . ";\n" );
+ }
+ fclose( $fp );
+ }
+
+ /**
+ * Create an xml parser
+ *
+ * @return object PHP XML parser object
+ *
+ * @access private
+ */
+ function &create_parser() {
+ // Create the parser
+ $xmlParser = xml_parser_create();
+ xml_set_object( $xmlParser, $this );
+
+ // Initialize the XML callback functions
+ xml_set_element_handler( $xmlParser, '_tag_open', '_tag_close' );
+ xml_set_character_data_handler( $xmlParser, '_tag_cdata' );
+
+ return $xmlParser;
+ }
+
+ /**
+ * XML Callback to process start elements
+ *
+ * @access private
+ */
+ function _tag_open( &$parser, $tag, $attributes ) {
+ switch( strtoupper( $tag ) ) {
+ case 'TABLE':
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ $this->obj = new dbTable( $this, $attributes );
+ xml_set_object( $parser, $this->obj );
+ }
+ break;
+ case 'SQL':
+ if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
+ $this->obj = new dbQuerySet( $this, $attributes );
+ xml_set_object( $parser, $this->obj );
+ }
+ break;
+ default:
+ // print_r( array( $tag, $attributes ) );
+ }
+
+ }
+
+ /**
+ * XML Callback to process CDATA elements
+ *
+ * @access private
+ */
+ function _tag_cdata( &$parser, $cdata ) {
+ }
+
+ /**
+ * XML Callback to process end elements
+ *
+ * @access private
+ * @internal
+ */
+ function _tag_close( &$parser, $tag ) {
+
+ }
+
+ /**
+ * Converts an XML schema string to the specified DTD version.
+ *
+ * Call this method to convert a string containing an XML schema to a different AXMLS
+ * DTD version. For instance, to convert a schema created for an pre-1.0 version for
+ * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
+ * parameter is specified, the schema will be converted to the current DTD version.
+ * If the newFile parameter is provided, the converted schema will be written to the specified
+ * file.
+ * @see ConvertSchemaFile()
+ *
+ * @param string $schema String containing XML schema that will be converted.
+ * @param string $newVersion DTD version to convert to.
+ * @param string $newFile File name of (converted) output file.
+ * @return string Converted XML schema or FALSE if an error occurs.
+ */
+ function ConvertSchemaString( $schema, $newVersion = NULL, $newFile = NULL ) {
+
+ // grab current version
+ if( !( $version = $this->SchemaStringVersion( $schema ) ) ) {
+ return FALSE;
+ }
+
+ if( !isset ($newVersion) ) {
+ $newVersion = $this->schemaVersion;
+ }
+
+ if( $version == $newVersion ) {
+ $result = $schema;
+ } else {
+ $result = $this->TransformSchema( $schema, 'convert-' . $version . '-' . $newVersion);
+ }
+
+ if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
+ fwrite( $fp, $result );
+ fclose( $fp );
+ }
+
+ return $result;
+ }
+
+ /*
+ // compat for pre-4.3 - jlim
+ function _file_get_contents($path)
+ {
+ if (function_exists('file_get_contents')) return file_get_contents($path);
+ return join('',file($path));
+ }*/
+
+ /**
+ * Converts an XML schema file to the specified DTD version.
+ *
+ * Call this method to convert the specified XML schema file to a different AXMLS
+ * DTD version. For instance, to convert a schema created for an pre-1.0 version for
+ * AXMLS (DTD version 0.1) to a newer version of the DTD (e.g. 0.2). If no DTD version
+ * parameter is specified, the schema will be converted to the current DTD version.
+ * If the newFile parameter is provided, the converted schema will be written to the specified
+ * file.
+ * @see ConvertSchemaString()
+ *
+ * @param string $filename Name of XML schema file that will be converted.
+ * @param string $newVersion DTD version to convert to.
+ * @param string $newFile File name of (converted) output file.
+ * @return string Converted XML schema or FALSE if an error occurs.
+ */
+ function ConvertSchemaFile( $filename, $newVersion = NULL, $newFile = NULL ) {
+
+ // grab current version
+ if( !( $version = $this->SchemaFileVersion( $filename ) ) ) {
+ return FALSE;
+ }
+
+ if( !isset ($newVersion) ) {
+ $newVersion = $this->schemaVersion;
+ }
+
+ if( $version == $newVersion ) {
+ $result = _file_get_contents( $filename );
+
+ // remove unicode BOM if present
+ if( substr( $result, 0, 3 ) == sprintf( '%c%c%c', 239, 187, 191 ) ) {
+ $result = substr( $result, 3 );
+ }
+ } else {
+ $result = $this->TransformSchema( $filename, 'convert-' . $version . '-' . $newVersion, 'file' );
+ }
+
+ if( is_string( $result ) AND is_string( $newFile ) AND ( $fp = fopen( $newFile, 'w' ) ) ) {
+ fwrite( $fp, $result );
+ fclose( $fp );
+ }
+
+ return $result;
+ }
+
+ function TransformSchema( $schema, $xsl, $schematype='string' )
+ {
+ // Fail if XSLT extension is not available
+ if( ! function_exists( 'xslt_create' ) ) {
+ return FALSE;
+ }
+
+ $xsl_file = dirname( __FILE__ ) . '/xsl/' . $xsl . '.xsl';
+
+ // look for xsl
+ if( !is_readable( $xsl_file ) ) {
+ return FALSE;
+ }
+
+ switch( $schematype )
+ {
+ case 'file':
+ if( !is_readable( $schema ) ) {
+ return FALSE;
+ }
+
+ $schema = _file_get_contents( $schema );
+ break;
+ case 'string':
+ default:
+ if( !is_string( $schema ) ) {
+ return FALSE;
+ }
+ }
+
+ $arguments = array (
+ '/_xml' => $schema,
+ '/_xsl' => _file_get_contents( $xsl_file )
+ );
+
+ // create an XSLT processor
+ $xh = xslt_create ();
+
+ // set error handler
+ xslt_set_error_handler ($xh, array (&$this, 'xslt_error_handler'));
+
+ // process the schema
+ $result = xslt_process ($xh, 'arg:/_xml', 'arg:/_xsl', NULL, $arguments);
+
+ xslt_free ($xh);
+
+ return $result;
+ }
+
+ /**
+ * Processes XSLT transformation errors
+ *
+ * @param object $parser XML parser object
+ * @param integer $errno Error number
+ * @param integer $level Error level
+ * @param array $fields Error information fields
+ *
+ * @access private
+ */
+ function xslt_error_handler( $parser, $errno, $level, $fields ) {
+ if( is_array( $fields ) ) {
+ $msg = array(
+ 'Message Type' => ucfirst( $fields['msgtype'] ),
+ 'Message Code' => $fields['code'],
+ 'Message' => $fields['msg'],
+ 'Error Number' => $errno,
+ 'Level' => $level
+ );
+
+ switch( $fields['URI'] ) {
+ case 'arg:/_xml':
+ $msg['Input'] = 'XML';
+ break;
+ case 'arg:/_xsl':
+ $msg['Input'] = 'XSL';
+ break;
+ default:
+ $msg['Input'] = $fields['URI'];
+ }
+
+ $msg['Line'] = $fields['line'];
+ } else {
+ $msg = array(
+ 'Message Type' => 'Error',
+ 'Error Number' => $errno,
+ 'Level' => $level,
+ 'Fields' => var_export( $fields, TRUE )
+ );
+ }
+
+ $error_details = $msg['Message Type'] . ' in XSLT Transformation' . "\n"
+ . '<table>' . "\n";
+
+ foreach( $msg as $label => $details ) {
+ $error_details .= '<tr><td><b>' . $label . ': </b></td><td>' . htmlentities( $details ) . '</td></tr>' . "\n";
+ }
+
+ $error_details .= '</table>';
+
+ trigger_error( $error_details, E_USER_ERROR );
+ }
+
+ /**
+ * Returns the AXMLS Schema Version of the requested XML schema file.
+ *
+ * Call this method to obtain the AXMLS DTD version of the requested XML schema file.
+ * @see SchemaStringVersion()
+ *
+ * @param string $filename AXMLS schema file
+ * @return string Schema version number or FALSE on error
+ */
+ function SchemaFileVersion( $filename ) {
+ // Open the file
+ if( !($fp = fopen( $filename, 'r' )) ) {
+ // die( 'Unable to open file' );
+ return FALSE;
+ }
+
+ // Process the file
+ while( $data = fread( $fp, 4096 ) ) {
+ if( preg_match( $this->versionRegex, $data, $matches ) ) {
+ return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
+ }
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * Returns the AXMLS Schema Version of the provided XML schema string.
+ *
+ * Call this method to obtain the AXMLS DTD version of the provided XML schema string.
+ * @see SchemaFileVersion()
+ *
+ * @param string $xmlstring XML schema string
+ * @return string Schema version number or FALSE on error
+ */
+ function SchemaStringVersion( $xmlstring ) {
+ if( !is_string( $xmlstring ) OR empty( $xmlstring ) ) {
+ return FALSE;
+ }
+
+ if( preg_match( $this->versionRegex, $xmlstring, $matches ) ) {
+ return !empty( $matches[2] ) ? $matches[2] : XMLS_DEFAULT_SCHEMA_VERSION;
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * Extracts an XML schema from an existing database.
+ *
+ * Call this method to create an XML schema string from an existing database.
+ * If the data parameter is set to TRUE, AXMLS will include the data from the database
+ * in the schema.
+ *
+ * @param boolean $data Include data in schema dump
+ * @indent string indentation to use
+ * @prefix string extract only tables with given prefix
+ * @stripprefix strip prefix string when storing in XML schema
+ * @return string Generated XML schema
+ */
+ function ExtractSchema( $data = FALSE, $indent = ' ', $prefix = '' , $stripprefix=false) {
+ $old_mode = $this->db->SetFetchMode( ADODB_FETCH_NUM );
+
+ $schema = '<?xml version="1.0"?>' . "\n"
+ . '<schema version="' . $this->schemaVersion . '">' . "\n";
+
+ if( is_array( $tables = $this->db->MetaTables( 'TABLES' , ($prefix) ? $prefix.'%' : '') ) ) {
+ foreach( $tables as $table ) {
+ if ($stripprefix) $table = str_replace(str_replace('\\_', '_', $pfx ), '', $table);
+ $schema .= $indent . '<table name="' . htmlentities( $table ) . '">' . "\n";
+
+ // grab details from database
+ $rs = $this->db->Execute( 'SELECT * FROM ' . $table . ' WHERE -1' );
+ $fields = $this->db->MetaColumns( $table );
+ $indexes = $this->db->MetaIndexes( $table );
+
+ if( is_array( $fields ) ) {
+ foreach( $fields as $details ) {
+ $extra = '';
+ $content = array();
+
+ if( isset($details->max_length) && $details->max_length > 0 ) {
+ $extra .= ' size="' . $details->max_length . '"';
+ }
+
+ if( isset($details->primary_key) && $details->primary_key ) {
+ $content[] = '<KEY/>';
+ } elseif( isset($details->not_null) && $details->not_null ) {
+ $content[] = '<NOTNULL/>';
+ }
+
+ if( isset($details->has_default) && $details->has_default ) {
+ $content[] = '<DEFAULT value="' . htmlentities( $details->default_value ) . '"/>';
+ }
+
+ if( isset($details->auto_increment) && $details->auto_increment ) {
+ $content[] = '<AUTOINCREMENT/>';
+ }
+
+ if( isset($details->unsigned) && $details->unsigned ) {
+ $content[] = '<UNSIGNED/>';
+ }
+
+ // this stops the creation of 'R' columns,
+ // AUTOINCREMENT is used to create auto columns
+ $details->primary_key = 0;
+ $type = $rs->MetaType( $details );
+
+ $schema .= str_repeat( $indent, 2 ) . '<field name="' . htmlentities( $details->name ) . '" type="' . $type . '"' . $extra;
+
+ if( !empty( $content ) ) {
+ $schema .= ">\n" . str_repeat( $indent, 3 )
+ . implode( "\n" . str_repeat( $indent, 3 ), $content ) . "\n"
+ . str_repeat( $indent, 2 ) . '</field>' . "\n";
+ } else {
+ $schema .= "/>\n";
+ }
+ }
+ }
+
+ if( is_array( $indexes ) ) {
+ foreach( $indexes as $index => $details ) {
+ $schema .= str_repeat( $indent, 2 ) . '<index name="' . $index . '">' . "\n";
+
+ if( $details['unique'] ) {
+ $schema .= str_repeat( $indent, 3 ) . '<UNIQUE/>' . "\n";
+ }
+
+ foreach( $details['columns'] as $column ) {
+ $schema .= str_repeat( $indent, 3 ) . '<col>' . htmlentities( $column ) . '</col>' . "\n";
+ }
+
+ $schema .= str_repeat( $indent, 2 ) . '</index>' . "\n";
+ }
+ }
+
+ if( $data ) {
+ $rs = $this->db->Execute( 'SELECT * FROM ' . $table );
+
+ if( is_object( $rs ) && !$rs->EOF ) {
+ $schema .= str_repeat( $indent, 2 ) . "<data>\n";
+
+ while( $row = $rs->FetchRow() ) {
+ foreach( $row as $key => $val ) {
+ if ( $val != htmlentities( $val ) ) {
+ $row[$key] = '<![CDATA[' . $val . ']]>';
+ }
+ }
+
+ $schema .= str_repeat( $indent, 3 ) . '<row><f>' . implode( '</f><f>', $row ) . "</f></row>\n";
+ }
+
+ $schema .= str_repeat( $indent, 2 ) . "</data>\n";
+ }
+ }
+
+ $schema .= $indent . "</table>\n";
+ }
+ }
+
+ $this->db->SetFetchMode( $old_mode );
+
+ $schema .= '</schema>';
+ return $schema;
+ }
+
+ /**
+ * Sets a prefix for database objects
+ *
+ * Call this method to set a standard prefix that will be prepended to all database tables
+ * and indices when the schema is parsed. Calling setPrefix with no arguments clears the prefix.
+ *
+ * @param string $prefix Prefix that will be prepended.
+ * @param boolean $underscore If TRUE, automatically append an underscore character to the prefix.
+ * @return boolean TRUE if successful, else FALSE
+ */
+ function SetPrefix( $prefix = '', $underscore = TRUE ) {
+ switch( TRUE ) {
+ // clear prefix
+ case empty( $prefix ):
+ logMsg( 'Cleared prefix' );
+ $this->objectPrefix = '';
+ return TRUE;
+ // prefix too long
+ case strlen( $prefix ) > XMLS_PREFIX_MAXLEN:
+ // prefix contains invalid characters
+ case !preg_match( '/^[a-z][a-z0-9_]+$/i', $prefix ):
+ logMsg( 'Invalid prefix: ' . $prefix );
+ return FALSE;
+ }
+
+ if( $underscore AND substr( $prefix, -1 ) != '_' ) {
+ $prefix .= '_';
+ }
+
+ // prefix valid
+ logMsg( 'Set prefix: ' . $prefix );
+ $this->objectPrefix = $prefix;
+ return TRUE;
+ }
+
+ /**
+ * Returns an object name with the current prefix prepended.
+ *
+ * @param string $name Name
+ * @return string Prefixed name
+ *
+ * @access private
+ */
+ function prefix( $name = '' ) {
+ // if prefix is set
+ if( !empty( $this->objectPrefix ) ) {
+ // Prepend the object prefix to the table name
+ // prepend after quote if used
+ return preg_replace( '/^(`?)(.+)$/', '$1' . $this->objectPrefix . '$2', $name );
+ }
+
+ // No prefix set. Use name provided.
+ return $name;
+ }
+
+ /**
+ * Checks if element references a specific platform
+ *
+ * @param string $platform Requested platform
+ * @returns boolean TRUE if platform check succeeds
+ *
+ * @access private
+ */
+ function supportedPlatform( $platform = NULL ) {
+ if( !empty( $platform ) ) {
+ $regex = '/(^|\|)' . $this->db->databaseType . '(\||$)/i';
+
+ if( preg_match( '/^- /', $platform ) ) {
+ if (preg_match ( $regex, substr( $platform, 2 ) ) ) {
+ logMsg( 'Platform ' . $platform . ' is NOT supported' );
+ return FALSE;
+ }
+ } else {
+ if( !preg_match ( $regex, $platform ) ) {
+ logMsg( 'Platform ' . $platform . ' is NOT supported' );
+ return FALSE;
+ }
+ }
+ }
+
+ logMsg( 'Platform ' . $platform . ' is supported' );
+ return TRUE;
+ }
+
+ /**
+ * Clears the array of generated SQL.
+ *
+ * @access private
+ */
+ function clearSQL() {
+ $this->sqlArray = array();
+ }
+
+ /**
+ * Adds SQL into the SQL array.
+ *
+ * @param mixed $sql SQL to Add
+ * @return boolean TRUE if successful, else FALSE.
+ *
+ * @access private
+ */
+ function addSQL( $sql = NULL ) {
+ if( is_array( $sql ) ) {
+ foreach( $sql as $line ) {
+ $this->addSQL( $line );
+ }
+
+ return TRUE;
+ }
+
+ if( is_string( $sql ) ) {
+ $this->sqlArray[] = $sql;
+
+ // if executeInline is enabled, and either no errors have occurred or continueOnError is enabled, execute SQL.
+ if( $this->ExecuteInline() && ( $this->success == 2 || $this->ContinueOnError() ) ) {
+ $saved = $this->db->debug;
+ $this->db->debug = $this->debug;
+ $ok = $this->db->Execute( $sql );
+ $this->db->debug = $saved;
+
+ if( !$ok ) {
+ if( $this->debug ) {
+ ADOConnection::outp( $this->db->ErrorMsg() );
+ }
+
+ $this->success = 1;
+ }
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ /**
+ * Gets the SQL array in the specified format.
+ *
+ * @param string $format Format
+ * @return mixed SQL
+ *
+ * @access private
+ */
+ function getSQL( $format = NULL, $sqlArray = NULL ) {
+ if( !is_array( $sqlArray ) ) {
+ $sqlArray = $this->sqlArray;
+ }
+
+ if( !is_array( $sqlArray ) ) {
+ return FALSE;
+ }
+
+ switch( strtolower( $format ) ) {
+ case 'string':
+ case 'text':
+ return !empty( $sqlArray ) ? implode( ";\n\n", $sqlArray ) . ';' : '';
+ case'html':
+ return !empty( $sqlArray ) ? nl2br( htmlentities( implode( ";\n\n", $sqlArray ) . ';' ) ) : '';
+ }
+
+ return $this->sqlArray;
+ }
+
+ /**
+ * Destroys an adoSchema object.
+ *
+ * Call this method to clean up after an adoSchema object that is no longer in use.
+ * @deprecated adoSchema now cleans up automatically.
+ */
+ function Destroy() {
+ set_magic_quotes_runtime( $this->mgq );
+ unset( $this );
+ }
+}
+
+/**
+* Message logging function
+*
+* @access private
+*/
+function logMsg( $msg, $title = NULL, $force = FALSE ) {
+ if( XMLS_DEBUG or $force ) {
+ echo '<pre>';
+
+ if( isset( $title ) ) {
+ echo '<h3>' . htmlentities( $title ) . '</h3>';
+ }
+
+ if( @is_object( $this ) ) {
+ echo '[' . get_class( $this ) . '] ';
+ }
+
+ print_r( $msg );
+
+ echo '</pre>';
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/adodb.inc.php b/lib/adodb/adodb.inc.php
new file mode 100644
index 0000000..351d505
--- /dev/null
+++ b/lib/adodb/adodb.inc.php
@@ -0,0 +1,4231 @@
+<?php
+/*
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://adodb.sourceforge.net
+ *
+ * This is the main include file for ADOdb.
+ * Database specific drivers are stored in the adodb/drivers/adodb-*.inc.php
+ *
+ * The ADOdb files are formatted so that doxygen can be used to generate documentation.
+ * Doxygen is a documentation generation tool and can be downloaded from http://doxygen.org/
+ */
+
+/**
+ \mainpage
+
+ @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+
+ Released under both BSD license and Lesser GPL library license. You can choose which license
+ you prefer.
+
+ PHP's database access functions are not standardised. This creates a need for a database
+ class library to hide the differences between the different database API's (encapsulate
+ the differences) so we can easily switch databases.
+
+ We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, DB2,
+ Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access,
+ ADO, SAP DB, SQLite and ODBC. We have had successful reports of connecting to Progress and
+ other databases via ODBC.
+
+ Latest Download at http://adodb.sourceforge.net/
+
+ */
+
+ if (!defined('_ADODB_LAYER')) {
+ define('_ADODB_LAYER',1);
+
+ //==============================================================================================
+ // 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_EXTENSION, // ADODB extension installed
+ $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_QUOTE_FIELDNAMES; // Allows you to force quotes (backticks) around field names in queries generated by getinsertsql and getupdatesql.
+
+ //==============================================================================================
+ // GLOBAL SETUP
+ //==============================================================================================
+
+ $ADODB_EXTENSION = defined('ADODB_EXTENSION');
+
+ //********************************************************//
+ /*
+ Controls $ADODB_FORCE_TYPE mode. Default is ADODB_FORCE_VALUE (3).
+ Used in GetUpdateSql and GetInsertSql functions. Thx to Niko, nuko#mbnet.fi
+
+ 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.
+ */
+ define('ADODB_FORCE_IGNORE',0);
+ define('ADODB_FORCE_NULL',1);
+ define('ADODB_FORCE_EMPTY',2);
+ define('ADODB_FORCE_VALUE',3);
+ //********************************************************//
+
+
+ if (!$ADODB_EXTENSION || ADODB_EXTENSION < 4.0) {
+
+ define('ADODB_BAD_RS','<p>Bad $rs in %s. Connection or SQL invalid. Try using $connection->debug=true;</p>');
+
+ // allow [ ] @ ` " and . in table names
+ define('ADODB_TABLE_REGEX','([]0-9a-z_\:\"\`\.\@\[-]*)');
+
+ // prefetching used by oracle
+ if (!defined('ADODB_PREFETCH_ROWS')) define('ADODB_PREFETCH_ROWS',10);
+
+
+ /*
+ Controls ADODB_FETCH_ASSOC field-name case. Default is 2, use native case-names.
+ This currently works only with mssql, odbc, oci8po and ibase derived drivers.
+
+ 0 = assoc lowercase field names. $rs->fields['orderid']
+ 1 = assoc uppercase field names. $rs->fields['ORDERID']
+ 2 = use native-case field names. $rs->fields['OrderID']
+ */
+
+ define('ADODB_FETCH_DEFAULT',0);
+ define('ADODB_FETCH_NUM',1);
+ define('ADODB_FETCH_ASSOC',2);
+ define('ADODB_FETCH_BOTH',3);
+
+ if (!defined('TIMESTAMP_FIRST_YEAR')) define('TIMESTAMP_FIRST_YEAR',100);
+
+ // PHP's version scheme makes converting to numbers difficult - workaround
+ $_adodb_ver = (float) PHP_VERSION;
+ if ($_adodb_ver >= 5.2) {
+ define('ADODB_PHPVER',0x5200);
+ } else if ($_adodb_ver >= 5.0) {
+ define('ADODB_PHPVER',0x5000);
+ } else if ($_adodb_ver > 4.299999) { # 4.3
+ define('ADODB_PHPVER',0x4300);
+ } else if ($_adodb_ver > 4.199999) { # 4.2
+ define('ADODB_PHPVER',0x4200);
+ } else if (strnatcmp(PHP_VERSION,'4.0.5')>=0) {
+ define('ADODB_PHPVER',0x4050);
+ } else {
+ define('ADODB_PHPVER',0x4000);
+ }
+ }
+
+ //if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
+
+
+ /**
+ Accepts $src and $dest arrays, replacing string $data
+ */
+ function ADODB_str_replace($src, $dest, $data)
+ {
+ if (ADODB_PHPVER >= 0x4050) return str_replace($src,$dest,$data);
+
+ $s = reset($src);
+ $d = reset($dest);
+ while ($s !== false) {
+ $data = str_replace($s,$d,$data);
+ $s = next($src);
+ $d = next($dest);
+ }
+ return $data;
+ }
+
+ 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_FORCE_TYPE,
+ $ADODB_QUOTE_FIELDNAMES;
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_DEFAULT;
+ $ADODB_FORCE_TYPE = ADODB_FORCE_VALUE;
+
+
+ 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://");
+ }
+
+
+ // Initialize random number generator for randomizing cache flushes
+ // -- note Since PHP 4.2.0, the seed becomes optional and defaults to a random value if omitted.
+ srand(((double)microtime())*1000000);
+
+ /**
+ * ADODB version as a string.
+ */
+ $ADODB_vers = 'V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved. Released BSD & LGPL.';
+
+ /**
+ * 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
+ */
+ 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.
+*/
+ }
+
+
+
+ function ADODB_TransMonitor($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnection)
+ {
+ //print "Errorno ($fn errno=$errno m=$errmsg) ";
+ $thisConnection->_transOK = false;
+ if ($thisConnection->_oldRaiseFn) {
+ $fn = $thisConnection->_oldRaiseFn;
+ $fn($dbms, $fn, $errno, $errmsg, $p1, $p2,$thisConnection);
+ }
+ }
+
+ //==============================================================================================
+ // CLASS ADOConnection
+ //==============================================================================================
+
+ /**
+ * Connection object. For connecting to databases, and executing queries.
+ */
+ class ADOConnection {
+ //
+ // PUBLIC VARS
+ //
+ var $dataProvider = 'native';
+ var $databaseType = ''; /// RDBMS currently in use, eg. odbc, mysql, mssql
+ var $database = ''; /// Name of database to be used.
+ var $host = ''; /// The hostname of the database server
+ var $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 statements
+ var $maxblobsize = 262144; /// maximum size of blobs or large text fields (262144 = 256K)-- some db's die otherwise like foxpro
+ var $concat_operator = '+'; /// default concat operator -- change to || for Oracle/Interbase
+ var $substr = 'substr'; /// substring operator
+ var $length = 'length'; /// string length ofperator
+ var $random = 'rand()'; /// random function
+ var $upperCase = 'upper'; /// uppercase function
+ var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
+ var $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 database
+ var $false = '0'; /// string that represents FALSE for a database
+ var $replaceQuote = "\\'"; /// string to use to replace quotes
+ var $nameQuote = '"'; /// string to use to quote identifiers and names
+ var $charSet=false; /// character set to use - only for interbase, postgres and oci8
+ var $metaDatabasesSQL = '';
+ var $metaTablesSQL = '';
+ var $uniqueOrderBy = false; /// All order by columns have to be unique
+ var $emptyDate = '&nbsp;';
+ var $emptyTimeStamp = '&nbsp;';
+ 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 TABLE
+ var $hasLimit = false; /// support pgsql/mysql SELECT * FROM TABLE LIMIT 10
+ var $readOnly = false; /// this is a readonly database - used by phpLens
+ var $hasMoveFirst = false; /// has ability to run MoveFirst(), scrolling backwards
+ var $hasGenID = false; /// can generate sequences using GenID();
+ var $hasTransactions = true; /// has transactions
+ //--
+ var $genID = 0; /// sequence id used by GenID();
+ var $raiseErrorFn = false; /// error function to call
+ var $isoDates = false; /// accepts dates in ISO format
+ var $cacheSecs = 3600; /// cache for 1 hour
+
+ // memcache
+ var $memCache = false; /// should we use memCache instead of caching in files
+ var $memCacheHost; /// memCache host
+ var $memCachePort = 11211; /// memCache port
+ var $memCacheCompress = false; /// Use 'true' to store the item compressed (uses zlib)
+
+ var $sysDate = false; /// name of function that returns the current date
+ var $sysTimeStamp = false; /// name of function that returns the current timestamp
+ var $arrayClass = 'ADORecordSet_array'; /// name of class used to generate array recordsets, which are pre-downloaded recordsets
+
+ var $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 unique
+ var $leftOuter = false; /// operator to use for left outer join in WHERE clause
+ var $rightOuter = false; /// operator to use for right outer join in WHERE clause
+ var $ansiOuter = false; /// whether ansi outer join syntax supported
+ var $autoRollback = false; // autoRollback on PConnect().
+ var $poorAffectedRows = false; // affectedRows not working or unreliable
+
+ var $fnExecute = false;
+ var $fnCacheExecute = false;
+ var $blobEncodeType = false; // false=not required, 'I'=encode to integer, 'C'=encode to char
+ var $rsPrefix = "ADORecordSet_";
+
+ var $autoCommit = true; /// do not modify this yourself - actually private
+ var $transOff = 0; /// temporarily disable transactions
+ var $transCnt = 0; /// count of nested transactions
+
+ var $fetchMode=false;
+
+ var $null2null = 'null'; // in autoexecute/getinsertsql/getupdatesql, this value will be converted to a null
+ //
+ // PRIVATE VARS
+ //
+ var $_oldRaiseFn = false;
+ var $_transOK = null;
+ var $_connectionID = false; /// The returned link identifier whenever a successful database connection is made.
+ var $_errorMsg = false; /// A variable which was used to keep the returned last error message. The value will
+ /// then returned by the errorMsg() function
+ var $_errorCode = false; /// Last error code, not guaranteed to be used - only by oci8
+ var $_queryID = false; /// This variable keeps the last created result link identifier
+
+ var $_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.
+ var $_evalAll = false;
+ var $_affected = false;
+ var $_logsql = false;
+ var $_transmode = ''; // transaction mode
+
+
+
+ /**
+ * Constructor
+ */
+ function ADOConnection()
+ {
+ die('Virtual Class -- cannot instantiate');
+ }
+
+ function Version()
+ {
+ global $ADODB_vers;
+
+ return (float) substr($ADODB_vers,1);
+ }
+
+ /**
+ Get server version info...
+
+ @returns An array with 2 elements: $arr['string'] is the description string,
+ and $arr[version] is the version (also a string).
+ */
+ function ServerInfo()
+ {
+ return array('description' => '', 'version' => '');
+ }
+
+ function IsConnected()
+ {
+ return !empty($this->_connectionID);
+ }
+
+ 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.
+ */
+ 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)) {
+ $fn = $ADODB_OUTP;
+ $fn($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
+
+ }
+
+ function Time()
+ {
+ $rs =& $this->_Execute("select $this->sysTimeStamp");
+ if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
+
+ return false;
+ }
+
+ /**
+ * Connect to database
+ *
+ * @param [argHostname] Host to connect to
+ * @param [argUsername] Userid to login
+ * @param [argPassword] Associated password
+ * @param [argDatabaseName] database
+ * @param [forceNew] force new connection
+ *
+ * @return true or false
+ */
+ function Connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "", $forceNew = false)
+ {
+ if ($argHostname != "") $this->host = $argHostname;
+ if ($argUsername != "") $this->user = $argUsername;
+ if ($argPassword != "") $this->password = $argPassword; // not stored for security reasons
+ if ($argDatabaseName != "") $this->database = $argDatabaseName;
+
+ $this->_isPersistentConnection = false;
+ if ($forceNew) {
+ if ($rez=$this->_nconnect($this->host, $this->user, $this->password, $this->database)) return true;
+ } else {
+ if ($rez=$this->_connect($this->host, $this->user, $this->password, $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 = 0;
+ }
+ if ($fn = $this->raiseErrorFn)
+ $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
+
+
+ $this->_connectionID = false;
+ if ($this->debug) ADOConnection::outp( $this->host.': '.$err);
+ return $ret;
+ }
+
+ function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
+ {
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName);
+ }
+
+
+ /**
+ * Always force a new connection to database - currently only works with oracle
+ *
+ * @param [argHostname] Host to connect to
+ * @param [argUsername] Userid to login
+ * @param [argPassword] Associated password
+ * @param [argDatabaseName] database
+ *
+ * @return true or false
+ */
+ function NConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
+ {
+ return $this->Connect($argHostname, $argUsername, $argPassword, $argDatabaseName, true);
+ }
+
+ /**
+ * Establish persistent connect to database
+ *
+ * @param [argHostname] Host to connect to
+ * @param [argUsername] Userid to login
+ * @param [argPassword] Associated password
+ * @param [argDatabaseName] database
+ *
+ * @return return true or false
+ */
+ function PConnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "")
+ {
+ if (defined('ADODB_NEVER_PERSIST'))
+ return $this->Connect($argHostname,$argUsername,$argPassword,$argDatabaseName);
+
+ if ($argHostname != "") $this->host = $argHostname;
+ if ($argUsername != "") $this->user = $argUsername;
+ if ($argPassword != "") $this->password = $argPassword;
+ if ($argDatabaseName != "") $this->database = $argDatabaseName;
+
+ $this->_isPersistentConnection = true;
+ if ($rez = $this->_pconnect($this->host, $this->user, $this->password, $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 = 0;
+ }
+ 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;
+ }
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysDate;
+ return $col; // child class implement
+ }
+
+ /**
+ * Should prepare the sql statement and return the stmt resource.
+ * For databases that do not support this, we return the $sql. To ensure
+ * compatibility with databases that do not support prepare:
+ *
+ * $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 sql SQL to send to database
+ *
+ * @return return FALSE, or the prepared statement, or the original sql if
+ * if the database does not support prepare.
+ *
+ */
+ function Prepare($sql)
+ {
+ return $sql;
+ }
+
+ /**
+ * Some databases, eg. mssql require a different function for preparing
+ * stored procedures. So we cannot use Prepare().
+ *
+ * Should prepare the stored procedure and return the stmt resource.
+ * For databases that do not support this, we return the $sql. To ensure
+ * compatibility with databases that do not support prepare:
+ *
+ * @param sql SQL to send to database
+ *
+ * @return return FALSE, or the prepared statement, or the original sql if
+ * if the database does not support prepare.
+ *
+ */
+ function PrepareSP($sql,$param=true)
+ {
+ return $this->Prepare($sql,$param);
+ }
+
+ /**
+ * PEAR DB Compat
+ */
+ function Quote($s)
+ {
+ return $this->qstr($s,false);
+ }
+
+ /**
+ Requested by "Karsten Dambekalns" <k.dambekalns@fishfarm.de>
+ */
+ function QMagic($s)
+ {
+ return $this->qstr($s,get_magic_quotes_gpc());
+ }
+
+ function q(&$s)
+ {
+ #if (!empty($this->qNull)) if ($s == 'null') return $s;
+ $s = $this->qstr($s,false);
+ }
+
+ /**
+ * PEAR DB Compat - do not use internally.
+ */
+ function ErrorNative()
+ {
+ return $this->ErrorNo();
+ }
+
+
+ /**
+ * PEAR DB Compat - do not use internally.
+ */
+ function nextId($seq_name)
+ {
+ return $this->GenID($seq_name);
+ }
+
+ /**
+ * Lock a row, will escalate and lock the table if row locking not supported
+ * will normally free the lock at the end of the transaction
+ *
+ * @param $table name of table to lock
+ * @param $where where clause to use, eg: "WHERE row=12". If left empty, will escalate to table lock
+ */
+ function RowLock($table,$where)
+ {
+ return false;
+ }
+
+ function CommitLock($table)
+ {
+ return $this->CommitTrans();
+ }
+
+ 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 mode The fetchmode ADODB_FETCH_ASSOC or ADODB_FETCH_NUM
+ * @returns The 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.
+ */
+ 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 placeholder for parameter, eg.
+ $DB->Param('a')
+
+ will return ':a' for Oracle, and '?' for most other databases...
+
+ For databases that require positioned params, eg $1, $2, $3 for postgresql,
+ pass in Param(false) before setting the first parameter.
+ */
+ function Param($name,$type='C')
+ {
+ return '?';
+ }
+
+ /*
+ InParameter and OutParameter are self-documenting versions of Parameter().
+ */
+ function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
+ {
+ return $this->Parameter($stmt,$var,$name,false,$maxLen,$type);
+ }
+
+ /*
+ */
+ 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 $stmt Statement returned by Prepare() or PrepareSP().
+ @param $var PHP variable to bind to
+ @param $name Name of stored procedure variable name to bind to.
+ @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
+ @param [$maxLen] Holds an maximum length of the variable.
+ @param [$type] The data type of $var. Legal values depend on driver.
+
+ */
+ 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;
+ }
+
+ $this->_oldRaiseFn = $this->raiseErrorFn;
+ $this->raiseErrorFn = $errfn;
+ $this->_transOK = true;
+
+ if ($this->debug && $this->transCnt > 0) ADOConnection::outp("Bad Transaction: StartTrans called within BeginTrans");
+ $this->BeginTrans();
+ $this->transOff = 1;
+ }
+
+
+ /**
+ Used together with StartTrans() to end a transaction. Monitors connection
+ for sql errors, and will commit or rollback as appropriate.
+
+ @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 sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
+ * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
+ * @return RecordSet or false
+ */
+ function &Execute($sql,$inputarr=false)
+ {
+ if ($this->fnExecute) {
+ $fn = $this->fnExecute;
+ $ret =& $fn($this,$sql,$inputarr);
+ if (isset($ret)) return $ret;
+ }
+ if ($inputarr) {
+ if (!is_array($inputarr)) $inputarr = array($inputarr);
+
+ $element0 = reset($inputarr);
+ # is_object check because oci8 descriptors can be passed in
+ $array_2d = is_array($element0) && !is_object(reset($element0));
+ //remove extra memory copy of input -mikefedyk
+ unset($element0);
+
+ if (!is_array($sql) && !$this->_bindInputArray) {
+ $sqlarr = explode('?',$sql);
+
+ if (!$array_2d) $inputarr = array($inputarr);
+ foreach($inputarr as $arr) {
+ $sql = ''; $i = 0;
+ //Use each() instead of foreach to reduce memory usage -mikefedyk
+ while(list(, $v) = each($arr)) {
+ $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 (isset($sqlarr[$i])) {
+ $sql .= $sqlarr[$i];
+ if ($i+1 != sizeof($sqlarr)) ADOConnection::outp( "Input Array does not match ?: ".htmlspecialchars($sql));
+ } else if ($i != sizeof($sqlarr))
+ ADOConnection::outp( "Input array does not match ?: ".htmlspecialchars($sql));
+
+ $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)
+ {
+ if ($this->debug) {
+ global $ADODB_INCLUDED_LIB;
+ if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
+ $this->_queryID = _adodb_debug_execute($this, $sql,$inputarr);
+ } else {
+ $this->_queryID = @$this->_query($sql,$inputarr);
+ }
+
+ /************************
+ // OK, query executed
+ *************************/
+
+ if ($this->_queryID === false) { // error handling if query fails
+ if ($this->debug == 99) adodb_backtrace(true,5);
+ $fn = $this->raiseErrorFn;
+ if ($fn) {
+ $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr,$this);
+ }
+ $false = false;
+ return $false;
+ }
+
+ if ($this->_queryID === true) { // return simplified recordset for inserts/updates/deletes with lower overhead
+ $rs = new ADORecordSet_empty();
+ return $rs;
+ }
+
+ // return real recordset from select statement
+ $rsclass = $this->rsPrefix.$this->databaseType;
+ $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;
+ }
+
+ 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 seqname name of sequence to use
+ * @param startID if sequence does not exist, start at this ID
+ * @return 0 if not supported, otherwise a sequence id
+ */
+ 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;
+ }
+
+ /**
+ * @param $table string name of the table, not needed by all databases (eg. mysql), default ''
+ * @param $column string name of the column, not needed by all databases (eg. mysql), default ''
+ * @return the last inserted ID. Not all databases support this.
+ */
+ 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;
+ }
+
+
+ /**
+ * Portable Insert ID. Pablo Roca <pabloroca#mvps.org>
+ *
+ * @return the last inserted ID. All databases support this. But aware possible
+ * problems in multiuser environments. Heavy 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 # 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 the last error message
+ */
+ function ErrorMsg()
+ {
+ if ($this->_errorMsg) return '!! '.strtoupper($this->dataProvider.' '.$this->databaseType).': '.$this->_errorMsg;
+ else return '';
+ }
+
+
+ /**
+ * @return 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 assoc array where keys are tables, and values are foreign keys
+ */
+ function MetaForeignKeys($table, $owner=false, $upper=false)
+ {
+ return false;
+ }
+ /**
+ * Choose a database to connect to. Many databases do not support this.
+ *
+ * @param dbName is the name of the database to select
+ * @return true or false
+ */
+ function SelectDB($dbName)
+ {return false;}
+
+
+ /**
+ * 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 sql
+ * @param [offset] is the row to start calculations from (1-based)
+ * @param [nrows] is the number of rows to get
+ * @param [inputarr] array of bind variables
+ * @param [secs2cache] is a private parameter only used by jlim
+ * @return the recordset ($rs->databaseType == 'array')
+ */
+ function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
+ {
+ 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 result
+ if ($isaccess) {
+ $sql = preg_replace(
+ '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop.' '.((integer)$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.' '.((integer)$nrows).' ',$sql);
+ } else {
+ $sql = preg_replace(
+ '/(^\s*select\s)/i','\\1 '.$this->hasTop.' '.((integer)$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;
+
+ $savec = $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = false;
+
+ if ($offset>0){
+ if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
+ else $rs = &$this->Execute($sql,$inputarr);
+ } else {
+ if ($secs2cache != 0) $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
+ else $rs = &$this->Execute($sql,$inputarr);
+ }
+ $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 rs the recordset to serialize
+ */
+ function &SerializableRS(&$rs)
+ {
+ $rs2 =& $this->_rs2rs($rs);
+ $ignore = false;
+ $rs2->connection =& $ignore;
+
+ return $rs2;
+ }
+
+ /**
+ * Convert database recordset to an array recordset
+ * input recordset's cursor should be at beginning, and
+ * old $rs will be closed.
+ *
+ * @param rs the recordset to copy
+ * @param [nrows] number of rows to retrieve (optional)
+ * @param [offset] offset by number of rows (optional)
+ * @return the new recordset
+ */
+ function &_rs2rs(&$rs,$nrows=-1,$offset=-1,$close=true)
+ {
+ if (! $rs) {
+ $false = false;
+ return $false;
+ }
+ $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();
+ $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
+ */
+ function &GetAll($sql, $inputarr=false)
+ {
+ $arr =& $this->GetArray($sql,$inputarr);
+ return $arr;
+ }
+
+ function &GetAssoc($sql, $inputarr=false,$force_array = false, $first2cols = false)
+ {
+ $rs =& $this->Execute($sql, $inputarr);
+ if (!$rs) {
+ $false = false;
+ return $false;
+ }
+ $arr =& $rs->GetAssoc($force_array,$first2cols);
+ return $arr;
+ }
+
+ 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) {
+ $false = false;
+ return $false;
+ }
+ $arr =& $rs->GetAssoc($force_array,$first2cols);
+ return $arr;
+ }
+
+ /**
+ * Return first element of first row of sql statement. Recordset is disposed
+ * for you.
+ *
+ * @param sql SQL statement
+ * @param [inputarr] input bind array
+ */
+ function GetOne($sql,$inputarr=false)
+ {
+ global $ADODB_COUNTRECS;
+ $crecs = $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = false;
+
+ $ret = false;
+ $rs = &$this->Execute($sql,$inputarr);
+ if ($rs) {
+ if (!$rs->EOF) $ret = reset($rs->fields);
+ $rs->Close();
+ }
+ $ADODB_COUNTRECS = $crecs;
+ return $ret;
+ }
+
+ function CacheGetOne($secs2cache,$sql=false,$inputarr=false)
+ {
+ $ret = false;
+ $rs = &$this->CacheExecute($secs2cache,$sql,$inputarr);
+ if ($rs) {
+ if (!$rs->EOF) $ret = reset($rs->fields);
+ $rs->Close();
+ }
+
+ return $ret;
+ }
+
+ function GetCol($sql, $inputarr = false, $trim = false)
+ {
+ $rv = 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();
+ }
+ return $rv;
+ }
+
+ function CacheGetCol($secs, $sql = false, $inputarr = false,$trim=false)
+ {
+ $rv = false;
+ $rs = &$this->CacheExecute($secs, $sql, $inputarr);
+ if ($rs) {
+ if ($trim) {
+ while (!$rs->EOF) {
+ $rv[] = trim(reset($rs->fields));
+ $rs->MoveNext();
+ }
+ } else {
+ while (!$rs->EOF) {
+ $rv[] = reset($rs->fields);
+ $rs->MoveNext();
+ }
+ }
+ $rs->Close();
+ }
+ return $rv;
+ }
+
+ function &Transpose(&$rs,$addfieldnames=true)
+ {
+ $rs2 =& $this->_rs2rs($rs);
+ $false = false;
+ if (!$rs2) return $false;
+
+ $rs2->_transpose($addfieldnames);
+ return $rs2;
+ }
+
+ /*
+ 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.
+
+ If dayFraction=1.5 means 1.5 days from now, 1.0/24 for 1 hour.
+ */
+ function OffsetDate($dayFraction,$date=false)
+ {
+ if (!$date) $date = $this->sysDate;
+ return '('.$date.'+'.$dayFraction.')';
+ }
+
+
+ /**
+ *
+ * @param sql SQL statement
+ * @param [inputarr] input bind array
+ */
+ function &GetArray($sql,$inputarr=false)
+ {
+ global $ADODB_COUNTRECS;
+
+ $savec = $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = false;
+ $rs =& $this->Execute($sql,$inputarr);
+ $ADODB_COUNTRECS = $savec;
+ if (!$rs)
+ if (defined('ADODB_PEAR')) {
+ $cls = ADODB_PEAR_Error();
+ return $cls;
+ } else {
+ $false = false;
+ return $false;
+ }
+ $arr =& $rs->GetArray();
+ $rs->Close();
+ return $arr;
+ }
+
+ function &CacheGetAll($secs2cache,$sql=false,$inputarr=false)
+ {
+ $arr =& $this->CacheGetArray($secs2cache,$sql,$inputarr);
+ return $arr;
+ }
+
+ function &CacheGetArray($secs2cache,$sql=false,$inputarr=false)
+ {
+ global $ADODB_COUNTRECS;
+
+ $savec = $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = false;
+ $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
+ $ADODB_COUNTRECS = $savec;
+
+ if (!$rs)
+ if (defined('ADODB_PEAR')) {
+ $cls = ADODB_PEAR_Error();
+ return $cls;
+ } else {
+ $false = false;
+ return $false;
+ }
+ $arr =& $rs->GetArray();
+ $rs->Close();
+ return $arr;
+ }
+
+
+
+ /**
+ * Return one row of sql statement. Recordset is disposed for you.
+ *
+ * @param sql SQL statement
+ * @param [inputarr] input bind array
+ */
+ function &GetRow($sql,$inputarr=false)
+ {
+ global $ADODB_COUNTRECS;
+ $crecs = $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = false;
+
+ $rs =& $this->Execute($sql,$inputarr);
+
+ $ADODB_COUNTRECS = $crecs;
+ if ($rs) {
+ if (!$rs->EOF) $arr = $rs->fields;
+ else $arr = array();
+ $rs->Close();
+ return $arr;
+ }
+
+ $false = false;
+ return $false;
+ }
+
+ function &CacheGetRow($secs2cache,$sql=false,$inputarr=false)
+ {
+ $rs =& $this->CacheExecute($secs2cache,$sql,$inputarr);
+ if ($rs) {
+ $arr = false;
+ if (!$rs->EOF) $arr = $rs->fields;
+ $rs->Close();
+ return $arr;
+ }
+ $false = false;
+ 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 hueristic 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(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 [secs2cache] seconds to cache data, set to 0 to force query. This is optional
+ * @param sql
+ * @param [offset] is the row to start calculations from (1-based)
+ * @param [nrows] is the number of rows to get
+ * @param [inputarr] array of bind variables
+ * @return 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) ADOConnection::outp( "Warning: \$sql missing from 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.
+ */
+
+ /**
+ * 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;
+
+ if ($this->memCache) {
+ global $ADODB_INCLUDED_MEMCACHE;
+
+ $key = false;
+ if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php');
+ if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true);
+ FlushMemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug);
+ return;
+ }
+
+ if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
+ /*if (strncmp(PHP_OS,'WIN',3) === 0)
+ $dir = str_replace('/', '\\', $ADODB_CACHE_DIR);
+ else */
+ $dir = $ADODB_CACHE_DIR;
+
+ if ($this->debug) {
+ ADOConnection::outp( "CacheFlush: $dir<br><pre>\n", $this->_dirFlush($dir),"</pre>");
+ } else {
+ $this->_dirFlush($dir);
+ }
+ return;
+ }
+
+ global $ADODB_INCLUDED_CSV;
+ if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
+
+ $f = $this->_gencachename($sql.serialize($inputarr),false);
+ adodb_write_file($f,''); // is adodb_write_file needed?
+ if (!@unlink($f)) {
+ if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
+ }
+ }
+
+ /**
+ * 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;
+
+ if (!@unlink($dir.'/'.$obj))
+ $this->_dirFlush($dir.'/'.$obj, true);
+ }
+ if ($kill_top_level === true)
+ @rmdir($dir);
+ return true;
+ }
+
+
+ function xCacheFlush($sql=false,$inputarr=false)
+ {
+ global $ADODB_CACHE_DIR;
+
+ if ($this->memCache) {
+ global $ADODB_INCLUDED_MEMCACHE;
+ $key = false;
+ if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php');
+ if ($sql) $key = $this->_gencachename($sql.serialize($inputarr),false,true);
+ flushmemCache($key, $this->memCacheHost, $this->memCachePort, $this->debug);
+ return;
+ }
+
+ if (strlen($ADODB_CACHE_DIR) > 1 && !$sql) {
+ if (strncmp(PHP_OS,'WIN',3) === 0) {
+ $cmd = 'del /s '.str_replace('/','\\',$ADODB_CACHE_DIR).'\adodb_*.cache';
+ } else {
+ //$cmd = 'find "'.$ADODB_CACHE_DIR.'" -type f -maxdepth 1 -print0 | xargs -0 rm -f';
+ $cmd = 'rm -rf '.$ADODB_CACHE_DIR.'/[0-9a-f][0-9a-f]/';
+ // old version 'rm -f `find '.$ADODB_CACHE_DIR.' -name adodb_*.cache`';
+ }
+ if ($this->debug) {
+ ADOConnection::outp( "CacheFlush: $cmd<br><pre>\n", system($cmd),"</pre>");
+ } else {
+ exec($cmd);
+ }
+ return;
+ }
+
+ global $ADODB_INCLUDED_CSV;
+ if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
+
+ $f = $this->_gencachename($sql.serialize($inputarr),false);
+ adodb_write_file($f,''); // is adodb_write_file needed?
+ if (!@unlink($f)) {
+ if ($this->debug) ADOConnection::outp( "CacheFlush: failed for $f");
+ }
+ }
+
+ /**
+ * 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)
+ *
+ * When not in safe mode, 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,$memcache=false)
+ {
+ global $ADODB_CACHE_DIR;
+ static $notSafeMode;
+
+ 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 ($memcache) return $m;
+
+ if (!isset($notSafeMode)) $notSafeMode = !ini_get('safe_mode');
+ $dir = ($notSafeMode) ? $ADODB_CACHE_DIR.'/'.substr($m,0,2) : $ADODB_CACHE_DIR;
+
+ if ($createdir && $notSafeMode && !file_exists($dir)) {
+ $oldu = umask(0);
+ if (!mkdir($dir,0771))
+ if ($this->debug) ADOConnection::outp( "Unable to mkdir $dir for $sql");
+ umask($oldu);
+ }
+ return $dir.'/adodb_'.$m.'.cache';
+ }
+
+
+ /**
+ * Execute SQL, caching recordsets.
+ *
+ * @param [secs2cache] seconds to cache data, set to 0 to force query.
+ * This is an optional parameter.
+ * @param sql SQL statement to execute
+ * @param [inputarr] holds the input data to bind to
+ * @return RecordSet or false
+ */
+ function &CacheExecute($secs2cache,$sql=false,$inputarr=false)
+ {
+
+
+ if (!is_numeric($secs2cache)) {
+ $inputarr = $sql;
+ $sql = $secs2cache;
+ $secs2cache = $this->cacheSecs;
+ }
+
+ if (is_array($sql)) {
+ $sqlparam = $sql;
+ $sql = $sql[0];
+ } else
+ $sqlparam = $sql;
+
+ if ($this->memCache) {
+ global $ADODB_INCLUDED_MEMCACHE;
+ if (empty($ADODB_INCLUDED_MEMCACHE)) include(ADODB_DIR.'/adodb-memcache.lib.inc.php');
+ $md5file = $this->_gencachename($sql.serialize($inputarr),false,true);
+ } else {
+ global $ADODB_INCLUDED_CSV;
+ if (empty($ADODB_INCLUDED_CSV)) include(ADODB_DIR.'/adodb-csvlib.inc.php');
+ $md5file = $this->_gencachename($sql.serialize($inputarr),true);
+ }
+
+ $err = '';
+
+ if ($secs2cache > 0){
+ if ($this->memCache)
+ $rs = &getmemCache($md5file,$err,$secs2cache, $this->memCacheHost, $this->memCachePort);
+ else
+ $rs = &csv2rs($md5file,$err,$secs2cache,$this->arrayClass);
+ $this->numCacheHits += 1;
+ } else {
+ $err='Timeout 1';
+ $rs = false;
+ $this->numCacheMisses += 1;
+ }
+ if (!$rs) {
+ // no cached rs found
+ if ($this->debug) {
+ if (get_magic_quotes_runtime() && !$this->memCache) {
+ ADOConnection::outp("Please disable magic_quotes_runtime - it corrupts cache files :(");
+ }
+ if ($this->debug !== -1) ADOConnection::outp( " $md5file cache failure: $err (see sql below)");
+ }
+
+ $rs = &$this->Execute($sqlparam,$inputarr);
+
+ if ($rs && $this->memCache) {
+ $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
+ if(!putmemCache($md5file, $rs, $this->memCacheHost, $this->memCachePort, $this->memCacheCompress, $this->debug)) {
+ if ($fn = $this->raiseErrorFn)
+ $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
+ if ($this->debug) ADOConnection::outp( " Cache write error");
+ }
+ } else
+ if ($rs) {
+ $eof = $rs->EOF;
+ $rs = &$this->_rs2rs($rs); // read entire recordset into memory immediately
+ $txt = _rs2serialize($rs,false,$sql); // serialize
+
+ if (!adodb_write_file($md5file,$txt,$this->debug)) {
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'CacheExecute',-32000,"Cache write error",$md5file,$sql,$this);
+ }
+ if ($this->debug) ADOConnection::outp( " Cache write error");
+ }
+ if ($rs->EOF && !$eof) {
+ $rs->MoveFirst();
+ //$rs = &csv2rs($md5file,$err);
+ $rs->connection = &$this; // Pablo suggestion
+ }
+
+ } else
+ if (!$this->memCache)
+ @unlink($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 suggestion
+ if ($this->debug){
+
+ $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;
+ }
+
+
+ /*
+ Similar to PEAR DB's autoExecute(), except that
+ $mode can be 'INSERT' or 'UPDATE' or DB_AUTOQUERY_INSERT or DB_AUTOQUERY_UPDATE
+ If $mode == 'UPDATE', then $where is compulsory as a safety measure.
+
+ $forceUpdate means that even if the data has not changed, perform update.
+ */
+ function& AutoExecute($table, $fields_values, $mode = 'INSERT', $where = FALSE, $forceUpdate=true, $magicq=false)
+ {
+ $false = false;
+ $sql = 'SELECT * FROM '.$table;
+ if ($where!==FALSE) $sql .= ' WHERE '.$where;
+ else if ($mode == 'UPDATE' || $mode == 2 /* DB_AUTOQUERY_UPDATE */) {
+ ADOConnection::outp('AutoExecute: Illegal mode=UPDATE with empty WHERE clause');
+ return $false;
+ }
+
+ $rs =& $this->SelectLimit($sql,1);
+ if (!$rs) return $false; // table does not exist
+ $rs->tableName = $table;
+
+ switch((string) $mode) {
+ case 'UPDATE':
+ case '2':
+ $sql = $this->GetUpdateSQL($rs, $fields_values, $forceUpdate, $magicq);
+ break;
+ case 'INSERT':
+ case '1':
+ $sql = $this->GetInsertSQL($rs, $fields_values, $magicq);
+ break;
+ default:
+ ADOConnection::outp("AutoExecute: Unknown mode=$mode");
+ return $false;
+ }
+ $ret = false;
+ if ($sql) $ret = $this->Execute($sql);
+ if ($ret) $ret = true;
+ return $ret;
+ }
+
+
+ /**
+ * 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
+ *
+ * "Jonathan Younger" <jyounger@unilab.com>
+ */
+ function GetUpdateSQL(&$rs, $arrFields,$forceUpdate=false,$magicq=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(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_getupdatesql($this,$rs,$arrFields,$forceUpdate,$magicq,$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.
+ */
+ function GetInsertSQL(&$rs, $arrFields,$magicq=false,$force=null)
+ {
+ global $ADODB_INCLUDED_LIB;
+ if (!isset($force)) {
+ global $ADODB_FORCE_TYPE;
+ $force = $ADODB_FORCE_TYPE;
+
+ }
+ if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_getinsertsql($this,$rs,$arrFields,$magicq,$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.
+ *
+ * Note: $blobtype supports 'BLOB' and 'CLOB', default is BLOB of course.
+ *
+ * Usage to update a $blobvalue which has a primary key blob_id=1 into a
+ * field blobtable.blobcolumn:
+ *
+ * UpdateBlob('blobtable', 'blobcolumn', $blobvalue, 'blob_id=1');
+ *
+ * Insert example:
+ *
+ * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ * $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+ */
+
+ function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+ return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
+ }
+
+ /**
+ * Usage:
+ * UpdateBlob('TABLE', 'COLUMN', '/path/to/file', 'ID=1');
+ *
+ * $blobtype supports 'BLOB' and 'CLOB'
+ *
+ * $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ * $conn->UpdateBlob('blobtable','blobcol',$blobpath,'id=1');
+ */
+ 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;
+ }
+
+ function SetCharSet($charset)
+ {
+ return false;
+ }
+
+ 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;
+ }
+
+ function GetCharSet()
+ {
+ return false;
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ function &GetActiveRecordsClass($class, $table,$whereOrderBy=false,$bindarr=false, $primkeyArr=false)
+ {
+ global $_ADODB_ACTIVE_DBS;
+
+ $save = $this->SetFetchMode(ADODB_FETCH_NUM);
+ if (empty($whereOrderBy)) $whereOrderBy = '1=1';
+ $rows = $this->GetAll("select * from ".$table.' WHERE '.$whereOrderBy,$bindarr);
+ $this->SetFetchMode($save);
+
+ $false = false;
+
+ if ($rows === false) {
+ return $false;
+ }
+
+
+ if (!isset($_ADODB_ACTIVE_DBS)) {
+ include(ADODB_DIR.'/adodb-active-record.inc.php');
+ }
+ if (!class_exists($class)) {
+ ADOConnection::outp("Unknown class $class in GetActiveRcordsClass()");
+ return $false;
+ }
+ $arr = array();
+ foreach($rows as $row) {
+
+ $obj = new $class($table,$primkeyArr,$this);
+ if ($obj->ErrorMsg()){
+ $this->_errorMsg = $obj->ErrorMsg();
+ return $false;
+ }
+ $obj->Set($row);
+ $arr[] = $obj;
+ }
+ return $arr;
+ }
+
+ 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->_connectionID = false;
+ return $rez;
+ }
+
+ /**
+ * Begin a Transaction. Must be followed by CommitTrans() or RollbackTrans().
+ *
+ * @return 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.aspx
+http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-isolation.html
+http://www.postgresql.org/docs/8.1/interactive/sql-set-transaction.html
+http://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;
+ }
+ }
+
+ /**
+ * If database does not support transactions, always return true as data always commited
+ *
+ * @param $ok set to false to rollback transaction, true to commit
+ *
+ * @return true/false.
+ */
+ function CommitTrans($ok=true)
+ { return true;}
+
+
+ /**
+ * If database does not support transactions, rollbacks always fail, so return false
+ *
+ * @return true/false.
+ */
+ function RollbackTrans()
+ { return false;}
+
+
+ /**
+ * return the databases that the driver can connect to.
+ * Some databases will return an empty array.
+ *
+ * @return 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;
+ }
+
+
+ /**
+ * @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;
+
+
+ $false = false;
+ 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;
+
+ $false = false;
+
+ 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)
+ {
+ $false = 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)) {
+ $false = false;
+ return $false;
+ }
+ $arr = array();
+ if ($numIndexes) {
+ $i = 0;
+ if ($useattnum) {
+ foreach($objarr as $v)
+ $arr[$v->attnum] = $v->name;
+
+ } else
+ foreach($objarr as $v) $arr[$i++] = $v->name;
+ } else
+ foreach($objarr as $v) $arr[strtoupper($v->name)] = $v->name;
+
+ return $arr;
+ }
+
+ /**
+ * Different SQL databases used different methods to combine strings together.
+ * This function provides a wrapper.
+ *
+ * param s variable number of string parameters
+ *
+ * Usage: $db->Concat($str1,$str2);
+ *
+ * @return 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 d a date in Unix date time format.
+ *
+ * @return date string in database date format
+ */
+ function DBDate($d)
+ {
+ if (empty($d) && $d !== 0) return 'null';
+
+ if (is_string($d) && !is_numeric($d)) {
+ if ($d === 'null' || strncmp($d,"'",1) === 0) 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 ts a timestamp in Unix date time format.
+ *
+ * @return timestamp string in database timestamp format
+ */
+ function DBTimeStamp($ts)
+ {
+ if (empty($ts) && $ts !== 0) return 'null';
+
+ # strlen(14) allows YYYYMMDDHHMMSS format
+ if (!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) return "'$ts'";
+
+ $ts = ADOConnection::UnixTimeStamp($ts);
+ return adodb_date($this->fmtTimeStamp,$ts);
+ }
+
+ /**
+ * Also in ADORecordSet.
+ * @param $v is a date string in YYYY-MM-DD format
+ *
+ * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+ */
+ 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-YY
+ return @adodb_mktime(0,0,0,$rr[2],$rr[3],$rr[1]);
+ }
+
+
+ /**
+ * Also in ADORecordSet.
+ * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+ *
+ * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+ */
+ 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-YY
+ if (!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]);
+ }
+
+ /**
+ * Also in ADORecordSet.
+ *
+ * Format database date based on user defined format.
+ *
+ * @param v is the character date in YYYY-MM-DD format, returned by database
+ * @param fmt is the format to apply to it, using date()
+ *
+ * @return a date formated as user desires
+ */
+
+ function UserDate($v,$fmt='Y-m-d',$gmt=false)
+ {
+ $tt = $this->UnixDate($v);
+
+ // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
+ if (($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);
+
+ }
+
+ /**
+ *
+ * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
+ * @param fmt is the format to apply to it, using date()
+ *
+ * @return a timestamp formated as user desires
+ */
+ function UserTimeStamp($v,$fmt='Y-m-d H:i:s',$gmt=false)
+ {
+ if (!isset($v)) return $this->emptyTimeStamp;
+ # strlen(14) allows YYYYMMDDHHMMSS format
+ if (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_YEAR
+ if (($tt === false || $tt == -1) && $v != false) return $v;
+ if ($tt == 0) return $this->emptyTimeStamp;
+ return ($gmt) ? adodb_gmdate($fmt,$tt) : adodb_date($fmt,$tt);
+ }
+
+ function escape($s,$magic_quotes=false)
+ {
+ return $this->addq($s,$magic_quotes);
+ }
+
+ /**
+ * Quotes a string, without prefixing nor appending quotes.
+ */
+ function addq($s,$magic_quotes=false)
+ {
+ if (!$magic_quotes) {
+
+ if ($this->replaceQuote[0] == '\\'){
+ // only since php 4.0.5
+ $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+ //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
+ }
+ return str_replace("'",$this->replaceQuote,$s);
+ }
+
+ // undo magic quotes for "
+ $s = str_replace('\\"','"',$s);
+
+ if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
+ return $s;
+ else {// change \' to '' for sybase/mssql
+ $s = str_replace('\\\\','\\',$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",magic_quotes_runtime());
+ *
+ * @param s the string to quote
+ * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
+ * This undoes the stupidity of magic quotes for GPC.
+ *
+ * @return quoted string to be sent back to database
+ */
+ function qstr($s,$magic_quotes=false)
+ {
+ if (!$magic_quotes) {
+
+ if ($this->replaceQuote[0] == '\\'){
+ // only since php 4.0.5
+ $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+ //$s = str_replace("\0","\\\0", str_replace('\\','\\\\',$s));
+ }
+ return "'".str_replace("'",$this->replaceQuote,$s)."'";
+ }
+
+ // undo magic quotes for "
+ $s = str_replace('\\"','"',$s);
+
+ if ($this->replaceQuote == "\\'") // ' already quoted, no need to change anything
+ return "'$s'";
+ else {// change \' to '' for sybase/mssql
+ $s = str_replace('\\\\','\\',$s);
+ return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
+ }
+ }
+
+
+ /**
+ * 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.
+ *
+ * See readme.htm#ex8 for an example of usage.
+ *
+ * @param sql
+ * @param nrows is the number of rows per page to get
+ * @param page is the page number to get (1-based)
+ * @param [inputarr] array of bind variables
+ * @param [secs2cache] is a private parameter only used by jlim
+ * @return the recordset ($rs->databaseType == 'array')
+ *
+ * NOTE: phpLens uses a different algorithm and does not use PageExecute().
+ *
+ */
+ function &PageExecute($sql, $nrows, $page, $inputarr=false, $secs2cache=0)
+ {
+ global $ADODB_INCLUDED_LIB;
+ if (empty($ADODB_INCLUDED_LIB)) include(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 secs2cache seconds to cache data, set to 0 to force query
+ * @param sql
+ * @param nrows is the number of rows per page to get
+ * @param page is the page number to get (1-based)
+ * @param [inputarr] array of bind variables
+ * @return 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;
+ }*/
+ $rs =& $this->PageExecute($sql,$nrows,$page,$inputarr,$secs2cache);
+ return $rs;
+ }
+
+} // end class ADOConnection
+
+
+
+ //==============================================================================================
+ // CLASS ADOFetchObj
+ //==============================================================================================
+
+ /**
+ * Internal placeholder for record objects. Used by ADORecordSet->FetchObj().
+ */
+ class ADOFetchObj {
+ };
+
+ //==============================================================================================
+ // CLASS ADORecordSet_empty
+ //==============================================================================================
+
+ /**
+ * Lightweight recordset when there are no records to be returned
+ */
+ class ADORecordSet_empty
+ {
+ var $dataProvider = 'empty';
+ var $databaseType = false;
+ var $EOF = true;
+ var $_numOfRows = 0;
+ 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() {}
+ }
+
+ //==============================================================================================
+ // DATE AND TIME FUNCTIONS
+ //==============================================================================================
+ if (!defined('ADODB_DATE_VERSION')) include(ADODB_DIR.'/adodb-time.inc.php');
+
+ //==============================================================================================
+ // CLASS ADORecordSet
+ //==============================================================================================
+
+ if (PHP_VERSION < 5) include_once(ADODB_DIR.'/adodb-php4.inc.php');
+ else include_once(ADODB_DIR.'/adodb-iterator.inc.php');
+ /**
+ * 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 extends ADODB_BASE_RS {
+ /*
+ * public variables
+ */
+ var $dataProvider = "native";
+ var $fields = false; /// holds the current row data
+ var $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 supported
+ var $sql; /// sql text
+ var $EOF = false; /// Indicates that the current record position is after the last record in a Recordset object.
+
+ var $emptyTimeStamp = '&nbsp;'; /// what to display when $time==0
+ var $emptyDate = '&nbsp;'; /// what to display when $time==0
+ var $debug = false;
+ var $timeCreated=0; /// datetime in Unix format rs created -- for cached recordsets
+
+ var $bind = false; /// used by Fields() to hold array - should be private?
+ var $fetchMode; /// default fetch mode
+ var $connection = false; /// the parent connection
+ /*
+ * private variables
+ */
+ var $_numOfRows = -1; /** number of rows, or -1 */
+ var $_numOfFields = -1; /** number of fields in recordset */
+ var $_queryID = -1; /** This variable keeps the result link identifier. */
+ 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 */
+
+ var $_currentPage = -1; /** Added by Iván Oliva to implement recordset pagination */
+ var $_atFirstPage = false; /** Added by Iván Oliva to implement recordset pagination */
+ var $_atLastPage = false; /** Added by Iván Oliva to implement recordset pagination */
+ var $_lastPageNo = -1;
+ var $_maxRecordCount = 0;
+ var $datetime = false;
+
+ /**
+ * Constructor
+ *
+ * @param queryID this is the queryID returned by ADOConnection->_query()
+ *
+ */
+ function ADORecordSet($queryID)
+ {
+ $this->_queryID = $queryID;
+ }
+
+
+
+ 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;
+ }
+ }
+
+
+ /**
+ * Generate a SELECT tag string from a recordset, and return the string.
+ * If the recordset has 2 cols, we treat the 1st col as the containing
+ * the text to display to the user, and 2nd col as the return value. Default
+ * strings are compared with the FIRST column.
+ *
+ * @param name name of SELECT tag
+ * @param [defstr] the value to hilite. Use an array for multiple hilites for listbox.
+ * @param [blank1stItem] true to leave the 1st item in list empty
+ * @param [multiple] true for listbox, false for popup
+ * @param [size] #rows to show for listbox. not used by popup
+ * @param [selectAttr] additional attributes to defined for SELECT tag.
+ * useful for holding javascript onChange='...' handlers.
+ & @param [compareFields0] when we have 2 cols in recordset, we compare the defstr with
+ * column 0 (1st col) if this is true. This is not documented.
+ *
+ * @return HTML
+ *
+ * changes by glen.davies@cce.ac.nz to support multiple hilited items
+ */
+ function GetMenu($name,$defstr='',$blank1stItem=true,$multiple=false,
+ $size=0, $selectAttr='',$compareFields0=true)
+ {
+ global $ADODB_INCLUDED_LIB;
+ if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_getmenu($this, $name,$defstr,$blank1stItem,$multiple,
+ $size, $selectAttr,$compareFields0);
+ }
+
+
+
+ /**
+ * Generate a SELECT tag string from a recordset, and return the string.
+ * If the recordset has 2 cols, we treat the 1st col as the containing
+ * the text to display to the user, and 2nd col as the return value. Default
+ * strings are compared with the SECOND column.
+ *
+ */
+ function GetMenu2($name,$defstr='',$blank1stItem=true,$multiple=false,$size=0, $selectAttr='')
+ {
+ return $this->GetMenu($name,$defstr,$blank1stItem,$multiple,
+ $size, $selectAttr,false);
+ }
+
+ /*
+ Grouped Menu
+ */
+ function GetMenu3($name,$defstr='',$blank1stItem=true,$multiple=false,
+ $size=0, $selectAttr='')
+ {
+ global $ADODB_INCLUDED_LIB;
+ if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_getmenu_gp($this, $name,$defstr,$blank1stItem,$multiple,
+ $size, $selectAttr,false);
+ }
+
+ /**
+ * return recordset as a 2-dimensional array.
+ *
+ * @param [nRows] is the number of rows to return. -1 means every row.
+ *
+ * @return an array indexed by the rows (0-based) from the recordset
+ */
+ function &GetArray($nRows = -1)
+ {
+ global $ADODB_EXTENSION; if ($ADODB_EXTENSION) {
+ $results = adodb_getall($this,$nRows);
+ return $results;
+ }
+ $results = array();
+ $cnt = 0;
+ while (!$this->EOF && $nRows != $cnt) {
+ $results[] = $this->fields;
+ $this->MoveNext();
+ $cnt++;
+ }
+ return $results;
+ }
+
+ function &GetAll($nRows = -1)
+ {
+ $arr =& $this->GetArray($nRows);
+ return $arr;
+ }
+
+ /*
+ * Some databases allow multiple recordsets to be returned. This function
+ * will return 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 offset is the row to start calculations from (1-based)
+ * @param [nrows] is the number of rows to return
+ *
+ * @return an array indexed by the rows (0-based) from the recordset
+ */
+ function &GetArrayLimit($nrows,$offset=-1)
+ {
+ if ($offset <= 0) {
+ $arr =& $this->GetArray($nrows);
+ return $arr;
+ }
+
+ $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 [nRows] is the number of rows to return. -1 means every row.
+ *
+ * @return an array indexed by the rows (0-based) from the recordset
+ */
+ function &GetRows($nRows = -1)
+ {
+ $arr =& $this->GetArray($nRows);
+ return $arr;
+ }
+
+ /**
+ * 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.
+ *
+ * @param [force_array] 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 [first2cols] 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 an associative array indexed by the first column of the array,
+ * or false if the data has less than 2 cols.
+ */
+ function &GetAssoc($force_array = false, $first2cols = false)
+ {
+ global $ADODB_EXTENSION;
+
+ $cols = $this->_numOfFields;
+ if ($cols < 2) {
+ $false = false;
+ return $false;
+ }
+ $numIndex = isset($this->fields[0]);
+ $results = array();
+
+ if (!$first2cols && ($cols > 2 || $force_array)) {
+ if ($ADODB_EXTENSION) {
+ if ($numIndex) {
+ while (!$this->EOF) {
+ $results[trim($this->fields[0])] = array_slice($this->fields, 1);
+ adodb_movenext($this);
+ }
+ } else {
+ while (!$this->EOF) {
+ // Fix for array_slice re-numbering numeric associative keys
+ $keys = array_slice(array_keys($this->fields), 1);
+ $sliced_array = array();
+
+ foreach($keys as $key) {
+ $sliced_array[$key] = $this->fields[$key];
+ }
+
+ $results[trim(reset($this->fields))] = $sliced_array;
+ adodb_movenext($this);
+ }
+ }
+ } else {
+ if ($numIndex) {
+ while (!$this->EOF) {
+ $results[trim($this->fields[0])] = array_slice($this->fields, 1);
+ $this->MoveNext();
+ }
+ } else {
+ while (!$this->EOF) {
+ // Fix for array_slice re-numbering numeric associative keys
+ $keys = array_slice(array_keys($this->fields), 1);
+ $sliced_array = array();
+
+ foreach($keys as $key) {
+ $sliced_array[$key] = $this->fields[$key];
+ }
+
+ $results[trim(reset($this->fields))] = $sliced_array;
+ $this->MoveNext();
+ }
+ }
+ }
+ } else {
+ if ($ADODB_EXTENSION) {
+ // return scalar values
+ if ($numIndex) {
+ while (!$this->EOF) {
+ // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
+ $results[trim(($this->fields[0]))] = $this->fields[1];
+ adodb_movenext($this);
+ }
+ } else {
+ while (!$this->EOF) {
+ // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
+ $v1 = trim(reset($this->fields));
+ $v2 = ''.next($this->fields);
+ $results[$v1] = $v2;
+ adodb_movenext($this);
+ }
+ }
+ } else {
+ if ($numIndex) {
+ while (!$this->EOF) {
+ // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
+ $results[trim(($this->fields[0]))] = $this->fields[1];
+ $this->MoveNext();
+ }
+ } else {
+ while (!$this->EOF) {
+ // some bug in mssql PHP 4.02 -- doesn't handle references properly so we FORCE creating a new string
+ $v1 = trim(reset($this->fields));
+ $v2 = ''.next($this->fields);
+ $results[$v1] = $v2;
+ $this->MoveNext();
+ }
+ }
+ }
+ }
+
+ $ref =& $results; # workaround accelerator incompat with PHP 4.4 :(
+ return $ref;
+ }
+
+
+ /**
+ *
+ * @param v is the character timestamp in YYYY-MM-DD hh:mm:ss format
+ * @param fmt is the format to apply to it, using date()
+ *
+ * @return 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_YEAR
+ if (($tt === false || $tt == -1) && $v != false) return $v;
+ if ($tt === 0) return $this->emptyTimeStamp;
+ return adodb_date($fmt,$tt);
+ }
+
+
+ /**
+ * @param v is the character date in YYYY-MM-DD format, returned by database
+ * @param fmt is the format to apply to it, using date()
+ *
+ * @return a date formated as user desires
+ */
+ function UserDate($v,$fmt='Y-m-d')
+ {
+ $tt = $this->UnixDate($v);
+ // $tt == -1 if pre TIMESTAMP_FIRST_YEAR
+ if (($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 $v is a date string in YYYY-MM-DD format
+ *
+ * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+ */
+ function UnixDate($v)
+ {
+ return ADOConnection::UnixDate($v);
+ }
+
+
+ /**
+ * @param $v is a timestamp string in YYYY-MM-DD HH-NN-SS format
+ *
+ * @return date in unix timestamp format, or 0 if before TIMESTAMP_FIRST_YEAR, or false if invalid date format
+ */
+ 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
+ */
+ function NumRows()
+ {
+ return $this->_numOfRows;
+ }
+
+
+ /**
+ * PEAR DB compat, number of cols
+ */
+ function NumCols()
+ {
+ return $this->_numOfFields;
+ }
+
+ /**
+ * Fetch a row, returning false if no more rows.
+ * This is PEAR DB compat mode.
+ *
+ * @return false or array containing the current record
+ */
+ function &FetchRow()
+ {
+ if ($this->EOF) {
+ $false = false;
+ 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.
+ *
+ * @return 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 true or false
+ */
+ function MoveFirst()
+ {
+ if ($this->_currentRow == 0) return true;
+ return $this->Move(0);
+ }
+
+
+ /**
+ * Move to the last row in the recordset.
+ *
+ * @return 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 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 rowNumber is the row to move to (0-based)
+ *
+ * @return 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 ($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;
+ global $ADODB_EXTENSION;
+ if ($ADODB_EXTENSION) {
+ while (!$this->EOF && $this->_currentRow < $rowNumber) {
+ adodb_movenext($this);
+ }
+ } else {
+
+ 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;
+ }
+
+
+ /**
+ * 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 colname is the field to access
+ *
+ * @return the value of $colname column
+ */
+ function Fields($colname)
+ {
+ return $this->fields[$colname];
+ }
+
+ function GetAssocKeys($upper=true)
+ {
+ $this->bind = array();
+ for ($i=0; $i < $this->_numOfFields; $i++) {
+ $o = $this->FetchField($i);
+ if ($upper === 2) $this->bind[$o->name] = $i;
+ else $this->bind[($upper) ? strtoupper($o->name) : strtolower($o->name)] = $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
+ *
+ * If you don't want uppercase cols, set $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC
+ * before you execute your SQL statement, and access $rs->fields['col'] directly.
+ *
+ * $upper 0 = lowercase, 1 = uppercase, 2 = whatever is returned by FetchField
+ */
+ function &GetRowAssoc($upper=1)
+ {
+ $record = array();
+ // if (!$this->fields) return $record;
+
+ if (!$this->bind) {
+ $this->GetAssocKeys($upper);
+ }
+
+ foreach($this->bind as $k => $v) {
+ $record[$k] = $this->fields[$v];
+ }
+
+ return $record;
+ }
+
+
+ /**
+ * Clean up recordset
+ *
+ * @return true or false
+ */
+ 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();
+ } else
+ return true;
+ }
+
+ /**
+ * synonyms RecordCount and RowCount
+ *
+ * @return the 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.
+ */
+ function MaxRecordCount()
+ {
+ return ($this->_maxRecordCount) ? $this->_maxRecordCount : $this->RecordCount();
+ }
+
+ /**
+ * synonyms RecordCount and RowCount
+ *
+ * @return the number of rows or -1 if this is not supported
+ */
+ function RowCount() {return $this->_numOfRows;}
+
+
+ /**
+ * Portable RecordCount. Pablo Roca <pabloroca@mvps.org>
+ *
+ * @return the number of records from a previous SELECT. All databases support this.
+ *
+ * But aware possible problems in multiuser environments. For better speed the table
+ * must be indexed by the condition. Heavy test this before deploying.
+ */
+ function PO_RecordCount($table="", $condition="") {
+
+ $lnumrows = $this->_numOfRows;
+ // the database doesn't support native recordcount, so we do a workaround
+ if ($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 the ADOFieldObject of a specific column.
+ *
+ * @param fieldoffset is the column position to access(0-based).
+ *
+ * @return the ADOFieldObject for that column, or false.
+ */
+ function &FetchField($fieldoffset = -1)
+ {
+ // must be defined by child class
+
+ $false = false;
+ return $false;
+ }
+
+ /**
+ * Get the ADOFieldObjects of all columns in an array.
+ *
+ */
+ function& FieldTypesArray()
+ {
+ $arr = array();
+ for ($i=0, $max=$this->_numOfFields; $i < $max; $i++)
+ $arr[] = $this->FetchField($i);
+ return $arr;
+ }
+
+ /**
+ * 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()
+ {
+ $o =& $this->FetchObject(false);
+ return $o;
+ }
+
+ /**
+ * Return the fields array of the current row as an object for convenience.
+ * The default case is uppercase.
+ *
+ * @param $isupper to set the object property names to uppercase
+ *
+ * @return the object with the 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;
+ }
+ }
+ $i = 0;
+ if (PHP_VERSION >= 5) $o = clone($this->_obj);
+ else $o = $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 the object with the properties set to the fields of the current row,
+ * or false if EOF
+ *
+ * Fixed bug reported by tim@orotech.net
+ */
+ function &FetchNextObj()
+ {
+ $o =& $this->FetchNextObject(false);
+ return $o;
+ }
+
+
+ /**
+ * Return the fields array of the current row as an object for convenience.
+ * The default is upper case field names.
+ *
+ * @param $isupper to set the object property names to uppercase
+ *
+ * @return the object with the 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 metatype of the column. This is used for formatting. This is because
+ * many databases use different names for the same type, so we transform the original
+ * type to our standardised version which uses 1 character codes:
+ *
+ * @param t is the type passed in. Normally is ADOFieldObject->type.
+ * @param len is the maximum length of that field. This is because we treat character
+ * fields bigger than a certain size as a 'B' (blob).
+ * @param fieldobj is the field object returned by the database driver. Can hold
+ * additional info (eg. primary_key for mysql).
+ *
+ * @return the general type of the data:
+ * C for character < 250 chars
+ * X for teXt (>= 250 chars)
+ * B for Binary
+ * N for numeric or floating point
+ * D for date
+ * T for timestamp
+ * L for logical/Boolean
+ * I for integer
+ * R for autoincrement counter/integer
+ *
+ *
+ */
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $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
+ ##
+ '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
+ ##
+ 'TIME' => 'T',
+ 'TIMESTAMP' => 'T',
+ 'DATETIME' => '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'
+ );
+
+ $tmap = false;
+ $t = strtoupper($t);
+ $tmap = (isset($typeMap[$t])) ? $typeMap[$t] : 'N';
+ 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;
+ }
+ }
+
+
+ function _close() {}
+
+ /**
+ * set/returns the current recordset page when paginating
+ */
+ function AbsolutePage($page=-1)
+ {
+ if ($page != -1) $this->_currentPage = $page;
+ return $this->_currentPage;
+ }
+
+ /**
+ * set/returns the status of the atFirstPage flag when paginating
+ */
+ function AtFirstPage($status=false)
+ {
+ if ($status != false) $this->_atFirstPage = $status;
+ return $this->_atFirstPage;
+ }
+
+ function LastPageNo($page = false)
+ {
+ if ($page != false) $this->_lastPageNo = $page;
+ return $this->_lastPageNo;
+ }
+
+ /**
+ * set/returns the status of the atLastPage flag when paginating
+ */
+ 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 array
+ var $_types; // the array of types of each column (C B I L M)
+ var $_colnames; // names of each column in array
+ var $_skiprow1; // skip 1st row because it holds column names
+ var $_fieldobjects; // holds array of field objects
+ var $canSeek = true;
+ var $affectedrows = false;
+ var $insertid = false;
+ var $sql = '';
+ var $compat = false;
+ /**
+ * Constructor
+ *
+ */
+ function ADORecordSet_array($fakeid=1)
+ {
+ global $ADODB_FETCH_MODE,$ADODB_COMPAT_FETCH;
+
+ // fetch() on EOF does not delete $this->fields
+ $this->compat = !empty($ADODB_COMPAT_FETCH);
+ $this->ADORecordSet($fakeid); // fake queryID
+ $this->fetchMode = $ADODB_FETCH_MODE;
+ }
+
+ function _transpose($addfieldnames=true)
+ {
+ global $ADODB_INCLUDED_LIB;
+
+ if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
+ $hdr = true;
+
+ $fobjs = $addfieldnames ? $this->_fieldobjects : false;
+ adodb_transpose($this->_array, $newarr, $hdr, $fobjs);
+ //adodb_pr($newarr);
+
+ $this->_skiprow1 = false;
+ $this->_array =& $newarr;
+ $this->_colnames = $hdr;
+
+ adodb_probetypes($newarr,$this->_types);
+
+ $this->_fieldobjects = array();
+
+ foreach($hdr as $k => $name) {
+ $f = new ADOFieldObject();
+ $f->name = $name;
+ $f->type = $this->_types[$k];
+ $f->max_length = -1;
+ $this->_fieldobjects[] = $f;
+ }
+ $this->fields = reset($this->_array);
+
+ $this->_initrs();
+
+ }
+
+ /**
+ * Setup the array.
+ *
+ * @param array is a 2-dimensional array holding the data.
+ * The first row should hold the column names
+ * unless paramter $colnames is used.
+ * @param typearr holds an array of types. These are the same types
+ * used in MetaTypes (C,B,L,I,N).
+ * @param [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 is a 2-dimensional array holding the data.
+ * The first row should hold the column names
+ * unless paramter $colnames is used.
+ * @param fieldarr holds an array of ADOFieldObject's.
+ */
+ function InitArrayFields(&$array,&$fieldarr)
+ {
+ $this->_array =& $array;
+ $this->_skiprow1= false;
+ if ($fieldarr) {
+ $this->_fieldobjects =& $fieldarr;
+ }
+ $this->Init();
+ }
+
+ function &GetArray($nRows=-1)
+ {
+ if ($nRows == -1 && $this->_currentRow <= 0 && !$this->_skiprow1) {
+ return $this->_array;
+ } else {
+ $arr =& ADORecordSet::GetArray($nRows);
+ return $arr;
+ }
+ }
+
+ 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 */
+ function Fields($colname)
+ {
+ $mode = isset($this->adodbFetchMode) ? $this->adodbFetchMode : $this->fetchMode;
+
+ if ($mode & ADODB_FETCH_ASSOC) {
+ if (!isset($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)]];
+ }
+
+ 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 known
+
+ return $o;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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':
+ if (PHP_VERSION >= 5) $db = 'ado5';
+ $class = 'ado';
+ break;
+ case 'ifx':
+ case 'maxsql': $class = $db = 'mysqlt'; break;
+ case 'postgres':
+ case 'postgres8':
+ case 'pgsql': $class = $db = 'postgres7'; break;
+ default:
+ $class = $db; break;
+ }
+
+ $file = ADODB_DIR."/drivers/adodb-".$db.".inc.php";
+ @include_once($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
+ */
+ function &NewADOConnection($db='')
+ {
+ $tmp =& ADONewConnection($db);
+ return $tmp;
+ }
+
+ /**
+ * Instantiate a new Connection class for a specific database driver.
+ *
+ * @param [db] is the database Connection object to create. If undefined,
+ * use the last database driver that was loaded by ADOLoadCode().
+ *
+ * @return the freshly created instance of the Connection class.
+ */
+ function &ADONewConnection($db='')
+ {
+ GLOBAL $ADODB_NEWCONNECTION, $ADODB_LASTDB;
+
+ if (!defined('ADODB_ASSOC_CASE')) define('ADODB_ASSOC_CASE',2);
+ $errorfn = (defined('ADODB_ERROR_HANDLER')) ? ADODB_ERROR_HANDLER : false;
+ $false = false;
+ if ($at = strpos($db,'://')) {
+ $origdsn = $db;
+ if (PHP_VERSION < 5) $dsna = @parse_url($db);
+ else {
+ $fakedsn = 'fake'.substr($db,$at);
+ $dsna = @parse_url($fakedsn);
+ $dsna['scheme'] = substr($db,0,$at);
+
+ if (strncmp($db,'pdo',3) == 0) {
+ $sch = explode('_',$dsna['scheme']);
+ if (sizeof($sch)>1) {
+ $dsna['host'] = isset($dsna['host']) ? rawurldecode($dsna['host']) : '';
+ $dsna['host'] = rawurlencode($sch[1].':host='.rawurldecode($dsna['host']));
+ $dsna['scheme'] = 'pdo';
+ }
+ }
+ }
+
+ if (!$dsna) {
+ // special handling of oracle, which might not have host
+ $db = str_replace('@/','@adodb-fakehost/',$db);
+ $dsna = parse_url($db);
+ if (!$dsna) return $false;
+ $dsna['host'] = '';
+ }
+ $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 (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);
+
+ } else {
+
+ 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 fail
+ if ($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;
+ #ibase
+ case '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;
+ #ado
+ case 'charpage': $obj->charPage = $v; break;
+ #mysql, mysqli
+ case 'clientflags': $obj->clientFlags = $v; break;
+ #mysql, mysqli, postgres
+ case 'port': $obj->port = $v; break;
+ #mysqli
+ case 'socket': $obj->socket = $v; break;
+ #oci8
+ case 'nls_date_format': $obj->NLS_DATE_FORMAT = $v; 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 dictionary
+ function _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' : break;
+ case 'sapdb' : break;
+ default:
+ $drivername = 'generic';
+ break;
+ }
+ return $drivername;
+ }
+
+ function &NewPerfMonitor(&$conn)
+ {
+ $false = false;
+ $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;
+ $perf = new $class($conn);
+
+ return $perf;
+ }
+
+ function &NewDataDictionary(&$conn,$drivername=false)
+ {
+ $false = false;
+ 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";
+ $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 printOrArr Pass in a boolean to indicate print, or an $exception->trace array (assumes that print is true then).
+ @param levels Number of levels to display
+ */
+ function adodb_backtrace($printOrArr=true,$levels=9999)
+ {
+ global $ADODB_INCLUDED_LIB;
+ if (empty($ADODB_INCLUDED_LIB)) include(ADODB_DIR.'/adodb-lib.inc.php');
+ return _adodb_backtrace($printOrArr,$levels);
+ }
+
+
+}
+?>
diff --git a/lib/adodb/contrib/toxmlrpc.inc.php b/lib/adodb/contrib/toxmlrpc.inc.php
new file mode 100644
index 0000000..ef49235
--- /dev/null
+++ b/lib/adodb/contrib/toxmlrpc.inc.php
@@ -0,0 +1,183 @@
+<?php
+ /**
+ * Helper functions to convert between ADODB recordset objects and XMLRPC values.
+ * Uses John Lim's AdoDB and Edd Dumbill's phpxmlrpc libs
+ *
+ * @author Daniele Baroncelli
+ * @author Gaetano Giunta
+ * @copyright (c) 2003-2004 Giunta/Baroncelli. All rights reserved.
+ *
+ * @todo some more error checking here and there
+ * @todo document the xmlrpc-struct used to encode recordset info
+ * @todo verify if using xmlrpc_encode($rs->GetArray()) would work with:
+ * - ADODB_FETCH_BOTH
+ * - null values
+ */
+
+ /**
+ * Include the main libraries
+ */
+ require_once('xmlrpc.inc');
+ if (!defined('ADODB_DIR')) require_once('adodb.inc.php');
+
+ /**
+ * Builds an xmlrpc struct value out of an AdoDB recordset
+ */
+ function rs2xmlrpcval(&$adodbrs) {
+
+ $header =& rs2xmlrpcval_header($adodbrs);
+ $body =& rs2xmlrpcval_body($adodbrs);
+
+ // put it all together and build final xmlrpc struct
+ $xmlrpcrs =& new xmlrpcval ( array(
+ "header" => $header,
+ "body" => $body,
+ ), "struct");
+
+ return $xmlrpcrs;
+
+ }
+
+ /**
+ * Builds an xmlrpc struct value describing an AdoDB recordset
+ */
+ function rs2xmlrpcval_header($adodbrs)
+ {
+ $numfields = $adodbrs->FieldCount();
+ $numrecords = $adodbrs->RecordCount();
+
+ // build structure holding recordset information
+ $fieldstruct = array();
+ for ($i = 0; $i < $numfields; $i++) {
+ $fld = $adodbrs->FetchField($i);
+ $fieldarray = array();
+ if (isset($fld->name))
+ $fieldarray["name"] =& new xmlrpcval ($fld->name);
+ if (isset($fld->type))
+ $fieldarray["type"] =& new xmlrpcval ($fld->type);
+ if (isset($fld->max_length))
+ $fieldarray["max_length"] =& new xmlrpcval ($fld->max_length, "int");
+ if (isset($fld->not_null))
+ $fieldarray["not_null"] =& new xmlrpcval ($fld->not_null, "boolean");
+ if (isset($fld->has_default))
+ $fieldarray["has_default"] =& new xmlrpcval ($fld->has_default, "boolean");
+ if (isset($fld->default_value))
+ $fieldarray["default_value"] =& new xmlrpcval ($fld->default_value);
+ $fieldstruct[$i] =& new xmlrpcval ($fieldarray, "struct");
+ }
+ $fieldcount =& new xmlrpcval ($numfields, "int");
+ $recordcount =& new xmlrpcval ($numrecords, "int");
+ $sql =& new xmlrpcval ($adodbrs->sql);
+ $fieldinfo =& new xmlrpcval ($fieldstruct, "array");
+
+ $header =& new xmlrpcval ( array(
+ "fieldcount" => $fieldcount,
+ "recordcount" => $recordcount,
+ "sql" => $sql,
+ "fieldinfo" => $fieldinfo
+ ), "struct");
+
+ return $header;
+ }
+
+ /**
+ * Builds an xmlrpc struct value out of an AdoDB recordset
+ * (data values only, no data definition)
+ */
+ function rs2xmlrpcval_body($adodbrs)
+ {
+ $numfields = $adodbrs->FieldCount();
+
+ // build structure containing recordset data
+ $adodbrs->MoveFirst();
+ $rows = array();
+ while (!$adodbrs->EOF) {
+ $columns = array();
+ // This should work on all cases of fetch mode: assoc, num, both or default
+ if ($adodbrs->fetchMode == 'ADODB_FETCH_BOTH' || count($adodbrs->fields) == 2 * $adodbrs->FieldCount())
+ for ($i = 0; $i < $numfields; $i++)
+ if ($adodbrs->fields[$i] === null)
+ $columns[$i] =& new xmlrpcval ('');
+ else
+ $columns[$i] =& xmlrpc_encode ($adodbrs->fields[$i]);
+ else
+ foreach ($adodbrs->fields as $val)
+ if ($val === null)
+ $columns[] =& new xmlrpcval ('');
+ else
+ $columns[] =& xmlrpc_encode ($val);
+
+ $rows[] =& new xmlrpcval ($columns, "array");
+
+ $adodbrs->MoveNext();
+ }
+ $body =& new xmlrpcval ($rows, "array");
+
+ return $body;
+ }
+
+ /**
+ * Returns an xmlrpc struct value as string out of an AdoDB recordset
+ */
+ function rs2xmlrpcstring (&$adodbrs) {
+ $xmlrpc = rs2xmlrpcval ($adodbrs);
+ if ($xmlrpc)
+ return $xmlrpc->serialize();
+ else
+ return null;
+ }
+
+ /**
+ * Given a well-formed xmlrpc struct object returns an AdoDB object
+ *
+ * @todo add some error checking on the input value
+ */
+ function xmlrpcval2rs (&$xmlrpcval) {
+
+ $fields_array = array();
+ $data_array = array();
+
+ // rebuild column information
+ $header =& $xmlrpcval->structmem('header');
+
+ $numfields = $header->structmem('fieldcount');
+ $numfields = $numfields->scalarval();
+ $numrecords = $header->structmem('recordcount');
+ $numrecords = $numrecords->scalarval();
+ $sqlstring = $header->structmem('sql');
+ $sqlstring = $sqlstring->scalarval();
+
+ $fieldinfo =& $header->structmem('fieldinfo');
+ for ($i = 0; $i < $numfields; $i++) {
+ $temp =& $fieldinfo->arraymem($i);
+ $fld =& new ADOFieldObject();
+ while (list($key,$value) = $temp->structeach()) {
+ if ($key == "name") $fld->name = $value->scalarval();
+ if ($key == "type") $fld->type = $value->scalarval();
+ if ($key == "max_length") $fld->max_length = $value->scalarval();
+ if ($key == "not_null") $fld->not_null = $value->scalarval();
+ if ($key == "has_default") $fld->has_default = $value->scalarval();
+ if ($key == "default_value") $fld->default_value = $value->scalarval();
+ } // while
+ $fields_array[] = $fld;
+ } // for
+
+ // fetch recordset information into php array
+ $body =& $xmlrpcval->structmem('body');
+ for ($i = 0; $i < $numrecords; $i++) {
+ $data_array[$i]= array();
+ $xmlrpcrs_row =& $body->arraymem($i);
+ for ($j = 0; $j < $numfields; $j++) {
+ $temp =& $xmlrpcrs_row->arraymem($j);
+ $data_array[$i][$j] = $temp->scalarval();
+ } // for j
+ } // for i
+
+ // finally build in-memory recordset object and return it
+ $rs =& new ADORecordSet_array();
+ $rs->InitArrayFields($data_array,$fields_array);
+ return $rs;
+
+ }
+
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-access.inc.php b/lib/adodb/datadict/datadict-access.inc.php
new file mode 100644
index 0000000..4b62eb8
--- /dev/null
+++ b/lib/adodb/datadict/datadict-access.inc.php
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_access extends ADODB_DataDict {
+
+ var $databaseType = 'access';
+ var $seqField = false;
+
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'TEXT';
+ case 'XL':
+ case 'X': return 'MEMO';
+
+ case 'C2': return 'TEXT'; // up to 32K
+ case 'X2': return 'MEMO';
+
+ case 'B': return 'BINARY';
+
+ case 'D': return 'DATETIME';
+ case 'T': return 'DATETIME';
+
+ case 'L': return 'BYTE';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'BYTE';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'INTEGER';
+
+ case 'F': return 'DOUBLE';
+ case 'N': return 'NUMERIC';
+ default:
+ return $meta;
+ }
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
+ {
+ if ($fautoinc) {
+ $ftype = 'COUNTER';
+ return '';
+ }
+ if (substr($ftype,0,7) == 'DECIMAL') $ftype = 'DECIMAL';
+ $suffix = '';
+ if (strlen($fdefault)) {
+ //$suffix .= " DEFAULT $fdefault";
+ if ($this->debug) ADOConnection::outp("Warning: Access does not supported DEFAULT values (field $fname)");
+ }
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ function CreateDatabase($dbname,$options=false)
+ {
+ return array();
+ }
+
+
+ function SetSchema($schema)
+ {
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+ return array();
+ }
+
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+ return array();
+ }
+
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-db2.inc.php b/lib/adodb/datadict/datadict-db2.inc.php
new file mode 100644
index 0000000..21191b3
--- /dev/null
+++ b/lib/adodb/datadict/datadict-db2.inc.php
@@ -0,0 +1,143 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_db2 extends ADODB_DataDict {
+
+ var $databaseType = 'db2';
+ var $seqField = false;
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'XL': return 'CLOB';
+ case 'X': return 'VARCHAR(3600)';
+
+ case 'C2': return 'VARCHAR'; // up to 32K
+ case 'X2': return 'VARCHAR(3600)'; // up to 32000, but default page size too small
+
+ case 'B': return 'BLOB';
+
+ case 'D': return 'DATE';
+ case 'T': return 'TIMESTAMP';
+
+ case 'L': return 'SMALLINT';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'SMALLINT';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'BIGINT';
+
+ case 'F': return 'DOUBLE';
+ case 'N': return 'DECIMAL';
+ default:
+ return $meta;
+ }
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+ {
+ $suffix = '';
+ if ($fautoinc) return ' GENERATED ALWAYS AS IDENTITY'; # as identity start with
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+ return array();
+ }
+
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+ return array();
+ }
+
+
+ function ChangeTableSQL($tablename, $flds, $tableoptions = false)
+ {
+
+ /**
+ Allow basic table changes to DB2 databases
+ DB2 will fatally reject changes to non character columns
+
+ */
+
+ $validTypes = array("CHAR","VARC");
+ $invalidTypes = array("BIGI","BLOB","CLOB","DATE", "DECI","DOUB", "INTE", "REAL","SMAL", "TIME");
+ // check table exists
+ $cols = &$this->MetaColumns($tablename);
+ if ( empty($cols)) {
+ return $this->CreateTableSQL($tablename, $flds, $tableoptions);
+ }
+
+ // already exists, alter table instead
+ list($lines,$pkey) = $this->_GenFields($flds);
+ $alter = 'ALTER TABLE ' . $this->TableName($tablename);
+ $sql = array();
+
+ foreach ( $lines as $id => $v ) {
+ if ( isset($cols[$id]) && is_object($cols[$id]) ) {
+ /**
+ If the first field of $v is the fieldname, and
+ the second is the field type/size, we assume its an
+ attempt to modify the column size, so check that it is allowed
+ $v can have an indeterminate number of blanks between the
+ fields, so account for that too
+ */
+ $vargs = explode(' ' , $v);
+ // assume that $vargs[0] is the field name.
+ $i=0;
+ // Find the next non-blank value;
+ for ($i=1;$i<sizeof($vargs);$i++)
+ if ($vargs[$i] != '')
+ break;
+
+ // if $vargs[$i] is one of the following, we are trying to change the
+ // size of the field, if not allowed, simply ignore the request.
+ if (in_array(substr($vargs[$i],0,4),$invalidTypes))
+ continue;
+ // insert the appropriate DB2 syntax
+ if (in_array(substr($vargs[$i],0,4),$validTypes)) {
+ array_splice($vargs,$i,0,array('SET','DATA','TYPE'));
+ }
+
+ // Now Look for the NOT NULL statement as this is not allowed in
+ // the ALTER table statement. If it is in there, remove it
+ if (in_array('NOT',$vargs) && in_array('NULL',$vargs)) {
+ for ($i=1;$i<sizeof($vargs);$i++)
+ if ($vargs[$i] == 'NOT')
+ break;
+ array_splice($vargs,$i,2,'');
+ }
+ $v = implode(' ',$vargs);
+ $sql[] = $alter . $this->alterCol . ' ' . $v;
+ } else {
+ $sql[] = $alter . $this->addCol . ' ' . $v;
+ }
+ }
+
+ return $sql;
+ }
+
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-firebird.inc.php b/lib/adodb/datadict/datadict-firebird.inc.php
new file mode 100644
index 0000000..6598d95
--- /dev/null
+++ b/lib/adodb/datadict/datadict-firebird.inc.php
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+class ADODB2_firebird extends ADODB_DataDict {
+
+ var $databaseType = 'firebird';
+ var $seqField = false;
+ var $seqPrefix = 'gen_';
+ var $blobSize = 40000;
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'XL': return 'VARCHAR(32000)';
+ case 'X': return 'VARCHAR(4000)';
+
+ case 'C2': return 'VARCHAR'; // up to 32K
+ case 'X2': return 'VARCHAR(4000)';
+
+ case 'B': return 'BLOB';
+
+ case 'D': return 'DATE';
+ case 'T': return 'TIMESTAMP';
+
+ case 'L': return 'SMALLINT';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'SMALLINT';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'INTEGER';
+
+ case 'F': return 'DOUBLE PRECISION';
+ case 'N': return 'DECIMAL';
+ default:
+ return $meta;
+ }
+ }
+
+ function NameQuote($name = NULL)
+ {
+ if (!is_string($name)) {
+ return FALSE;
+ }
+
+ $name = trim($name);
+
+ if ( !is_object($this->connection) ) {
+ return $name;
+ }
+
+ $quote = $this->connection->nameQuote;
+
+ // if name is of the form `name`, quote it
+ if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
+ return $quote . $matches[1] . $quote;
+ }
+
+ // if name contains special characters, quote it
+ if ( !preg_match('/^[' . $this->nameRegex . ']+$/', $name) ) {
+ return $quote . $name . $quote;
+ }
+
+ return $quote . $name . $quote;
+ }
+
+ function CreateDatabase($dbname, $options=false)
+ {
+ $options = $this->_Options($options);
+ $sql = array();
+
+ $sql[] = "DECLARE EXTERNAL FUNCTION LOWER CSTRING(80) RETURNS CSTRING(80) FREE_IT ENTRY_POINT 'IB_UDF_lower' MODULE_NAME 'ib_udf'";
+
+ return $sql;
+ }
+
+ function _DropAutoIncrement($t)
+ {
+ if (strpos($t,'.') !== false) {
+ $tarr = explode('.',$t);
+ return 'DROP GENERATOR '.$tarr[0].'."gen_'.$tarr[1].'"';
+ }
+ return 'DROP GENERATOR "GEN_'.$t;
+ }
+
+
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
+ {
+ $suffix = '';
+
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if ($fautoinc) $this->seqField = $fname;
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+
+ return $suffix;
+ }
+
+/*
+CREATE or replace TRIGGER jaddress_insert
+before insert on jaddress
+for each row
+begin
+IF ( NEW."seqField" IS NULL OR NEW."seqField" = 0 ) THEN
+ NEW."seqField" = GEN_ID("GEN_tabname", 1);
+end;
+*/
+ function _Triggers($tabname,$tableoptions)
+ {
+ if (!$this->seqField) return array();
+
+ $tab1 = preg_replace( '/"/', '', $tabname );
+ if ($this->schema) {
+ $t = strpos($tab1,'.');
+ if ($t !== false) $tab = substr($tab1,$t+1);
+ else $tab = $tab1;
+ $seqField = $this->seqField;
+ $seqname = $this->schema.'.'.$this->seqPrefix.$tab;
+ $trigname = $this->schema.'.trig_'.$this->seqPrefix.$tab;
+ } else {
+ $seqField = $this->seqField;
+ $seqname = $this->seqPrefix.$tab1;
+ $trigname = 'trig_'.$seqname;
+ }
+ if (isset($tableoptions['REPLACE']))
+ { $sql[] = "DROP GENERATOR \"$seqname\"";
+ $sql[] = "CREATE GENERATOR \"$seqname\"";
+ $sql[] = "ALTER TRIGGER \"$trigname\" BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END";
+ }
+ else
+ { $sql[] = "CREATE GENERATOR \"$seqname\"";
+ $sql[] = "CREATE TRIGGER \"$trigname\" FOR $tabname BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END";
+ }
+
+ $this->seqField = false;
+ return $sql;
+ }
+
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-generic.inc.php b/lib/adodb/datadict/datadict-generic.inc.php
new file mode 100644
index 0000000..fc5ba76
--- /dev/null
+++ b/lib/adodb/datadict/datadict-generic.inc.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_generic extends ADODB_DataDict {
+
+ var $databaseType = 'generic';
+ var $seqField = false;
+
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'XL':
+ case 'X': return 'VARCHAR(250)';
+
+ case 'C2': return 'VARCHAR';
+ case 'X2': return 'VARCHAR(250)';
+
+ case 'B': return 'VARCHAR';
+
+ case 'D': return 'DATE';
+ case 'T': return 'DATE';
+
+ case 'L': return 'DECIMAL(1)';
+ case 'I': return 'DECIMAL(10)';
+ case 'I1': return 'DECIMAL(3)';
+ case 'I2': return 'DECIMAL(5)';
+ case 'I4': return 'DECIMAL(10)';
+ case 'I8': return 'DECIMAL(20)';
+
+ case 'F': return 'DECIMAL(32,8)';
+ case 'N': return 'DECIMAL';
+ default:
+ return $meta;
+ }
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+ return array();
+ }
+
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+ return array();
+ }
+
+}
+
+/*
+//db2
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'X': return 'VARCHAR';
+
+ case 'C2': return 'VARCHAR'; // up to 32K
+ case 'X2': return 'VARCHAR';
+
+ case 'B': return 'BLOB';
+
+ case 'D': return 'DATE';
+ case 'T': return 'TIMESTAMP';
+
+ case 'L': return 'SMALLINT';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'SMALLINT';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'BIGINT';
+
+ case 'F': return 'DOUBLE';
+ case 'N': return 'DECIMAL';
+ default:
+ return $meta;
+ }
+ }
+
+// ifx
+function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';// 255
+ case 'X': return 'TEXT';
+
+ case 'C2': return 'NVARCHAR';
+ case 'X2': return 'TEXT';
+
+ case 'B': return 'BLOB';
+
+ case 'D': return 'DATE';
+ case 'T': return 'DATETIME';
+
+ case 'L': return 'SMALLINT';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'SMALLINT';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'DECIMAL(20)';
+
+ case 'F': return 'FLOAT';
+ case 'N': return 'DECIMAL';
+ default:
+ return $meta;
+ }
+ }
+*/
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-ibase.inc.php b/lib/adodb/datadict/datadict-ibase.inc.php
new file mode 100644
index 0000000..163ba81
--- /dev/null
+++ b/lib/adodb/datadict/datadict-ibase.inc.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_ibase extends ADODB_DataDict {
+
+ var $databaseType = 'ibase';
+ var $seqField = false;
+
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'XL':
+ case 'X': return 'VARCHAR(4000)';
+
+ case 'C2': return 'VARCHAR'; // up to 32K
+ case 'X2': return 'VARCHAR(4000)';
+
+ case 'B': return 'BLOB';
+
+ case 'D': return 'DATE';
+ case 'T': return 'TIMESTAMP';
+
+ case 'L': return 'SMALLINT';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'SMALLINT';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'INTEGER';
+
+ case 'F': return 'DOUBLE PRECISION';
+ case 'N': return 'DECIMAL';
+ default:
+ return $meta;
+ }
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+ return array();
+ }
+
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+ return array();
+ }
+
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-informix.inc.php b/lib/adodb/datadict/datadict-informix.inc.php
new file mode 100644
index 0000000..879813b
--- /dev/null
+++ b/lib/adodb/datadict/datadict-informix.inc.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_informix extends ADODB_DataDict {
+
+ var $databaseType = 'informix';
+ var $seqField = false;
+
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';// 255
+ case 'XL':
+ case 'X': return 'TEXT';
+
+ case 'C2': return 'NVARCHAR';
+ case 'X2': return 'TEXT';
+
+ case 'B': return 'BLOB';
+
+ case 'D': return 'DATE';
+ case 'T': return 'DATETIME YEAR TO SECOND';
+
+ case 'L': return 'SMALLINT';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'SMALLINT';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'DECIMAL(20)';
+
+ case 'F': return 'FLOAT';
+ case 'N': return 'DECIMAL';
+ default:
+ return $meta;
+ }
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
+ return array();
+ }
+
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
+ return array();
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
+ {
+ if ($fautoinc) {
+ $ftype = 'SERIAL';
+ return '';
+ }
+ $suffix = '';
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-mssql.inc.php b/lib/adodb/datadict/datadict-mssql.inc.php
new file mode 100644
index 0000000..5737c27
--- /dev/null
+++ b/lib/adodb/datadict/datadict-mssql.inc.php
@@ -0,0 +1,282 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+/*
+In ADOdb, named quotes for MS SQL Server use ". From the MSSQL Docs:
+
+ Note Delimiters are for identifiers only. Delimiters cannot be used for keywords,
+ whether or not they are marked as reserved in SQL Server.
+
+ Quoted identifiers are delimited by double quotation marks ("):
+ SELECT * FROM "Blanks in Table Name"
+
+ Bracketed identifiers are delimited by brackets ([ ]):
+ SELECT * FROM [Blanks In Table Name]
+
+ Quoted identifiers are valid only when the QUOTED_IDENTIFIER option is set to ON. By default,
+ the Microsoft OLE DB Provider for SQL Server and SQL Server ODBC driver set QUOTED_IDENTIFIER ON
+ when they connect.
+
+ In Transact-SQL, the option can be set at various levels using SET QUOTED_IDENTIFIER,
+ the quoted identifier option of sp_dboption, or the user options option of sp_configure.
+
+ When SET ANSI_DEFAULTS is ON, SET QUOTED_IDENTIFIER is enabled.
+
+ Syntax
+
+ SET QUOTED_IDENTIFIER { ON | OFF }
+
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_mssql extends ADODB_DataDict {
+ var $databaseType = 'mssql';
+ var $dropIndex = 'DROP INDEX %2$s.%1$s';
+ var $renameTable = "EXEC sp_rename '%s','%s'";
+ var $renameColumn = "EXEC sp_rename '%s.%s','%s'";
+
+ var $typeX = 'TEXT'; ## Alternatively, set it to VARCHAR(4000)
+ var $typeXL = 'TEXT';
+
+ //var $alterCol = ' ALTER COLUMN ';
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+ $len = -1; // mysql max_length is not accurate
+ switch (strtoupper($t)) {
+ case 'R':
+ case 'INT':
+ case 'INTEGER': return 'I';
+ case 'BIT':
+ case 'TINYINT': return 'I1';
+ case 'SMALLINT': return 'I2';
+ case 'BIGINT': return 'I8';
+
+ case 'REAL':
+ case 'FLOAT': return 'F';
+ default: return parent::MetaType($t,$len,$fieldobj);
+ }
+ }
+
+ function ActualType($meta)
+ {
+ switch(strtoupper($meta)) {
+
+ case 'C': return 'VARCHAR';
+ case 'XL': return (isset($this)) ? $this->typeXL : 'TEXT';
+ case 'X': return (isset($this)) ? $this->typeX : 'TEXT'; ## could be varchar(8000), but we want compat with oracle
+ case 'C2': return 'NVARCHAR';
+ case 'X2': return 'NTEXT';
+
+ case 'B': return 'IMAGE';
+
+ case 'D': return 'DATETIME';
+ case 'T': return 'DATETIME';
+ case 'L': return 'BIT';
+
+ case 'R':
+ case 'I': return 'INT';
+ case 'I1': return 'TINYINT';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INT';
+ case 'I8': return 'BIGINT';
+
+ case 'F': return 'REAL';
+ case 'N': return 'NUMERIC';
+ default:
+ return $meta;
+ }
+ }
+
+
+ function AddColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $f = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ $s = "ALTER TABLE $tabname $this->addCol";
+ foreach($lines as $v) {
+ $f[] = "\n $v";
+ }
+ $s .= implode(', ',$f);
+ $sql[] = $s;
+ return $sql;
+ }
+
+ /*
+ function AlterColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ foreach($lines as $v) {
+ $sql[] = "ALTER TABLE $tabname $this->alterCol $v";
+ }
+
+ return $sql;
+ }
+ */
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ if (!is_array($flds))
+ $flds = explode(',',$flds);
+ $f = array();
+ $s = 'ALTER TABLE ' . $tabname;
+ foreach($flds as $v) {
+ $f[] = "\n$this->dropCol ".$this->NameQuote($v);
+ }
+ $s .= implode(', ',$f);
+ $sql[] = $s;
+ return $sql;
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+ {
+ $suffix = '';
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fautoinc) $suffix .= ' IDENTITY(1,1)';
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ else if ($suffix == '') $suffix .= ' NULL';
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ /*
+CREATE TABLE
+ [ database_name.[ owner ] . | owner. ] table_name
+ ( { < column_definition >
+ | column_name AS computed_column_expression
+ | < table_constraint > ::= [ CONSTRAINT constraint_name ] }
+
+ | [ { PRIMARY KEY | UNIQUE } [ ,...n ]
+ )
+
+[ ON { filegroup | DEFAULT } ]
+[ TEXTIMAGE_ON { filegroup | DEFAULT } ]
+
+< column_definition > ::= { column_name data_type }
+ [ COLLATE < collation_name > ]
+ [ [ DEFAULT constant_expression ]
+ | [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ]
+ ]
+ [ ROWGUIDCOL]
+ [ < column_constraint > ] [ ...n ]
+
+< column_constraint > ::= [ CONSTRAINT constraint_name ]
+ { [ NULL | NOT NULL ]
+ | [ { PRIMARY KEY | UNIQUE }
+ [ CLUSTERED | NONCLUSTERED ]
+ [ WITH FILLFACTOR = fillfactor ]
+ [ON {filegroup | DEFAULT} ] ]
+ ]
+ | [ [ FOREIGN KEY ]
+ REFERENCES ref_table [ ( ref_column ) ]
+ [ ON DELETE { CASCADE | NO ACTION } ]
+ [ ON UPDATE { CASCADE | NO ACTION } ]
+ [ NOT FOR REPLICATION ]
+ ]
+ | CHECK [ NOT FOR REPLICATION ]
+ ( logical_expression )
+ }
+
+< table_constraint > ::= [ CONSTRAINT constraint_name ]
+ { [ { PRIMARY KEY | UNIQUE }
+ [ CLUSTERED | NONCLUSTERED ]
+ { ( column [ ASC | DESC ] [ ,...n ] ) }
+ [ WITH FILLFACTOR = fillfactor ]
+ [ ON { filegroup | DEFAULT } ]
+ ]
+ | FOREIGN KEY
+ [ ( column [ ,...n ] ) ]
+ REFERENCES ref_table [ ( ref_column [ ,...n ] ) ]
+ [ ON DELETE { CASCADE | NO ACTION } ]
+ [ ON UPDATE { CASCADE | NO ACTION } ]
+ [ NOT FOR REPLICATION ]
+ | CHECK [ NOT FOR REPLICATION ]
+ ( search_conditions )
+ }
+
+
+ */
+
+ /*
+ CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
+ ON { table | view } ( column [ ASC | DESC ] [ ,...n ] )
+ [ WITH < index_option > [ ,...n] ]
+ [ ON filegroup ]
+ < index_option > :: =
+ { PAD_INDEX |
+ FILLFACTOR = fillfactor |
+ IGNORE_DUP_KEY |
+ DROP_EXISTING |
+ STATISTICS_NORECOMPUTE |
+ SORT_IN_TEMPDB
+ }
+*/
+ function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+ {
+ $sql = array();
+
+ if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
+ $sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
+ if ( isset($idxoptions['DROP']) )
+ return $sql;
+ }
+
+ if ( empty ($flds) ) {
+ return $sql;
+ }
+
+ $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
+ $clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : '';
+
+ if ( is_array($flds) )
+ $flds = implode(', ',$flds);
+ $s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')';
+
+ if ( isset($idxoptions[$this->upperName]) )
+ $s .= $idxoptions[$this->upperName];
+
+
+ $sql[] = $s;
+
+ return $sql;
+ }
+
+
+ function _GetSize($ftype, $ty, $fsize, $fprec)
+ {
+ switch ($ftype) {
+ case 'INT':
+ case 'SMALLINT':
+ case 'TINYINT':
+ case 'BIGINT':
+ return $ftype;
+ }
+ if ($ty == 'T') return $ftype;
+ return parent::_GetSize($ftype, $ty, $fsize, $fprec);
+
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-mysql.inc.php b/lib/adodb/datadict/datadict-mysql.inc.php
new file mode 100644
index 0000000..a4af25f
--- /dev/null
+++ b/lib/adodb/datadict/datadict-mysql.inc.php
@@ -0,0 +1,181 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_mysql extends ADODB_DataDict {
+ var $databaseType = 'mysql';
+ var $alterCol = ' MODIFY COLUMN';
+ var $alterTableAddIndex = true;
+ var $dropTable = 'DROP TABLE IF EXISTS %s'; // requires mysql 3.22 or later
+
+ var $dropIndex = 'DROP INDEX %s ON %s';
+ var $renameColumn = 'ALTER TABLE %s CHANGE COLUMN %s %s %s'; // needs column-definition!
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ $is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->auto_increment;
+
+ $len = -1; // mysql max_length is not accurate
+ switch (strtoupper($t)) {
+ case 'STRING':
+ case 'CHAR':
+ case 'VARCHAR':
+ case 'TINYBLOB':
+ case 'TINYTEXT':
+ case 'ENUM':
+ case 'SET':
+ if ($len <= $this->blobSize) return 'C';
+
+ case 'TEXT':
+ case 'LONGTEXT':
+ case 'MEDIUMTEXT':
+ return 'X';
+
+ // php_mysql extension always returns 'blob' even if 'text'
+ // so we have to check whether binary...
+ case 'IMAGE':
+ case 'LONGBLOB':
+ case 'BLOB':
+ case 'MEDIUMBLOB':
+ return !empty($fieldobj->binary) ? 'B' : 'X';
+
+ case 'YEAR':
+ case 'DATE': return 'D';
+
+ case 'TIME':
+ case 'DATETIME':
+ case 'TIMESTAMP': return 'T';
+
+ case 'FLOAT':
+ case 'DOUBLE':
+ return 'F';
+
+ case 'INT':
+ case 'INTEGER': return $is_serial ? 'R' : 'I';
+ case 'TINYINT': return $is_serial ? 'R' : 'I1';
+ case 'SMALLINT': return $is_serial ? 'R' : 'I2';
+ case 'MEDIUMINT': return $is_serial ? 'R' : 'I4';
+ case 'BIGINT': return $is_serial ? 'R' : 'I8';
+ default: return 'N';
+ }
+ }
+
+ function ActualType($meta)
+ {
+ switch(strtoupper($meta)) {
+ case 'C': return 'VARCHAR';
+ case 'XL':return 'LONGTEXT';
+ case 'X': return 'TEXT';
+
+ case 'C2': return 'VARCHAR';
+ case 'X2': return 'LONGTEXT';
+
+ case 'B': return 'LONGBLOB';
+
+ case 'D': return 'DATE';
+ case 'T': return 'DATETIME';
+ case 'L': return 'TINYINT';
+
+ case 'R':
+ case 'I4':
+ case 'I': return 'INTEGER';
+ case 'I1': return 'TINYINT';
+ case 'I2': return 'SMALLINT';
+ case 'I8': return 'BIGINT';
+
+ case 'F': return 'DOUBLE';
+ case 'N': return 'NUMERIC';
+ default:
+ return $meta;
+ }
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
+ {
+ $suffix = '';
+ if ($funsigned) $suffix .= ' UNSIGNED';
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fautoinc) $suffix .= ' AUTO_INCREMENT';
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ /*
+ CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
+ [table_options] [select_statement]
+ create_definition:
+ col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
+ [PRIMARY KEY] [reference_definition]
+ or PRIMARY KEY (index_col_name,...)
+ or KEY [index_name] (index_col_name,...)
+ or INDEX [index_name] (index_col_name,...)
+ or UNIQUE [INDEX] [index_name] (index_col_name,...)
+ or FULLTEXT [INDEX] [index_name] (index_col_name,...)
+ or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
+ [reference_definition]
+ or CHECK (expr)
+ */
+
+ /*
+ CREATE [UNIQUE|FULLTEXT] INDEX index_name
+ ON tbl_name (col_name[(length)],... )
+ */
+
+ function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+ {
+ $sql = array();
+
+ if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
+ if ($this->alterTableAddIndex) $sql[] = "ALTER TABLE $tabname DROP INDEX $idxname";
+ else $sql[] = sprintf($this->dropIndex, $idxname, $tabname);
+
+ if ( isset($idxoptions['DROP']) )
+ return $sql;
+ }
+
+ if ( empty ($flds) ) {
+ return $sql;
+ }
+
+ if (isset($idxoptions['FULLTEXT'])) {
+ $unique = ' FULLTEXT';
+ } elseif (isset($idxoptions['UNIQUE'])) {
+ $unique = ' UNIQUE';
+ } else {
+ $unique = '';
+ }
+
+ if ( is_array($flds) ) $flds = implode(', ',$flds);
+
+ if ($this->alterTableAddIndex) $s = "ALTER TABLE $tabname ADD $unique INDEX $idxname ";
+ else $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname;
+
+ $s .= ' (' . $flds . ')';
+
+ if ( isset($idxoptions[$this->upperName]) )
+ $s .= $idxoptions[$this->upperName];
+
+ $sql[] = $s;
+
+ return $sql;
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-oci8.inc.php b/lib/adodb/datadict/datadict-oci8.inc.php
new file mode 100644
index 0000000..238fab4
--- /dev/null
+++ b/lib/adodb/datadict/datadict-oci8.inc.php
@@ -0,0 +1,290 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_oci8 extends ADODB_DataDict {
+
+ var $databaseType = 'oci8';
+ var $seqField = false;
+ var $seqPrefix = 'SEQ_';
+ var $dropTable = "DROP TABLE %s CASCADE CONSTRAINTS";
+ var $trigPrefix = 'TRIG_';
+ var $alterCol = ' MODIFY ';
+ var $typeX = 'VARCHAR(4000)';
+ var $typeXL = 'CLOB';
+
+ function MetaType($t,$len=-1)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ switch (strtoupper($t)) {
+ case 'VARCHAR':
+ case 'VARCHAR2':
+ case 'CHAR':
+ case 'VARBINARY':
+ case 'BINARY':
+ if (isset($this) && $len <= $this->blobSize) return 'C';
+ return 'X';
+
+ case 'NCHAR':
+ case 'NVARCHAR2':
+ case 'NVARCHAR':
+ if (isset($this) && $len <= $this->blobSize) return 'C2';
+ return 'X2';
+
+ case 'NCLOB':
+ case 'CLOB':
+ return 'XL';
+
+ case 'LONG RAW':
+ case 'LONG VARBINARY':
+ case 'BLOB':
+ return 'B';
+
+ case 'DATE':
+ return 'T';
+
+ case 'INT':
+ case 'SMALLINT':
+ case 'INTEGER':
+ return 'I';
+
+ default:
+ return 'N';
+ }
+ }
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'X': return $this->typeX;
+ case 'XL': return $this->typeXL;
+
+ case 'C2': return 'NVARCHAR2';
+ case 'X2': return 'NVARCHAR2(4000)';
+
+ case 'B': return 'BLOB';
+
+ case 'D':
+ case 'T': return 'DATE';
+ case 'L': return 'DECIMAL(1)';
+ case 'I1': return 'DECIMAL(3)';
+ case 'I2': return 'DECIMAL(5)';
+ case 'I':
+ case 'I4': return 'DECIMAL(10)';
+
+ case 'I8': return 'DECIMAL(20)';
+ case 'F': return 'DECIMAL';
+ case 'N': return 'DECIMAL';
+ default:
+ return $meta;
+ }
+ }
+
+ function CreateDatabase($dbname, $options=false)
+ {
+ $options = $this->_Options($options);
+ $password = isset($options['PASSWORD']) ? $options['PASSWORD'] : 'tiger';
+ $tablespace = isset($options["TABLESPACE"]) ? " DEFAULT TABLESPACE ".$options["TABLESPACE"] : '';
+ $sql[] = "CREATE USER ".$dbname." IDENTIFIED BY ".$password.$tablespace;
+ $sql[] = "GRANT CREATE SESSION, CREATE TABLE,UNLIMITED TABLESPACE,CREATE SEQUENCE TO $dbname";
+
+ return $sql;
+ }
+
+ function AddColumnSQL($tabname, $flds)
+ {
+ $f = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ $s = "ALTER TABLE $tabname ADD (";
+ foreach($lines as $v) {
+ $f[] = "\n $v";
+ }
+
+ $s .= implode(', ',$f).')';
+ $sql[] = $s;
+ return $sql;
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ $f = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ $s = "ALTER TABLE $tabname MODIFY(";
+ foreach($lines as $v) {
+ $f[] = "\n $v";
+ }
+ $s .= implode(', ',$f).')';
+ $sql[] = $s;
+ return $sql;
+ }
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ if (!is_array($flds)) $flds = explode(',',$flds);
+ foreach ($flds as $k => $v) $flds[$k] = $this->NameQuote($v);
+
+ $sql = array();
+ $s = "ALTER TABLE $tabname DROP(";
+ $s .= implode(', ',$flds).') CASCADE CONSTRAINTS';
+ $sql[] = $s;
+ return $sql;
+ }
+
+ function _DropAutoIncrement($t)
+ {
+ if (strpos($t,'.') !== false) {
+ $tarr = explode('.',$t);
+ return "drop sequence ".$tarr[0].".seq_".$tarr[1];
+ }
+ return "drop sequence seq_".$t;
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
+ {
+ $suffix = '';
+
+ if ($fdefault == "''" && $fnotnull) {// this is null in oracle
+ $fnotnull = false;
+ if ($this->debug) ADOConnection::outp("NOT NULL and DEFAULT='' illegal in Oracle");
+ }
+
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fnotnull) $suffix .= ' NOT NULL';
+
+ if ($fautoinc) $this->seqField = $fname;
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+
+ return $suffix;
+ }
+
+/*
+CREATE or replace TRIGGER jaddress_insert
+before insert on jaddress
+for each row
+begin
+select seqaddress.nextval into :new.A_ID from dual;
+end;
+*/
+ function _Triggers($tabname,$tableoptions)
+ {
+ if (!$this->seqField) return array();
+
+ if ($this->schema) {
+ $t = strpos($tabname,'.');
+ if ($t !== false) $tab = substr($tabname,$t+1);
+ else $tab = $tabname;
+ $seqname = $this->schema.'.'.$this->seqPrefix.$tab;
+ $trigname = $this->schema.'.'.$this->trigPrefix.$this->seqPrefix.$tab;
+ } else {
+ $seqname = $this->seqPrefix.$tabname;
+ $trigname = $this->trigPrefix.$seqname;
+ }
+
+ if (strlen($seqname) > 30) {
+ $seqname = $this->seqPrefix.uniqid('');
+ } // end if
+ if (strlen($trigname) > 30) {
+ $trigname = $this->trigPrefix.uniqid('');
+ } // end if
+
+ if (isset($tableoptions['REPLACE'])) $sql[] = "DROP SEQUENCE $seqname";
+ $seqCache = '';
+ if (isset($tableoptions['SEQUENCE_CACHE'])){$seqCache = $tableoptions['SEQUENCE_CACHE'];}
+ $seqIncr = '';
+ if (isset($tableoptions['SEQUENCE_INCREMENT'])){$seqIncr = ' INCREMENT BY '.$tableoptions['SEQUENCE_INCREMENT'];}
+ $seqStart = '';
+ if (isset($tableoptions['SEQUENCE_START'])){$seqIncr = ' START WITH '.$tableoptions['SEQUENCE_START'];}
+ $sql[] = "CREATE SEQUENCE $seqname $seqStart $seqIncr $seqCache";
+ $sql[] = "CREATE OR REPLACE TRIGGER $trigname BEFORE insert ON $tabname FOR EACH ROW WHEN (NEW.$this->seqField IS NULL OR NEW.$this->seqField = 0) BEGIN select $seqname.nextval into :new.$this->seqField from dual; END;";
+
+ $this->seqField = false;
+ return $sql;
+ }
+
+ /*
+ CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
+ [table_options] [select_statement]
+ create_definition:
+ col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
+ [PRIMARY KEY] [reference_definition]
+ or PRIMARY KEY (index_col_name,...)
+ or KEY [index_name] (index_col_name,...)
+ or INDEX [index_name] (index_col_name,...)
+ or UNIQUE [INDEX] [index_name] (index_col_name,...)
+ or FULLTEXT [INDEX] [index_name] (index_col_name,...)
+ or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
+ [reference_definition]
+ or CHECK (expr)
+ */
+
+
+
+ function _IndexSQL($idxname, $tabname, $flds,$idxoptions)
+ {
+ $sql = array();
+
+ if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
+ $sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
+ if ( isset($idxoptions['DROP']) )
+ return $sql;
+ }
+
+ if ( empty ($flds) ) {
+ return $sql;
+ }
+
+ if (isset($idxoptions['BITMAP'])) {
+ $unique = ' BITMAP';
+ } elseif (isset($idxoptions['UNIQUE'])) {
+ $unique = ' UNIQUE';
+ } else {
+ $unique = '';
+ }
+
+ if ( is_array($flds) )
+ $flds = implode(', ',$flds);
+ $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')';
+
+ if ( isset($idxoptions[$this->upperName]) )
+ $s .= $idxoptions[$this->upperName];
+
+ if (isset($idxoptions['oci8']))
+ $s .= $idxoptions['oci8'];
+
+
+ $sql[] = $s;
+
+ return $sql;
+ }
+
+ function GetCommentSQL($table,$col)
+ {
+ $table = $this->connection->qstr($table);
+ $col = $this->connection->qstr($col);
+ return "select comments from USER_COL_COMMENTS where TABLE_NAME=$table and COLUMN_NAME=$col";
+ }
+
+ function SetCommentSQL($table,$col,$cmt)
+ {
+ $cmt = $this->connection->qstr($cmt);
+ return "COMMENT ON COLUMN $table.$col IS $cmt";
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-postgres.inc.php b/lib/adodb/datadict/datadict-postgres.inc.php
new file mode 100644
index 0000000..c56d3b6
--- /dev/null
+++ b/lib/adodb/datadict/datadict-postgres.inc.php
@@ -0,0 +1,371 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_postgres extends ADODB_DataDict {
+
+ var $databaseType = 'postgres';
+ var $seqField = false;
+ var $seqPrefix = 'SEQ_';
+ var $addCol = ' ADD COLUMN';
+ var $quote = '"';
+ var $renameTable = 'ALTER TABLE %s RENAME TO %s'; // at least since 7.1
+ var $dropTable = 'DROP TABLE %s CASCADE';
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ $is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->unique &&
+ $fieldobj->has_default && substr($fieldobj->default_value,0,8) == 'nextval(';
+
+ switch (strtoupper($t)) {
+ case 'INTERVAL':
+ case 'CHAR':
+ case 'CHARACTER':
+ case 'VARCHAR':
+ case 'NAME':
+ case 'BPCHAR':
+ if ($len <= $this->blobSize) return 'C';
+
+ case 'TEXT':
+ return 'X';
+
+ case 'IMAGE': // user defined type
+ case 'BLOB': // user defined type
+ case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
+ case 'VARBIT':
+ case 'BYTEA':
+ return 'B';
+
+ case 'BOOL':
+ case 'BOOLEAN':
+ return 'L';
+
+ case 'DATE':
+ return 'D';
+
+ case 'TIME':
+ case 'DATETIME':
+ case 'TIMESTAMP':
+ case 'TIMESTAMPTZ':
+ return 'T';
+
+ case 'INTEGER': return !$is_serial ? 'I' : 'R';
+ case 'SMALLINT':
+ case 'INT2': return !$is_serial ? 'I2' : 'R';
+ case 'INT4': return !$is_serial ? 'I4' : 'R';
+ case 'BIGINT':
+ case 'INT8': return !$is_serial ? 'I8' : 'R';
+
+ case 'OID':
+ case 'SERIAL':
+ return 'R';
+
+ case 'FLOAT4':
+ case 'FLOAT8':
+ case 'DOUBLE PRECISION':
+ case 'REAL':
+ return 'F';
+
+ default:
+ return 'N';
+ }
+ }
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'XL':
+ case 'X': return 'TEXT';
+
+ case 'C2': return 'VARCHAR';
+ case 'X2': return 'TEXT';
+
+ case 'B': return 'BYTEA';
+
+ case 'D': return 'DATE';
+ case 'T': return 'TIMESTAMP';
+
+ case 'L': return 'BOOLEAN';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'SMALLINT';
+ case 'I2': return 'INT2';
+ case 'I4': return 'INT4';
+ case 'I8': return 'INT8';
+
+ case 'F': return 'FLOAT8';
+ case 'N': return 'NUMERIC';
+ default:
+ return $meta;
+ }
+ }
+
+ /**
+ * Adding a new Column
+ *
+ * reimplementation of the default function as postgres does NOT allow to set the default in the same statement
+ *
+ * @param string $tabname table-name
+ * @param string $flds column-names and types for the changed columns
+ * @return array with SQL strings
+ */
+ function AddColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ $alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
+ foreach($lines as $v) {
+ if (($not_null = preg_match('/NOT NULL/i',$v))) {
+ $v = preg_replace('/NOT NULL/i','',$v);
+ }
+ if (preg_match('/^([^ ]+) .*DEFAULT ([^ ]+)/',$v,$matches)) {
+ list(,$colname,$default) = $matches;
+ $sql[] = $alter . str_replace('DEFAULT '.$default,'',$v);
+ $sql[] = 'UPDATE '.$tabname.' SET '.$colname.'='.$default;
+ $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET DEFAULT ' . $default;
+ } else {
+ $sql[] = $alter . $v;
+ }
+ if ($not_null) {
+ list($colname) = explode(' ',$v);
+ $sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET NOT NULL';
+ }
+ }
+ return $sql;
+ }
+
+ /**
+ * Change the definition of one column
+ *
+ * Postgres can't do that on it's own, you need to supply the complete defintion of the new table,
+ * to allow, recreating the table and copying the content over to the new table
+ * @param string $tabname table-name
+ * @param string $flds column-name and type for the changed column
+ * @param string $tableflds complete defintion of the new table, eg. for postgres, default ''
+ * @param array/ $tableoptions options for the new table see CreateTableSQL, default ''
+ * @return array with SQL strings
+ */
+ function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
+ {
+ if (!$tableflds) {
+ if ($this->debug) ADOConnection::outp("AlterColumnSQL needs a complete table-definiton for PostgreSQL");
+ return array();
+ }
+ return $this->_recreate_copy_table($tabname,False,$tableflds,$tableoptions);
+ }
+
+ /**
+ * Drop one column
+ *
+ * Postgres < 7.3 can't do that on it's own, you need to supply the complete defintion of the new table,
+ * to allow, recreating the table and copying the content over to the new table
+ * @param string $tabname table-name
+ * @param string $flds column-name and type for the changed column
+ * @param string $tableflds complete defintion of the new table, eg. for postgres, default ''
+ * @param array/ $tableoptions options for the new table see CreateTableSQL, default ''
+ * @return array with SQL strings
+ */
+ function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
+ {
+ $has_drop_column = 7.3 <= (float) @$this->serverInfo['version'];
+ if (!$has_drop_column && !$tableflds) {
+ if ($this->debug) ADOConnection::outp("DropColumnSQL needs complete table-definiton for PostgreSQL < 7.3");
+ return array();
+ }
+ if ($has_drop_column) {
+ return ADODB_DataDict::DropColumnSQL($tabname, $flds);
+ }
+ return $this->_recreate_copy_table($tabname,$flds,$tableflds,$tableoptions);
+ }
+
+ /**
+ * Save the content into a temp. table, drop and recreate the original table and copy the content back in
+ *
+ * We also take care to set the values of the sequenz and recreate the indexes.
+ * All this is done in a transaction, to not loose the content of the table, if something went wrong!
+ * @internal
+ * @param string $tabname table-name
+ * @param string $dropflds column-names to drop
+ * @param string $tableflds complete defintion of the new table, eg. for postgres
+ * @param array/string $tableoptions options for the new table see CreateTableSQL, default ''
+ * @return array with SQL strings
+ */
+ function _recreate_copy_table($tabname,$dropflds,$tableflds,$tableoptions='')
+ {
+ if ($dropflds && !is_array($dropflds)) $dropflds = explode(',',$dropflds);
+ $copyflds = array();
+ foreach($this->MetaColumns($tabname) as $fld) {
+ if (!$dropflds || !in_array($fld->name,$dropflds)) {
+ // we need to explicit convert varchar to a number to be able to do an AlterColumn of a char column to a nummeric one
+ if (preg_match('/'.$fld->name.' (I|I2|I4|I8|N|F)/i',$tableflds,$matches) &&
+ in_array($fld->type,array('varchar','char','text','bytea'))) {
+ $copyflds[] = "to_number($fld->name,'S9999999999999D99')";
+ } else {
+ $copyflds[] = $fld->name;
+ }
+ // identify the sequence name and the fld its on
+ if ($fld->primary_key && $fld->has_default &&
+ preg_match("/nextval\('([^']+)'::text\)/",$fld->default_value,$matches)) {
+ $seq_name = $matches[1];
+ $seq_fld = $fld->name;
+ }
+ }
+ }
+ $copyflds = implode(', ',$copyflds);
+
+ $tempname = $tabname.'_tmp';
+ $aSql[] = 'BEGIN'; // we use a transaction, to make sure not to loose the content of the table
+ $aSql[] = "SELECT * INTO TEMPORARY TABLE $tempname FROM $tabname";
+ $aSql = array_merge($aSql,$this->DropTableSQL($tabname));
+ $aSql = array_merge($aSql,$this->CreateTableSQL($tabname,$tableflds,$tableoptions));
+ $aSql[] = "INSERT INTO $tabname SELECT $copyflds FROM $tempname";
+ if ($seq_name && $seq_fld) { // if we have a sequence we need to set it again
+ $seq_name = $tabname.'_'.$seq_fld.'_seq'; // has to be the name of the new implicit sequence
+ $aSql[] = "SELECT setval('$seq_name',MAX($seq_fld)) FROM $tabname";
+ }
+ $aSql[] = "DROP TABLE $tempname";
+ // recreate the indexes, if they not contain one of the droped columns
+ foreach($this->MetaIndexes($tabname) as $idx_name => $idx_data)
+ {
+ if (substr($idx_name,-5) != '_pkey' && (!$dropflds || !count(array_intersect($dropflds,$idx_data['columns'])))) {
+ $aSql = array_merge($aSql,$this->CreateIndexSQL($idx_name,$tabname,$idx_data['columns'],
+ $idx_data['unique'] ? array('UNIQUE') : False));
+ }
+ }
+ $aSql[] = 'COMMIT';
+ return $aSql;
+ }
+
+ function DropTableSQL($tabname)
+ {
+ $sql = ADODB_DataDict::DropTableSQL($tabname);
+
+ $drop_seq = $this->_DropAutoIncrement($tabname);
+ if ($drop_seq) $sql[] = $drop_seq;
+
+ return $sql;
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint)
+ {
+ if ($fautoinc) {
+ $ftype = 'SERIAL';
+ return '';
+ }
+ $suffix = '';
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ // search for a sequece for the given table (asumes the seqence-name contains the table-name!)
+ // if yes return sql to drop it
+ // this is still necessary if postgres < 7.3 or the SERIAL was created on an earlier version!!!
+ function _DropAutoIncrement($tabname)
+ {
+ $tabname = $this->connection->quote('%'.$tabname.'%');
+
+ $seq = $this->connection->GetOne("SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relname LIKE $tabname AND relkind='S'");
+
+ // check if a tables depends on the sequenz and it therefor cant and dont need to be droped separatly
+ if (!$seq || $this->connection->GetOne("SELECT relname FROM pg_class JOIN pg_depend ON pg_class.relfilenode=pg_depend.objid WHERE relname='$seq' AND relkind='S' AND deptype='i'")) {
+ return False;
+ }
+ return "DROP SEQUENCE ".$seq;
+ }
+
+ /*
+ CREATE [ [ LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name (
+ { column_name data_type [ DEFAULT default_expr ] [ column_constraint [, ... ] ]
+ | table_constraint } [, ... ]
+ )
+ [ INHERITS ( parent_table [, ... ] ) ]
+ [ WITH OIDS | WITHOUT OIDS ]
+ where column_constraint is:
+ [ CONSTRAINT constraint_name ]
+ { NOT NULL | NULL | UNIQUE | PRIMARY KEY |
+ CHECK (expression) |
+ REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL ]
+ [ ON DELETE action ] [ ON UPDATE action ] }
+ [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
+ and table_constraint is:
+ [ CONSTRAINT constraint_name ]
+ { UNIQUE ( column_name [, ... ] ) |
+ PRIMARY KEY ( column_name [, ... ] ) |
+ CHECK ( expression ) |
+ FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ]
+ [ MATCH FULL | MATCH PARTIAL ] [ ON DELETE action ] [ ON UPDATE action ] }
+ [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
+ */
+
+
+ /*
+ CREATE [ UNIQUE ] INDEX index_name ON table
+[ USING acc_method ] ( column [ ops_name ] [, ...] )
+[ WHERE predicate ]
+CREATE [ UNIQUE ] INDEX index_name ON table
+[ USING acc_method ] ( func_name( column [, ... ]) [ ops_name ] )
+[ WHERE predicate ]
+ */
+ function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+ {
+ $sql = array();
+
+ if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
+ $sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
+ if ( isset($idxoptions['DROP']) )
+ return $sql;
+ }
+
+ if ( empty ($flds) ) {
+ return $sql;
+ }
+
+ $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
+
+ $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
+
+ if (isset($idxoptions['HASH']))
+ $s .= 'USING HASH ';
+
+ if ( isset($idxoptions[$this->upperName]) )
+ $s .= $idxoptions[$this->upperName];
+
+ if ( is_array($flds) )
+ $flds = implode(', ',$flds);
+ $s .= '(' . $flds . ')';
+ $sql[] = $s;
+
+ return $sql;
+ }
+
+ function _GetSize($ftype, $ty, $fsize, $fprec)
+ {
+ if (strlen($fsize) && $ty != 'X' && $ty != 'B' && $ty != 'I' && strpos($ftype,'(') === false) {
+ $ftype .= "(".$fsize;
+ if (strlen($fprec)) $ftype .= ",".$fprec;
+ $ftype .= ')';
+ }
+ return $ftype;
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-sapdb.inc.php b/lib/adodb/datadict/datadict-sapdb.inc.php
new file mode 100644
index 0000000..37de29e
--- /dev/null
+++ b/lib/adodb/datadict/datadict-sapdb.inc.php
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ V4.50 6 July 2004 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+ Modified from datadict-generic.inc.php for sapdb by RalfBecker-AT-outdoor-training.de
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_sapdb extends ADODB_DataDict {
+
+ var $databaseType = 'sapdb';
+ var $seqField = false;
+ var $renameColumn = 'RENAME COLUMN %s.%s TO %s';
+
+ function ActualType($meta)
+ {
+ switch($meta) {
+ case 'C': return 'VARCHAR';
+ case 'XL':
+ case 'X': return 'LONG';
+
+ case 'C2': return 'VARCHAR UNICODE';
+ case 'X2': return 'LONG UNICODE';
+
+ case 'B': return 'LONG';
+
+ case 'D': return 'DATE';
+ case 'T': return 'TIMESTAMP';
+
+ case 'L': return 'BOOLEAN';
+ case 'I': return 'INTEGER';
+ case 'I1': return 'FIXED(3)';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INTEGER';
+ case 'I8': return 'FIXED(20)';
+
+ case 'F': return 'FLOAT(38)';
+ case 'N': return 'FIXED';
+ default:
+ return $meta;
+ }
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ static $maxdb_type2adodb = array(
+ 'VARCHAR' => 'C',
+ 'CHARACTER' => 'C',
+ 'LONG' => 'X', // no way to differ between 'X' and 'B' :-(
+ 'DATE' => 'D',
+ 'TIMESTAMP' => 'T',
+ 'BOOLEAN' => 'L',
+ 'INTEGER' => 'I4',
+ 'SMALLINT' => 'I2',
+ 'FLOAT' => 'F',
+ 'FIXED' => 'N',
+ );
+ $type = isset($maxdb_type2adodb[$t]) ? $maxdb_type2adodb[$t] : 'C';
+
+ // convert integer-types simulated with fixed back to integer
+ if ($t == 'FIXED' && !$fieldobj->scale && ($len == 20 || $len == 3)) {
+ $type = $len == 20 ? 'I8' : 'I1';
+ }
+ if ($fieldobj->auto_increment) $type = 'R';
+
+ return $type;
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
+ {
+ $suffix = '';
+ if ($funsigned) $suffix .= ' UNSIGNED';
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ if ($fautoinc) $suffix .= ' DEFAULT SERIAL';
+ elseif (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ function AddColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ return array( 'ALTER TABLE ' . $tabname . ' ADD (' . implode(', ',$lines) . ')' );
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ return array( 'ALTER TABLE ' . $tabname . ' MODIFY (' . implode(', ',$lines) . ')' );
+ }
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ if (!is_array($flds)) $flds = explode(',',$flds);
+ foreach($flds as $k => $v) {
+ $flds[$k] = $this->NameQuote($v);
+ }
+ return array( 'ALTER TABLE ' . $tabname . ' DROP (' . implode(', ',$flds) . ')' );
+ }
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/datadict/datadict-sybase.inc.php b/lib/adodb/datadict/datadict-sybase.inc.php
new file mode 100644
index 0000000..4d21502
--- /dev/null
+++ b/lib/adodb/datadict/datadict-sybase.inc.php
@@ -0,0 +1,228 @@
+<?php
+
+/**
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB2_sybase extends ADODB_DataDict {
+ var $databaseType = 'sybase';
+
+ var $dropIndex = 'DROP INDEX %2$s.%1$s';
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+ $len = -1; // mysql max_length is not accurate
+ switch (strtoupper($t)) {
+
+ case 'INT':
+ case 'INTEGER': return 'I';
+ case 'BIT':
+ case 'TINYINT': return 'I1';
+ case 'SMALLINT': return 'I2';
+ case 'BIGINT': return 'I8';
+
+ case 'REAL':
+ case 'FLOAT': return 'F';
+ default: return parent::MetaType($t,$len,$fieldobj);
+ }
+ }
+
+ function ActualType($meta)
+ {
+ switch(strtoupper($meta)) {
+ case 'C': return 'VARCHAR';
+ case 'XL':
+ case 'X': return 'TEXT';
+
+ case 'C2': return 'NVARCHAR';
+ case 'X2': return 'NTEXT';
+
+ case 'B': return 'IMAGE';
+
+ case 'D': return 'DATETIME';
+ case 'T': return 'DATETIME';
+ case 'L': return 'BIT';
+
+ case 'I': return 'INT';
+ case 'I1': return 'TINYINT';
+ case 'I2': return 'SMALLINT';
+ case 'I4': return 'INT';
+ case 'I8': return 'BIGINT';
+
+ case 'F': return 'REAL';
+ case 'N': return 'NUMERIC';
+ default:
+ return $meta;
+ }
+ }
+
+
+ function AddColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $f = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ $s = "ALTER TABLE $tabname $this->addCol";
+ foreach($lines as $v) {
+ $f[] = "\n $v";
+ }
+ $s .= implode(', ',$f);
+ $sql[] = $s;
+ return $sql;
+ }
+
+ function AlterColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName ($tabname);
+ $sql = array();
+ list($lines,$pkey) = $this->_GenFields($flds);
+ foreach($lines as $v) {
+ $sql[] = "ALTER TABLE $tabname $this->alterCol $v";
+ }
+
+ return $sql;
+ }
+
+ function DropColumnSQL($tabname, $flds)
+ {
+ $tabname = $this->TableName($tabname);
+ if (!is_array($flds)) $flds = explode(',',$flds);
+ $f = array();
+ $s = "ALTER TABLE $tabname";
+ foreach($flds as $v) {
+ $f[] = "\n$this->dropCol ".$this->NameQuote($v);
+ }
+ $s .= implode(', ',$f);
+ $sql[] = $s;
+ return $sql;
+ }
+
+ // return string must begin with space
+ function _CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint)
+ {
+ $suffix = '';
+ if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
+ if ($fautoinc) $suffix .= ' DEFAULT AUTOINCREMENT';
+ if ($fnotnull) $suffix .= ' NOT NULL';
+ else if ($suffix == '') $suffix .= ' NULL';
+ if ($fconstraint) $suffix .= ' '.$fconstraint;
+ return $suffix;
+ }
+
+ /*
+CREATE TABLE
+ [ database_name.[ owner ] . | owner. ] table_name
+ ( { < column_definition >
+ | column_name AS computed_column_expression
+ | < table_constraint > ::= [ CONSTRAINT constraint_name ] }
+
+ | [ { PRIMARY KEY | UNIQUE } [ ,...n ]
+ )
+
+[ ON { filegroup | DEFAULT } ]
+[ TEXTIMAGE_ON { filegroup | DEFAULT } ]
+
+< column_definition > ::= { column_name data_type }
+ [ COLLATE < collation_name > ]
+ [ [ DEFAULT constant_expression ]
+ | [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ]
+ ]
+ [ ROWGUIDCOL]
+ [ < column_constraint > ] [ ...n ]
+
+< column_constraint > ::= [ CONSTRAINT constraint_name ]
+ { [ NULL | NOT NULL ]
+ | [ { PRIMARY KEY | UNIQUE }
+ [ CLUSTERED | NONCLUSTERED ]
+ [ WITH FILLFACTOR = fillfactor ]
+ [ON {filegroup | DEFAULT} ] ]
+ ]
+ | [ [ FOREIGN KEY ]
+ REFERENCES ref_table [ ( ref_column ) ]
+ [ ON DELETE { CASCADE | NO ACTION } ]
+ [ ON UPDATE { CASCADE | NO ACTION } ]
+ [ NOT FOR REPLICATION ]
+ ]
+ | CHECK [ NOT FOR REPLICATION ]
+ ( logical_expression )
+ }
+
+< table_constraint > ::= [ CONSTRAINT constraint_name ]
+ { [ { PRIMARY KEY | UNIQUE }
+ [ CLUSTERED | NONCLUSTERED ]
+ { ( column [ ASC | DESC ] [ ,...n ] ) }
+ [ WITH FILLFACTOR = fillfactor ]
+ [ ON { filegroup | DEFAULT } ]
+ ]
+ | FOREIGN KEY
+ [ ( column [ ,...n ] ) ]
+ REFERENCES ref_table [ ( ref_column [ ,...n ] ) ]
+ [ ON DELETE { CASCADE | NO ACTION } ]
+ [ ON UPDATE { CASCADE | NO ACTION } ]
+ [ NOT FOR REPLICATION ]
+ | CHECK [ NOT FOR REPLICATION ]
+ ( search_conditions )
+ }
+
+
+ */
+
+ /*
+ CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
+ ON { table | view } ( column [ ASC | DESC ] [ ,...n ] )
+ [ WITH < index_option > [ ,...n] ]
+ [ ON filegroup ]
+ < index_option > :: =
+ { PAD_INDEX |
+ FILLFACTOR = fillfactor |
+ IGNORE_DUP_KEY |
+ DROP_EXISTING |
+ STATISTICS_NORECOMPUTE |
+ SORT_IN_TEMPDB
+ }
+*/
+ function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
+ {
+ $sql = array();
+
+ if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
+ $sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
+ if ( isset($idxoptions['DROP']) )
+ return $sql;
+ }
+
+ if ( empty ($flds) ) {
+ return $sql;
+ }
+
+ $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
+ $clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : '';
+
+ if ( is_array($flds) )
+ $flds = implode(', ',$flds);
+ $s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')';
+
+ if ( isset($idxoptions[$this->upperName]) )
+ $s .= $idxoptions[$this->upperName];
+
+ $sql[] = $s;
+
+ return $sql;
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-access.inc.php b/lib/adodb/drivers/adodb-access.inc.php
new file mode 100644
index 0000000..0b2cb2b
--- /dev/null
+++ b/lib/adodb/drivers/adodb-access.inc.php
@@ -0,0 +1,87 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Microsoft Access data driver. Requires ODBC. Works only on MS Windows.
+*/
+if (!defined('_ADODB_ODBC_LAYER')) {
+ if (!defined('ADODB_DIR')) die();
+
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+ if (!defined('_ADODB_ACCESS')) {
+ define('_ADODB_ACCESS',1);
+
+class ADODB_access extends ADODB_odbc {
+ var $databaseType = 'access';
+ var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE
+ var $fmtDate = "#Y-m-d#";
+ var $fmtTimeStamp = "#Y-m-d h:i:sA#"; // note not comma
+ var $_bindInputArray = false; // strangely enough, setting to true does not work reliably
+ var $sysDate = "FORMAT(NOW,'yyyy-mm-dd')";
+ var $sysTimeStamp = 'NOW';
+ var $hasTransactions = false;
+ var $upperCase = 'ucase';
+
+ function ADODB_access()
+ {
+ global $ADODB_EXTENSION;
+
+ $ADODB_EXTENSION = false;
+ $this->ADODB_odbc();
+ }
+
+ function Time()
+ {
+ return time();
+ }
+
+ function BeginTrans() { return false;}
+
+ function IfNull( $field, $ifNull )
+ {
+ return " IIF(IsNull($field), $ifNull, $field) "; // if Access
+ }
+/*
+ function &MetaTables()
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = odbc_tables($this->_connectionID);
+ $rs = new ADORecordSet_odbc($qid);
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) return false;
+
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+
+ $arr = &$rs->GetArray();
+ //print_pre($arr);
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if ($arr[$i][2] && $arr[$i][3] != 'SYSTEM TABLE')
+ $arr2[] = $arr[$i][2];
+ }
+ return $arr2;
+ }*/
+}
+
+
+class ADORecordSet_access extends ADORecordSet_odbc {
+
+ var $databaseType = "access";
+
+ function ADORecordSet_access($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbc($id,$mode);
+ }
+}// class
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ado.inc.php b/lib/adodb/drivers/adodb-ado.inc.php
new file mode 100644
index 0000000..4d730f2
--- /dev/null
+++ b/lib/adodb/drivers/adodb-ado.inc.php
@@ -0,0 +1,634 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Microsoft ADO data driver. Requires ADO. Works only on MS Windows.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+define("_ADODB_ADO_LAYER", 1 );
+/*--------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------*/
+
+
+class ADODB_ado extends ADOConnection {
+ var $databaseType = "ado";
+ var $_bindInputArray = false;
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $dataProvider = "ado";
+ var $hasAffectedRows = true;
+ var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary
+ var $_affectedRows = false;
+ var $_thisTransactions;
+ var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic
+ var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient;
+ var $_lock_type = -1;
+ var $_execute_option = -1;
+ var $poorAffectedRows = true;
+ var $charPage;
+
+ function ADODB_ado()
+ {
+ $this->_affectedRows = new VARIANT;
+ }
+
+ function ServerInfo()
+ {
+ if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
+ return array('description' => $desc, 'version' => '');
+ }
+
+ function _affectedrows()
+ {
+ if (PHP_VERSION >= 5) return $this->_affectedRows;
+
+ return $this->_affectedRows->value;
+ }
+
+ // you can also pass a connection string like this:
+ //
+ // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
+ function _connect($argHostname, $argUsername, $argPassword, $argProvider= 'MSDASQL')
+ {
+ $u = 'UID';
+ $p = 'PWD';
+
+ if (!empty($this->charPage))
+ $dbc = new COM('ADODB.Connection',null,$this->charPage);
+ else
+ $dbc = new COM('ADODB.Connection');
+
+ if (! $dbc) return false;
+
+ /* special support if provider is mssql or access */
+ if ($argProvider=='mssql') {
+ $u = 'User Id'; //User parameter name for OLEDB
+ $p = 'Password';
+ $argProvider = "SQLOLEDB"; // SQL Server Provider
+
+ // not yet
+ //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
+
+ //use trusted conection for SQL if username not specified
+ if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
+ } else if ($argProvider=='access')
+ $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
+
+ if ($argProvider) $dbc->Provider = $argProvider;
+
+ if ($argUsername) $argHostname .= ";$u=$argUsername";
+ if ($argPassword)$argHostname .= ";$p=$argPassword";
+
+ if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");
+ // @ added below for php 4.0.1 and earlier
+ @$dbc->Open((string) $argHostname);
+
+ $this->_connectionID = $dbc;
+
+ $dbc->CursorLocation = $this->_cursor_location;
+ return $dbc->State > 0;
+ }
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
+ {
+ return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
+ }
+
+/*
+ adSchemaCatalogs = 1,
+ adSchemaCharacterSets = 2,
+ adSchemaCollations = 3,
+ adSchemaColumns = 4,
+ adSchemaCheckConstraints = 5,
+ adSchemaConstraintColumnUsage = 6,
+ adSchemaConstraintTableUsage = 7,
+ adSchemaKeyColumnUsage = 8,
+ adSchemaReferentialContraints = 9,
+ adSchemaTableConstraints = 10,
+ adSchemaColumnsDomainUsage = 11,
+ adSchemaIndexes = 12,
+ adSchemaColumnPrivileges = 13,
+ adSchemaTablePrivileges = 14,
+ adSchemaUsagePrivileges = 15,
+ adSchemaProcedures = 16,
+ adSchemaSchemata = 17,
+ adSchemaSQLLanguages = 18,
+ adSchemaStatistics = 19,
+ adSchemaTables = 20,
+ adSchemaTranslations = 21,
+ adSchemaProviderTypes = 22,
+ adSchemaViews = 23,
+ adSchemaViewColumnUsage = 24,
+ adSchemaViewTableUsage = 25,
+ adSchemaProcedureParameters = 26,
+ adSchemaForeignKeys = 27,
+ adSchemaPrimaryKeys = 28,
+ adSchemaProcedureColumns = 29,
+ adSchemaDBInfoKeywords = 30,
+ adSchemaDBInfoLiterals = 31,
+ adSchemaCubes = 32,
+ adSchemaDimensions = 33,
+ adSchemaHierarchies = 34,
+ adSchemaLevels = 35,
+ adSchemaMeasures = 36,
+ adSchemaProperties = 37,
+ adSchemaMembers = 38
+
+*/
+
+ function &MetaTables()
+ {
+ $arr= array();
+ $dbc = $this->_connectionID;
+
+ $adors=@$dbc->OpenSchema(20);//tables
+ if ($adors){
+ $f = $adors->Fields(2);//table/view name
+ $t = $adors->Fields(3);//table type
+ while (!$adors->EOF){
+ $tt=substr($t->value,0,6);
+ if ($tt!='SYSTEM' && $tt !='ACCESS')
+ $arr[]=$f->value;
+ //print $f->value . ' ' . $t->value.'<br>';
+ $adors->MoveNext();
+ }
+ $adors->Close();
+ }
+
+ return $arr;
+ }
+
+ function &MetaColumns($table)
+ {
+ $table = strtoupper($table);
+ $arr = array();
+ $dbc = $this->_connectionID;
+
+ $adors=@$dbc->OpenSchema(4);//tables
+
+ if ($adors){
+ $t = $adors->Fields(2);//table/view name
+ while (!$adors->EOF){
+
+
+ if (strtoupper($t->Value) == $table) {
+
+ $fld = new ADOFieldObject();
+ $c = $adors->Fields(3);
+ $fld->name = $c->Value;
+ $fld->type = 'CHAR'; // cannot discover type in ADO!
+ $fld->max_length = -1;
+ $arr[strtoupper($fld->name)]=$fld;
+ }
+
+ $adors->MoveNext();
+ }
+ $adors->Close();
+ }
+ $false = false;
+ return empty($arr) ? $false : $arr;
+ }
+
+
+
+
+ /* returns queryID or false */
+ function &_query($sql,$inputarr=false)
+ {
+
+ $dbc = $this->_connectionID;
+ $false = false;
+
+ // return rs
+ if ($inputarr) {
+
+ if (!empty($this->charPage))
+ $oCmd = new COM('ADODB.Command',null,$this->charPage);
+ else
+ $oCmd = new COM('ADODB.Command');
+ $oCmd->ActiveConnection = $dbc;
+ $oCmd->CommandText = $sql;
+ $oCmd->CommandType = 1;
+
+ foreach($inputarr as $val) {
+ // name, type, direction 1 = input, len,
+ $this->adoParameterType = 130;
+ $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val);
+ //print $p->Type.' '.$p->value;
+ $oCmd->Parameters->Append($p);
+ }
+ $p = false;
+ $rs = $oCmd->Execute();
+ $e = $dbc->Errors;
+ if ($dbc->Errors->Count > 0) return $false;
+ return $rs;
+ }
+
+ $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
+
+ if ($dbc->Errors->Count > 0) return $false;
+ if (! $rs) return $false;
+
+ if ($rs->State == 0) {
+ $true = true;
+ return $true; // 0 = adStateClosed means no records returned
+ }
+ return $rs;
+ }
+
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+
+ if (isset($this->_thisTransactions))
+ if (!$this->_thisTransactions) return false;
+ else {
+ $o = $this->_connectionID->Properties("Transaction DDL");
+ $this->_thisTransactions = $o ? true : false;
+ if (!$o) return false;
+ }
+ @$this->_connectionID->BeginTrans();
+ $this->transCnt += 1;
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transOff) return true;
+
+ @$this->_connectionID->CommitTrans();
+ if ($this->transCnt) @$this->transCnt -= 1;
+ return true;
+ }
+ function RollbackTrans() {
+ if ($this->transOff) return true;
+ @$this->_connectionID->RollbackTrans();
+ if ($this->transCnt) @$this->transCnt -= 1;
+ return true;
+ }
+
+ /* Returns: the last error message from previous database operation */
+
+ function ErrorMsg()
+ {
+ if (!$this->_connectionID) return "No connection established";
+ $errc = $this->_connectionID->Errors;
+ if (!$errc) return "No Errors object found";
+ if ($errc->Count == 0) return '';
+ $err = $errc->Item($errc->Count-1);
+ return $err->Description;
+ }
+
+ function ErrorNo()
+ {
+ $errc = $this->_connectionID->Errors;
+ if ($errc->Count == 0) return 0;
+ $err = $errc->Item($errc->Count-1);
+ return $err->NativeError;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ if ($this->_connectionID) $this->_connectionID->Close();
+ $this->_connectionID = false;
+ return true;
+ }
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_ado extends ADORecordSet {
+
+ var $bind = false;
+ var $databaseType = "ado";
+ var $dataProvider = "ado";
+ var $_tarr = false; // caches the types
+ var $_flds; // and field objects
+ var $canSeek = true;
+ var $hideErrors = true;
+
+ function ADORecordSet_ado($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+ return $this->ADORecordSet($id,$mode);
+ }
+
+
+ // returns the field object
+ function &FetchField($fieldOffset = -1) {
+ $off=$fieldOffset+1; // offsets begin at 1
+
+ $o= new ADOFieldObject();
+ $rs = $this->_queryID;
+ $f = $rs->Fields($fieldOffset);
+ $o->name = $f->Name;
+ $t = $f->Type;
+ $o->type = $this->MetaType($t);
+ $o->max_length = $f->DefinedSize;
+ $o->ado_type = $t;
+
+ //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
+ return $o;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) 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)]];
+ }
+
+
+ function _initrs()
+ {
+ $rs = $this->_queryID;
+ $this->_numOfRows = $rs->RecordCount;
+
+ $f = $rs->Fields;
+ $this->_numOfFields = $f->Count;
+ }
+
+
+ // should only be used to move forward as we normally use forward-only cursors
+ function _seek($row)
+ {
+ $rs = $this->_queryID;
+ // absoluteposition doesn't work -- my maths is wrong ?
+ // $rs->AbsolutePosition->$row-2;
+ // return true;
+ if ($this->_currentRow > $row) return false;
+ @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst
+ return true;
+ }
+
+/*
+ OLEDB types
+
+ enum DBTYPEENUM
+ { DBTYPE_EMPTY = 0,
+ DBTYPE_NULL = 1,
+ DBTYPE_I2 = 2,
+ DBTYPE_I4 = 3,
+ DBTYPE_R4 = 4,
+ DBTYPE_R8 = 5,
+ DBTYPE_CY = 6,
+ DBTYPE_DATE = 7,
+ DBTYPE_BSTR = 8,
+ DBTYPE_IDISPATCH = 9,
+ DBTYPE_ERROR = 10,
+ DBTYPE_BOOL = 11,
+ DBTYPE_VARIANT = 12,
+ DBTYPE_IUNKNOWN = 13,
+ DBTYPE_DECIMAL = 14,
+ DBTYPE_UI1 = 17,
+ DBTYPE_ARRAY = 0x2000,
+ DBTYPE_BYREF = 0x4000,
+ DBTYPE_I1 = 16,
+ DBTYPE_UI2 = 18,
+ DBTYPE_UI4 = 19,
+ DBTYPE_I8 = 20,
+ DBTYPE_UI8 = 21,
+ DBTYPE_GUID = 72,
+ DBTYPE_VECTOR = 0x1000,
+ DBTYPE_RESERVED = 0x8000,
+ DBTYPE_BYTES = 128,
+ DBTYPE_STR = 129,
+ DBTYPE_WSTR = 130,
+ DBTYPE_NUMERIC = 131,
+ DBTYPE_UDT = 132,
+ DBTYPE_DBDATE = 133,
+ DBTYPE_DBTIME = 134,
+ DBTYPE_DBTIMESTAMP = 135
+
+ ADO Types
+
+ adEmpty = 0,
+ adTinyInt = 16,
+ adSmallInt = 2,
+ adInteger = 3,
+ adBigInt = 20,
+ adUnsignedTinyInt = 17,
+ adUnsignedSmallInt = 18,
+ adUnsignedInt = 19,
+ adUnsignedBigInt = 21,
+ adSingle = 4,
+ adDouble = 5,
+ adCurrency = 6,
+ adDecimal = 14,
+ adNumeric = 131,
+ adBoolean = 11,
+ adError = 10,
+ adUserDefined = 132,
+ adVariant = 12,
+ adIDispatch = 9,
+ adIUnknown = 13,
+ adGUID = 72,
+ adDate = 7,
+ adDBDate = 133,
+ adDBTime = 134,
+ adDBTimeStamp = 135,
+ adBSTR = 8,
+ adChar = 129,
+ adVarChar = 200,
+ adLongVarChar = 201,
+ adWChar = 130,
+ adVarWChar = 202,
+ adLongVarWChar = 203,
+ adBinary = 128,
+ adVarBinary = 204,
+ adLongVarBinary = 205,
+ adChapter = 136,
+ adFileTime = 64,
+ adDBFileTime = 137,
+ adPropVariant = 138,
+ adVarNumeric = 139
+*/
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+ if (!is_numeric($t)) return $t;
+
+ switch ($t) {
+ case 0:
+ case 12: // variant
+ case 8: // bstr
+ case 129: //char
+ case 130: //wc
+ case 200: // varc
+ case 202:// varWC
+ case 128: // bin
+ case 204: // varBin
+ case 72: // guid
+ if ($len <= $this->blobSize) return 'C';
+
+ case 201:
+ case 203:
+ return 'X';
+ case 128:
+ case 204:
+ case 205:
+ return 'B';
+ case 7:
+ case 133: return 'D';
+
+ case 134:
+ case 135: return 'T';
+
+ case 11: return 'L';
+
+ case 16:// adTinyInt = 16,
+ case 2://adSmallInt = 2,
+ case 3://adInteger = 3,
+ case 4://adBigInt = 20,
+ case 17://adUnsignedTinyInt = 17,
+ case 18://adUnsignedSmallInt = 18,
+ case 19://adUnsignedInt = 19,
+ case 20://adUnsignedBigInt = 21,
+ return 'I';
+ default: return 'N';
+ }
+ }
+
+ // time stamp not supported yet
+ function _fetch()
+ {
+ $rs = $this->_queryID;
+ if (!$rs or $rs->EOF) {
+ $this->fields = false;
+ return false;
+ }
+ $this->fields = array();
+
+ if (!$this->_tarr) {
+ $tarr = array();
+ $flds = array();
+ for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
+ $f = $rs->Fields($i);
+ $flds[] = $f;
+ $tarr[] = $f->Type;
+ }
+ // bind types and flds only once
+ $this->_tarr = $tarr;
+ $this->_flds = $flds;
+ }
+ $t = reset($this->_tarr);
+ $f = reset($this->_flds);
+
+ if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null
+ for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
+ //echo "<p>",$t,' ';var_dump($f->value); echo '</p>';
+ switch($t) {
+ case 135: // timestamp
+ if (!strlen((string)$f->value)) $this->fields[] = false;
+ else {
+ if (!is_numeric($f->value)) # $val = variant_date_to_timestamp($f->value);
+ // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00
+ $val=(float) variant_cast($f->value,VT_R8)*3600*24-2209161600;
+ else
+ $val = $f->value;
+ $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
+ }
+ break;
+ case 133:// A date value (yyyymmdd)
+ if ($val = $f->value) {
+ $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
+ } else
+ $this->fields[] = false;
+ break;
+ case 7: // adDate
+ if (!strlen((string)$f->value)) $this->fields[] = false;
+ else {
+ if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
+ else $val = $f->value;
+
+ if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val);
+ else $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
+ }
+ break;
+ case 1: // null
+ $this->fields[] = false;
+ break;
+ case 6: // currency is not supported properly;
+ ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>');
+ $this->fields[] = (float) $f->value;
+ break;
+ default:
+ $this->fields[] = $f->value;
+ break;
+ }
+ //print " $f->value $t, ";
+ $f = next($this->_flds);
+ $t = next($this->_tarr);
+ } // for
+ if ($this->hideErrors) error_reporting($olde);
+ @$rs->MoveNext(); // @ needed for some versions of PHP!
+
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields = &$this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+
+ function NextRecordSet()
+ {
+ $rs = $this->_queryID;
+ $this->_queryID = $rs->NextRecordSet();
+ //$this->_queryID = $this->_QueryId->NextRecordSet();
+ if ($this->_queryID == null) return false;
+
+ $this->_currentRow = -1;
+ $this->_currentPage = -1;
+ $this->bind = false;
+ $this->fields = false;
+ $this->_flds = false;
+ $this->_tarr = false;
+
+ $this->_inited = false;
+ $this->Init();
+ return true;
+ }
+
+ function _close() {
+ $this->_flds = false;
+ @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
+ $this->_queryID = false;
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ado5.inc.php b/lib/adodb/drivers/adodb-ado5.inc.php
new file mode 100644
index 0000000..a0e2e3e
--- /dev/null
+++ b/lib/adodb/drivers/adodb-ado5.inc.php
@@ -0,0 +1,668 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Microsoft ADO data driver. Requires ADO. Works only on MS Windows. PHP5 compat version.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+define("_ADODB_ADO_LAYER", 1 );
+/*--------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------*/
+
+
+class ADODB_ado extends ADOConnection {
+ var $databaseType = "ado";
+ var $_bindInputArray = false;
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $dataProvider = "ado";
+ var $hasAffectedRows = true;
+ var $adoParameterType = 201; // 201 = long varchar, 203=long wide varchar, 205 = long varbinary
+ var $_affectedRows = false;
+ var $_thisTransactions;
+ var $_cursor_type = 3; // 3=adOpenStatic,0=adOpenForwardOnly,1=adOpenKeyset,2=adOpenDynamic
+ var $_cursor_location = 3; // 2=adUseServer, 3 = adUseClient;
+ var $_lock_type = -1;
+ var $_execute_option = -1;
+ var $poorAffectedRows = true;
+ var $charPage;
+
+ function ADODB_ado()
+ {
+ $this->_affectedRows = new VARIANT;
+ }
+
+ function ServerInfo()
+ {
+ if (!empty($this->_connectionID)) $desc = $this->_connectionID->provider;
+ return array('description' => $desc, 'version' => '');
+ }
+
+ function _affectedrows()
+ {
+ if (PHP_VERSION >= 5) return $this->_affectedRows;
+
+ return $this->_affectedRows->value;
+ }
+
+ // you can also pass a connection string like this:
+ //
+ // $DB->Connect('USER ID=sa;PASSWORD=pwd;SERVER=mangrove;DATABASE=ai',false,false,'SQLOLEDB');
+ function _connect($argHostname, $argUsername, $argPassword,$argDBorProvider, $argProvider= '')
+ {
+ // two modes
+ // - if $argProvider is empty, we assume that $argDBorProvider holds provider -- this is for backward compat
+ // - if $argProvider is not empty, then $argDBorProvider holds db
+
+
+ if ($argProvider) {
+ $argDatabasename = $argDBorProvider;
+ } else {
+ $argDatabasename = '';
+ if ($argDBorProvider) $argProvider = $argDBorProvider;
+ else $argProvider = 'MSDASQL';
+ }
+
+
+ try {
+ $u = 'UID';
+ $p = 'PWD';
+
+ if (!empty($this->charPage))
+ $dbc = new COM('ADODB.Connection',null,$this->charPage);
+ else
+ $dbc = new COM('ADODB.Connection');
+
+ if (! $dbc) return false;
+
+ /* special support if provider is mssql or access */
+ if ($argProvider=='mssql') {
+ $u = 'User Id'; //User parameter name for OLEDB
+ $p = 'Password';
+ $argProvider = "SQLOLEDB"; // SQL Server Provider
+
+ // not yet
+ //if ($argDatabasename) $argHostname .= ";Initial Catalog=$argDatabasename";
+
+ //use trusted conection for SQL if username not specified
+ if (!$argUsername) $argHostname .= ";Trusted_Connection=Yes";
+ } else if ($argProvider=='access')
+ $argProvider = "Microsoft.Jet.OLEDB.4.0"; // Microsoft Jet Provider
+
+ if ($argProvider) $dbc->Provider = $argProvider;
+
+ if ($argProvider) $argHostname = "PROVIDER=$argProvider;DRIVER={SQL Server};SERVER=$argHostname";
+
+
+ if ($argDatabasename) $argHostname .= ";DATABASE=$argDatabasename";
+ if ($argUsername) $argHostname .= ";$u=$argUsername";
+ if ($argPassword)$argHostname .= ";$p=$argPassword";
+
+ if ($this->debug) ADOConnection::outp( "Host=".$argHostname."<BR>\n version=$dbc->version");
+ // @ added below for php 4.0.1 and earlier
+ @$dbc->Open((string) $argHostname);
+
+ $this->_connectionID = $dbc;
+
+ $dbc->CursorLocation = $this->_cursor_location;
+ return $dbc->State > 0;
+ } catch (exception $e) {
+ }
+
+ return false;
+ }
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argProvider='MSDASQL')
+ {
+ return $this->_connect($argHostname,$argUsername,$argPassword,$argProvider);
+ }
+
+/*
+ adSchemaCatalogs = 1,
+ adSchemaCharacterSets = 2,
+ adSchemaCollations = 3,
+ adSchemaColumns = 4,
+ adSchemaCheckConstraints = 5,
+ adSchemaConstraintColumnUsage = 6,
+ adSchemaConstraintTableUsage = 7,
+ adSchemaKeyColumnUsage = 8,
+ adSchemaReferentialContraints = 9,
+ adSchemaTableConstraints = 10,
+ adSchemaColumnsDomainUsage = 11,
+ adSchemaIndexes = 12,
+ adSchemaColumnPrivileges = 13,
+ adSchemaTablePrivileges = 14,
+ adSchemaUsagePrivileges = 15,
+ adSchemaProcedures = 16,
+ adSchemaSchemata = 17,
+ adSchemaSQLLanguages = 18,
+ adSchemaStatistics = 19,
+ adSchemaTables = 20,
+ adSchemaTranslations = 21,
+ adSchemaProviderTypes = 22,
+ adSchemaViews = 23,
+ adSchemaViewColumnUsage = 24,
+ adSchemaViewTableUsage = 25,
+ adSchemaProcedureParameters = 26,
+ adSchemaForeignKeys = 27,
+ adSchemaPrimaryKeys = 28,
+ adSchemaProcedureColumns = 29,
+ adSchemaDBInfoKeywords = 30,
+ adSchemaDBInfoLiterals = 31,
+ adSchemaCubes = 32,
+ adSchemaDimensions = 33,
+ adSchemaHierarchies = 34,
+ adSchemaLevels = 35,
+ adSchemaMeasures = 36,
+ adSchemaProperties = 37,
+ adSchemaMembers = 38
+
+*/
+
+ function &MetaTables()
+ {
+ $arr= array();
+ $dbc = $this->_connectionID;
+
+ $adors=@$dbc->OpenSchema(20);//tables
+ if ($adors){
+ $f = $adors->Fields(2);//table/view name
+ $t = $adors->Fields(3);//table type
+ while (!$adors->EOF){
+ $tt=substr($t->value,0,6);
+ if ($tt!='SYSTEM' && $tt !='ACCESS')
+ $arr[]=$f->value;
+ //print $f->value . ' ' . $t->value.'<br>';
+ $adors->MoveNext();
+ }
+ $adors->Close();
+ }
+
+ return $arr;
+ }
+
+ function &MetaColumns($table)
+ {
+ $table = strtoupper($table);
+ $arr= array();
+ $dbc = $this->_connectionID;
+
+ $adors=@$dbc->OpenSchema(4);//tables
+
+ if ($adors){
+ $t = $adors->Fields(2);//table/view name
+ while (!$adors->EOF){
+
+
+ if (strtoupper($t->Value) == $table) {
+
+ $fld = new ADOFieldObject();
+ $c = $adors->Fields(3);
+ $fld->name = $c->Value;
+ $fld->type = 'CHAR'; // cannot discover type in ADO!
+ $fld->max_length = -1;
+ $arr[strtoupper($fld->name)]=$fld;
+ }
+
+ $adors->MoveNext();
+ }
+ $adors->Close();
+ }
+
+ return $arr;
+ }
+
+ /* returns queryID or false */
+ function &_query($sql,$inputarr=false)
+ {
+ try { // In PHP5, all COM errors are exceptions, so to maintain old behaviour...
+
+ $dbc = $this->_connectionID;
+
+ // return rs
+
+ $false = false;
+
+ if ($inputarr) {
+
+ if (!empty($this->charPage))
+ $oCmd = new COM('ADODB.Command',null,$this->charPage);
+ else
+ $oCmd = new COM('ADODB.Command');
+ $oCmd->ActiveConnection = $dbc;
+ $oCmd->CommandText = $sql;
+ $oCmd->CommandType = 1;
+
+ foreach($inputarr as $val) {
+ // name, type, direction 1 = input, len,
+ $this->adoParameterType = 130;
+ $p = $oCmd->CreateParameter('name',$this->adoParameterType,1,strlen($val),$val);
+ //print $p->Type.' '.$p->value;
+ $oCmd->Parameters->Append($p);
+ }
+ $p = false;
+ $rs = $oCmd->Execute();
+ $e = $dbc->Errors;
+ if ($dbc->Errors->Count > 0) return $false;
+ return $rs;
+ }
+
+ $rs = @$dbc->Execute($sql,$this->_affectedRows, $this->_execute_option);
+
+ if ($dbc->Errors->Count > 0) return $false;
+ if (! $rs) return $false;
+
+ if ($rs->State == 0) {
+ $true = true;
+ return $true; // 0 = adStateClosed means no records returned
+ }
+ return $rs;
+
+ } catch (exception $e) {
+
+ }
+ return $false;
+ }
+
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+
+ if (isset($this->_thisTransactions))
+ if (!$this->_thisTransactions) return false;
+ else {
+ $o = $this->_connectionID->Properties("Transaction DDL");
+ $this->_thisTransactions = $o ? true : false;
+ if (!$o) return false;
+ }
+ @$this->_connectionID->BeginTrans();
+ $this->transCnt += 1;
+ return true;
+ }
+ function CommitTrans($ok=true)
+ {
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transOff) return true;
+
+ @$this->_connectionID->CommitTrans();
+ if ($this->transCnt) @$this->transCnt -= 1;
+ return true;
+ }
+ function RollbackTrans() {
+ if ($this->transOff) return true;
+ @$this->_connectionID->RollbackTrans();
+ if ($this->transCnt) @$this->transCnt -= 1;
+ return true;
+ }
+
+ /* Returns: the last error message from previous database operation */
+
+ function ErrorMsg()
+ {
+ if (!$this->_connectionID) return "No connection established";
+ $errmsg = '';
+
+ try {
+ $errc = $this->_connectionID->Errors;
+ if (!$errc) return "No Errors object found";
+ if ($errc->Count == 0) return '';
+ $err = $errc->Item($errc->Count-1);
+ $errmsg = $err->Description;
+ }catch(exception $e) {
+ }
+ return $errmsg;
+ }
+
+ function ErrorNo()
+ {
+ $errc = $this->_connectionID->Errors;
+ if ($errc->Count == 0) return 0;
+ $err = $errc->Item($errc->Count-1);
+ return $err->NativeError;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ if ($this->_connectionID) $this->_connectionID->Close();
+ $this->_connectionID = false;
+ return true;
+ }
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_ado extends ADORecordSet {
+
+ var $bind = false;
+ var $databaseType = "ado";
+ var $dataProvider = "ado";
+ var $_tarr = false; // caches the types
+ var $_flds; // and field objects
+ var $canSeek = true;
+ var $hideErrors = true;
+
+ function ADORecordSet_ado($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+ return $this->ADORecordSet($id,$mode);
+ }
+
+
+ // returns the field object
+ function &FetchField($fieldOffset = -1) {
+ $off=$fieldOffset+1; // offsets begin at 1
+
+ $o= new ADOFieldObject();
+ $rs = $this->_queryID;
+ $f = $rs->Fields($fieldOffset);
+ $o->name = $f->Name;
+ $t = $f->Type;
+ $o->type = $this->MetaType($t);
+ $o->max_length = $f->DefinedSize;
+ $o->ado_type = $t;
+
+
+ //print "off=$off name=$o->name type=$o->type len=$o->max_length<br>";
+ return $o;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) 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)]];
+ }
+
+
+ function _initrs()
+ {
+ $rs = $this->_queryID;
+ $this->_numOfRows = $rs->RecordCount;
+
+ $f = $rs->Fields;
+ $this->_numOfFields = $f->Count;
+ }
+
+
+ // should only be used to move forward as we normally use forward-only cursors
+ function _seek($row)
+ {
+ $rs = $this->_queryID;
+ // absoluteposition doesn't work -- my maths is wrong ?
+ // $rs->AbsolutePosition->$row-2;
+ // return true;
+ if ($this->_currentRow > $row) return false;
+ @$rs->Move((integer)$row - $this->_currentRow-1); //adBookmarkFirst
+ return true;
+ }
+
+/*
+ OLEDB types
+
+ enum DBTYPEENUM
+ { DBTYPE_EMPTY = 0,
+ DBTYPE_NULL = 1,
+ DBTYPE_I2 = 2,
+ DBTYPE_I4 = 3,
+ DBTYPE_R4 = 4,
+ DBTYPE_R8 = 5,
+ DBTYPE_CY = 6,
+ DBTYPE_DATE = 7,
+ DBTYPE_BSTR = 8,
+ DBTYPE_IDISPATCH = 9,
+ DBTYPE_ERROR = 10,
+ DBTYPE_BOOL = 11,
+ DBTYPE_VARIANT = 12,
+ DBTYPE_IUNKNOWN = 13,
+ DBTYPE_DECIMAL = 14,
+ DBTYPE_UI1 = 17,
+ DBTYPE_ARRAY = 0x2000,
+ DBTYPE_BYREF = 0x4000,
+ DBTYPE_I1 = 16,
+ DBTYPE_UI2 = 18,
+ DBTYPE_UI4 = 19,
+ DBTYPE_I8 = 20,
+ DBTYPE_UI8 = 21,
+ DBTYPE_GUID = 72,
+ DBTYPE_VECTOR = 0x1000,
+ DBTYPE_RESERVED = 0x8000,
+ DBTYPE_BYTES = 128,
+ DBTYPE_STR = 129,
+ DBTYPE_WSTR = 130,
+ DBTYPE_NUMERIC = 131,
+ DBTYPE_UDT = 132,
+ DBTYPE_DBDATE = 133,
+ DBTYPE_DBTIME = 134,
+ DBTYPE_DBTIMESTAMP = 135
+
+ ADO Types
+
+ adEmpty = 0,
+ adTinyInt = 16,
+ adSmallInt = 2,
+ adInteger = 3,
+ adBigInt = 20,
+ adUnsignedTinyInt = 17,
+ adUnsignedSmallInt = 18,
+ adUnsignedInt = 19,
+ adUnsignedBigInt = 21,
+ adSingle = 4,
+ adDouble = 5,
+ adCurrency = 6,
+ adDecimal = 14,
+ adNumeric = 131,
+ adBoolean = 11,
+ adError = 10,
+ adUserDefined = 132,
+ adVariant = 12,
+ adIDispatch = 9,
+ adIUnknown = 13,
+ adGUID = 72,
+ adDate = 7,
+ adDBDate = 133,
+ adDBTime = 134,
+ adDBTimeStamp = 135,
+ adBSTR = 8,
+ adChar = 129,
+ adVarChar = 200,
+ adLongVarChar = 201,
+ adWChar = 130,
+ adVarWChar = 202,
+ adLongVarWChar = 203,
+ adBinary = 128,
+ adVarBinary = 204,
+ adLongVarBinary = 205,
+ adChapter = 136,
+ adFileTime = 64,
+ adDBFileTime = 137,
+ adPropVariant = 138,
+ adVarNumeric = 139
+*/
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+ if (!is_numeric($t)) return $t;
+
+ switch ($t) {
+ case 0:
+ case 12: // variant
+ case 8: // bstr
+ case 129: //char
+ case 130: //wc
+ case 200: // varc
+ case 202:// varWC
+ case 128: // bin
+ case 204: // varBin
+ case 72: // guid
+ if ($len <= $this->blobSize) return 'C';
+
+ case 201:
+ case 203:
+ return 'X';
+ case 128:
+ case 204:
+ case 205:
+ return 'B';
+ case 7:
+ case 133: return 'D';
+
+ case 134:
+ case 135: return 'T';
+
+ case 11: return 'L';
+
+ case 16:// adTinyInt = 16,
+ case 2://adSmallInt = 2,
+ case 3://adInteger = 3,
+ case 4://adBigInt = 20,
+ case 17://adUnsignedTinyInt = 17,
+ case 18://adUnsignedSmallInt = 18,
+ case 19://adUnsignedInt = 19,
+ case 20://adUnsignedBigInt = 21,
+ return 'I';
+ default: return 'N';
+ }
+ }
+
+ // time stamp not supported yet
+ function _fetch()
+ {
+ $rs = $this->_queryID;
+ if (!$rs or $rs->EOF) {
+ $this->fields = false;
+ return false;
+ }
+ $this->fields = array();
+
+ if (!$this->_tarr) {
+ $tarr = array();
+ $flds = array();
+ for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
+ $f = $rs->Fields($i);
+ $flds[] = $f;
+ $tarr[] = $f->Type;
+ }
+ // bind types and flds only once
+ $this->_tarr = $tarr;
+ $this->_flds = $flds;
+ }
+ $t = reset($this->_tarr);
+ $f = reset($this->_flds);
+
+ if ($this->hideErrors) $olde = error_reporting(E_ERROR|E_CORE_ERROR);// sometimes $f->value be null
+ for ($i=0,$max = $this->_numOfFields; $i < $max; $i++) {
+ //echo "<p>",$t,' ';var_dump($f->value); echo '</p>';
+ switch($t) {
+ case 135: // timestamp
+ if (!strlen((string)$f->value)) $this->fields[] = false;
+ else {
+ if (!is_numeric($f->value)) # $val = variant_date_to_timestamp($f->value);
+ // VT_DATE stores dates as (float) fractional days since 1899/12/30 00:00:00
+ $val= (float) variant_cast($f->value,VT_R8)*3600*24-2209161600;
+ else
+ $val = $f->value;
+ $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
+ }
+ break;
+ case 133:// A date value (yyyymmdd)
+ if ($val = $f->value) {
+ $this->fields[] = substr($val,0,4).'-'.substr($val,4,2).'-'.substr($val,6,2);
+ } else
+ $this->fields[] = false;
+ break;
+ case 7: // adDate
+ if (!strlen((string)$f->value)) $this->fields[] = false;
+ else {
+ if (!is_numeric($f->value)) $val = variant_date_to_timestamp($f->value);
+ else $val = $f->value;
+
+ if (($val % 86400) == 0) $this->fields[] = adodb_date('Y-m-d',$val);
+ else $this->fields[] = adodb_date('Y-m-d H:i:s',$val);
+ }
+ break;
+ case 1: // null
+ $this->fields[] = false;
+ break;
+ case 6: // currency is not supported properly;
+ ADOConnection::outp( '<b>'.$f->Name.': currency type not supported by PHP</b>');
+ $this->fields[] = (float) $f->value;
+ break;
+ default:
+ $this->fields[] = $f->value;
+ break;
+ }
+ //print " $f->value $t, ";
+ $f = next($this->_flds);
+ $t = next($this->_tarr);
+ } // for
+ if ($this->hideErrors) error_reporting($olde);
+ @$rs->MoveNext(); // @ needed for some versions of PHP!
+
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields = &$this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+
+ function NextRecordSet()
+ {
+ $rs = $this->_queryID;
+ $this->_queryID = $rs->NextRecordSet();
+ //$this->_queryID = $this->_QueryId->NextRecordSet();
+ if ($this->_queryID == null) return false;
+
+ $this->_currentRow = -1;
+ $this->_currentPage = -1;
+ $this->bind = false;
+ $this->fields = false;
+ $this->_flds = false;
+ $this->_tarr = false;
+
+ $this->_inited = false;
+ $this->Init();
+ return true;
+ }
+
+ function _close() {
+ $this->_flds = false;
+ @$this->_queryID->Close();// by Pete Dishman (peterd@telephonetics.co.uk)
+ $this->_queryID = false;
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ado_access.inc.php b/lib/adodb/drivers/adodb-ado_access.inc.php
new file mode 100644
index 0000000..ab83e26
--- /dev/null
+++ b/lib/adodb/drivers/adodb-ado_access.inc.php
@@ -0,0 +1,55 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+Released under both BSD license and Lesser GPL library license.
+Whenever there is any discrepancy between the two licenses,
+the BSD license will take precedence. See License.txt.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Microsoft Access ADO data driver. Requires ADO and ODBC. Works only on MS Windows.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ADO_LAYER')) {
+ if (PHP_VERSION >= 5) include(ADODB_DIR."/drivers/adodb-ado5.inc.php");
+ else include(ADODB_DIR."/drivers/adodb-ado.inc.php");
+}
+
+class ADODB_ado_access extends ADODB_ado {
+ var $databaseType = 'ado_access';
+ var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE
+ var $fmtDate = "#Y-m-d#";
+ var $fmtTimeStamp = "#Y-m-d h:i:sA#";// note no comma
+ var $sysDate = "FORMAT(NOW,'yyyy-mm-dd')";
+ var $sysTimeStamp = 'NOW';
+ var $hasTransactions = false;
+ var $upperCase = 'ucase';
+
+ function ADODB_ado_access()
+ {
+ $this->ADODB_ado();
+ }
+
+ function BeginTrans() { return false;}
+
+ function CommitTrans() { return false;}
+
+ function RollbackTrans() { return false;}
+
+}
+
+
+class ADORecordSet_ado_access extends ADORecordSet_ado {
+
+ var $databaseType = "ado_access";
+
+ function ADORecordSet_ado_access($id,$mode=false)
+ {
+ return $this->ADORecordSet_ado($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ado_mssql.inc.php b/lib/adodb/drivers/adodb-ado_mssql.inc.php
new file mode 100644
index 0000000..576223d
--- /dev/null
+++ b/lib/adodb/drivers/adodb-ado_mssql.inc.php
@@ -0,0 +1,154 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Microsoft SQL Server ADO data driver. Requires ADO and MSSQL client.
+ Works only on MS Windows.
+
+ Warning: Some versions of PHP (esp PHP4) leak memory when ADO/COM is used.
+ Please check http://bugs.php.net/ for more info.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ADO_LAYER')) {
+ if (PHP_VERSION >= 5) include(ADODB_DIR."/drivers/adodb-ado5.inc.php");
+ else include(ADODB_DIR."/drivers/adodb-ado.inc.php");
+}
+
+
+class ADODB_ado_mssql extends ADODB_ado {
+ var $databaseType = 'ado_mssql';
+ var $hasTop = 'top';
+ var $hasInsertID = true;
+ var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
+ var $sysTimeStamp = 'GetDate()';
+ var $leftOuter = '*=';
+ var $rightOuter = '=*';
+ var $ansiOuter = true; // for mssql7 or later
+ var $substr = "substring";
+ var $length = 'len';
+ var $_dropSeqSQL = "drop table %s";
+
+ //var $_inTransaction = 1; // always open recordsets, so no transaction problems.
+
+ function ADODB_ado_mssql()
+ {
+ $this->ADODB_ado();
+ }
+
+ function _insertid()
+ {
+ return $this->GetOne('select @@identity');
+ }
+
+ function _affectedrows()
+ {
+ return $this->GetOne('select @@rowcount');
+ }
+
+ function SetTransactionMode( $transaction_mode )
+ {
+ $this->_transmode = $transaction_mode;
+ if (empty($transaction_mode)) {
+ $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+ return;
+ }
+ if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+ $this->Execute("SET TRANSACTION ".$transaction_mode);
+ }
+
+ function qstr($s,$magic_quotes=false)
+ {
+ $s = ADOConnection::qstr($s, $magic_quotes);
+ return str_replace("\0", "\\\\000", $s);
+ }
+
+ function MetaColumns($table)
+ {
+ $table = strtoupper($table);
+ $arr= array();
+ $dbc = $this->_connectionID;
+
+ $osoptions = array();
+ $osoptions[0] = null;
+ $osoptions[1] = null;
+ $osoptions[2] = $table;
+ $osoptions[3] = null;
+
+ $adors=@$dbc->OpenSchema(4, $osoptions);//tables
+
+ if ($adors){
+ while (!$adors->EOF){
+ $fld = new ADOFieldObject();
+ $c = $adors->Fields(3);
+ $fld->name = $c->Value;
+ $fld->type = 'CHAR'; // cannot discover type in ADO!
+ $fld->max_length = -1;
+ $arr[strtoupper($fld->name)]=$fld;
+
+ $adors->MoveNext();
+ }
+ $adors->Close();
+ }
+ $false = false;
+ return empty($arr) ? $false : $arr;
+ }
+
+ function CreateSequence($seq='adodbseq',$start=1)
+ {
+
+ $this->Execute('BEGIN TRANSACTION adodbseq');
+ $start -= 1;
+ $this->Execute("create table $seq (id float(53))");
+ $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
+ if (!$ok) {
+ $this->Execute('ROLLBACK TRANSACTION adodbseq');
+ return false;
+ }
+ $this->Execute('COMMIT TRANSACTION adodbseq');
+ return true;
+ }
+
+ function GenID($seq='adodbseq',$start=1)
+ {
+ //$this->debug=1;
+ $this->Execute('BEGIN TRANSACTION adodbseq');
+ $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1");
+ if (!$ok) {
+ $this->Execute("create table $seq (id float(53))");
+ $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
+ if (!$ok) {
+ $this->Execute('ROLLBACK TRANSACTION adodbseq');
+ return false;
+ }
+ $this->Execute('COMMIT TRANSACTION adodbseq');
+ return $start;
+ }
+ $num = $this->GetOne("select id from $seq");
+ $this->Execute('COMMIT TRANSACTION adodbseq');
+ return $num;
+
+ // in old implementation, pre 1.90, we returned GUID...
+ //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'");
+ }
+
+ } // end class
+
+ class ADORecordSet_ado_mssql extends ADORecordSet_ado {
+
+ var $databaseType = 'ado_mssql';
+
+ function ADORecordSet_ado_mssql($id,$mode=false)
+ {
+ return $this->ADORecordSet_ado($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-borland_ibase.inc.php b/lib/adodb/drivers/adodb-borland_ibase.inc.php
new file mode 100644
index 0000000..ab15fef
--- /dev/null
+++ b/lib/adodb/drivers/adodb-borland_ibase.inc.php
@@ -0,0 +1,92 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Support Borland Interbase 6.5 and later
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR."/drivers/adodb-ibase.inc.php");
+
+class ADODB_borland_ibase extends ADODB_ibase {
+ var $databaseType = "borland_ibase";
+
+
+ function ADODB_borland_ibase()
+ {
+ $this->ADODB_ibase();
+ }
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->autoCommit = false;
+ $this->_transactionID = ibase_trans($this->ibasetrans, $this->_connectionID);
+ return $this->_transactionID;
+ }
+
+ function ServerInfo()
+ {
+ $arr['dialect'] = $this->dialect;
+ switch($arr['dialect']) {
+ case '':
+ case '1': $s = 'Interbase 6.5, Dialect 1'; break;
+ case '2': $s = 'Interbase 6.5, Dialect 2'; break;
+ default:
+ case '3': $s = 'Interbase 6.5, Dialect 3'; break;
+ }
+ $arr['version'] = '6.5';
+ $arr['description'] = $s;
+ return $arr;
+ }
+
+ // Note that Interbase 6.5 uses ROWS instead - don't you love forking wars!
+ // SELECT col1, col2 FROM table ROWS 5 -- get 5 rows
+ // SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2
+ // Firebird uses
+ // SELECT FIRST 5 SKIP 2 col1, col2 FROM TABLE
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ {
+ if ($nrows > 0) {
+ if ($offset <= 0) $str = " ROWS $nrows ";
+ else {
+ $a = $offset+1;
+ $b = $offset+$nrows;
+ $str = " ROWS $a TO $b";
+ }
+ } else {
+ // ok, skip
+ $a = $offset + 1;
+ $str = " ROWS $a TO 999999999"; // 999 million
+ }
+ $sql .= $str;
+
+ return ($secs2cache) ?
+ $this->CacheExecute($secs2cache,$sql,$inputarr)
+ :
+ $this->Execute($sql,$inputarr);
+ }
+
+};
+
+
+class ADORecordSet_borland_ibase extends ADORecordSet_ibase {
+
+ var $databaseType = "borland_ibase";
+
+ function ADORecordSet_borland_ibase($id,$mode=false)
+ {
+ $this->ADORecordSet_ibase($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-csv.inc.php b/lib/adodb/drivers/adodb-csv.inc.php
new file mode 100644
index 0000000..a977416
--- /dev/null
+++ b/lib/adodb/drivers/adodb-csv.inc.php
@@ -0,0 +1,207 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4.
+
+ Currently unsupported: MetaDatabases, MetaTables and MetaColumns, and also inputarr in Execute.
+ Native types have been converted to MetaTypes.
+ Transactions not supported yet.
+
+ Limitation of url length. For IIS, see MaxClientRequestBuffer registry value.
+
+ http://support.microsoft.com/default.aspx?scid=kb;en-us;260694
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (! defined("_ADODB_CSV_LAYER")) {
+ define("_ADODB_CSV_LAYER", 1 );
+
+include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+
+class ADODB_csv extends ADOConnection {
+ var $databaseType = 'csv';
+ var $databaseProvider = 'csv';
+ var $hasInsertID = true;
+ var $hasAffectedRows = true;
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $_affectedrows=0;
+ var $_insertid=0;
+ var $_url;
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $hasTransactions = false;
+ var $_errorNo = false;
+
+ function ADODB_csv()
+ {
+ }
+
+ function _insertid()
+ {
+ return $this->_insertid;
+ }
+
+ function _affectedrows()
+ {
+ return $this->_affectedrows;
+ }
+
+ function &MetaDatabases()
+ {
+ return false;
+ }
+
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (strtolower(substr($argHostname,0,7)) !== 'http://') return false;
+ $this->_url = $argHostname;
+ return true;
+ }
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (strtolower(substr($argHostname,0,7)) !== 'http://') return false;
+ $this->_url = $argHostname;
+ return true;
+ }
+
+ function &MetaColumns($table)
+ {
+ return false;
+ }
+
+
+ // parameters use PostgreSQL convention, not MySQL
+ function &SelectLimit($sql,$nrows=-1,$offset=-1)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $url = $this->_url.'?sql='.urlencode($sql)."&nrows=$nrows&fetch=".
+ (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE).
+ "&offset=$offset";
+ $err = false;
+ $rs = csv2rs($url,$err,false);
+
+ if ($this->debug) print "$url<br><i>$err</i><br>";
+
+ $at = strpos($err,'::::');
+ if ($at === false) {
+ $this->_errorMsg = $err;
+ $this->_errorNo = (integer)$err;
+ } else {
+ $this->_errorMsg = substr($err,$at+4,1024);
+ $this->_errorNo = -9999;
+ }
+ if ($this->_errorNo)
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,'');
+ }
+
+ if (is_object($rs)) {
+
+ $rs->databaseType='csv';
+ $rs->fetchMode = ($this->fetchMode !== false) ? $this->fetchMode : $ADODB_FETCH_MODE;
+ $rs->connection = &$this;
+ }
+ return $rs;
+ }
+
+ // returns queryID or false
+ function &_Execute($sql,$inputarr=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ if (!$this->_bindInputArray && $inputarr) {
+ $sqlarr = explode('?',$sql);
+ $sql = '';
+ $i = 0;
+ foreach($inputarr as $v) {
+
+ $sql .= $sqlarr[$i];
+ if (gettype($v) == 'string')
+ $sql .= $this->qstr($v);
+ else if ($v === null)
+ $sql .= 'NULL';
+ else
+ $sql .= $v;
+ $i += 1;
+
+ }
+ $sql .= $sqlarr[$i];
+ if ($i+1 != sizeof($sqlarr))
+ print "Input Array does not match ?: ".htmlspecialchars($sql);
+ $inputarr = false;
+ }
+
+ $url = $this->_url.'?sql='.urlencode($sql)."&fetch=".
+ (($this->fetchMode !== false)?$this->fetchMode : $ADODB_FETCH_MODE);
+ $err = false;
+
+
+ $rs = csv2rs($url,$err,false);
+ if ($this->debug) print urldecode($url)."<br><i>$err</i><br>";
+ $at = strpos($err,'::::');
+ if ($at === false) {
+ $this->_errorMsg = $err;
+ $this->_errorNo = (integer)$err;
+ } else {
+ $this->_errorMsg = substr($err,$at+4,1024);
+ $this->_errorNo = -9999;
+ }
+
+ if ($this->_errorNo)
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'EXECUTE',$this->ErrorNo(),$this->ErrorMsg(),$sql,$inputarr);
+ }
+ if (is_object($rs)) {
+ $rs->fetchMode = ($this->fetchMode !== false) ? $this->fetchMode : $ADODB_FETCH_MODE;
+
+ $this->_affectedrows = $rs->affectedrows;
+ $this->_insertid = $rs->insertid;
+ $rs->databaseType='csv';
+ $rs->connection = &$this;
+ }
+ return $rs;
+ }
+
+ /* Returns: the last error message from previous database operation */
+ function ErrorMsg()
+ {
+ return $this->_errorMsg;
+ }
+
+ /* Returns: the last error number from previous database operation */
+ function ErrorNo()
+ {
+ return $this->_errorNo;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ return true;
+ }
+} // class
+
+class ADORecordset_csv extends ADORecordset {
+ function ADORecordset_csv($id,$mode=false)
+ {
+ $this->ADORecordset($id,$mode);
+ }
+
+ function _close()
+ {
+ return true;
+ }
+}
+
+} // define
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-db2.inc.php b/lib/adodb/drivers/adodb-db2.inc.php
new file mode 100644
index 0000000..9c1882d
--- /dev/null
+++ b/lib/adodb/drivers/adodb-db2.inc.php
@@ -0,0 +1,828 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2006 John Lim (jlim#natsoft.com.my). All rights reserved.
+
+ This is a version of the ADODB driver for DB2. It uses the 'ibm_db2' PECL extension
+ for PHP (http://pecl.php.net/package/ibm_db2), which in turn requires DB2 V8.2.2 or
+ higher.
+
+ Originally tested with PHP 5.1.1 and Apache 2.0.55 on Windows XP SP2.
+ More recently tested with PHP 5.1.2 and Apache 2.0.55 on Windows XP SP2.
+
+ This file was ported from "adodb-odbc.inc.php" by Larry Menard, "larry.menard#rogers.com".
+ I ripped out what I believed to be a lot of redundant or obsolete code, but there are
+ probably still some remnants of the ODBC support in this file; I'm relying on reviewers
+ of this code to point out any other things that can be removed.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+ define("_ADODB_DB2_LAYER", 2 );
+
+/*--------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------*/
+
+
+class ADODB_db2 extends ADOConnection {
+ var $databaseType = "db2";
+ var $fmtDate = "'Y-m-d'";
+ var $concat_operator = '||';
+
+ var $sysTime = 'CURRENT TIME';
+ var $sysDate = 'CURRENT DATE';
+ var $sysTimeStamp = 'CURRENT TIMESTAMP';
+
+ var $fmtTimeStamp = "'Y-m-d-H.i.s'";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $dataProvider = "db2";
+ var $hasAffectedRows = true;
+
+ var $binmode = DB2_BINARY;
+
+ var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive
+ // breaking backward-compat
+ var $_bindInputArray = false;
+ var $_genIDSQL = "VALUES NEXTVAL FOR %s";
+ var $_genSeqSQL = "CREATE SEQUENCE %s START WITH 1 NO MAXVALUE NO CYCLE";
+ var $_dropSeqSQL = "DROP SEQUENCE %s";
+ var $_autocommit = true;
+ var $_haserrorfunctions = true;
+ var $_lastAffectedRows = 0;
+ var $uCaseTables = true; // for meta* functions, uppercase table names
+ var $hasInsertID = true;
+
+ function _insertid()
+ {
+ return ADOConnection::GetOne('VALUES IDENTITY_VAL_LOCAL()');
+ }
+
+ function ADODB_db2()
+ {
+ $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050;
+ }
+
+ // returns true or false
+ function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ global $php_errormsg;
+
+ if (!function_exists('db2_connect')) {
+ ADOConnection::outp("Warning: The old ODBC based DB2 driver has been renamed 'odbc_db2'. This ADOdb driver calls PHP's native db2 extension.");
+ return null;
+ }
+ // This needs to be set before the connect().
+ // Replaces the odbc_binmode() call that was in Execute()
+ ini_set('ibm_db2.binmode', $this->binmode);
+
+ if ($argDatabasename) {
+ $this->_connectionID = db2_connect($argDatabasename,$argUsername,$argPassword);
+ } else {
+ $this->_connectionID = db2_connect($argDSN,$argUsername,$argPassword);
+ }
+ if (isset($php_errormsg)) $php_errormsg = '';
+
+ // For db2_connect(), there is an optional 4th arg. If present, it must be
+ // an array of valid options. So far, we don't use them.
+
+ $this->_errorMsg = @db2_conn_errormsg();
+
+ if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+
+ return $this->_connectionID != false;
+ }
+
+ // returns true or false
+ function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ global $php_errormsg;
+
+ if (!function_exists('db2_connect')) return null;
+
+ // This needs to be set before the connect().
+ // Replaces the odbc_binmode() call that was in Execute()
+ ini_set('ibm_db2.binmode', $this->binmode);
+
+ if (isset($php_errormsg)) $php_errormsg = '';
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+
+ if ($argDatabasename) {
+ $this->_connectionID = db2_pconnect($argDatabasename,$argUsername,$argPassword);
+ } else {
+ $this->_connectionID = db2_pconnect($argDSN,$argUsername,$argPassword);
+ }
+ if (isset($php_errormsg)) $php_errormsg = '';
+
+ $this->_errorMsg = @db2_conn_errormsg();
+ if ($this->_connectionID && $this->autoRollback) @db2_rollback($this->_connectionID);
+ if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+
+ return $this->_connectionID != false;
+ }
+
+ // format and return date string in database timestamp format
+ function DBTimeStamp($ts)
+ {
+ if (empty($ts) && $ts !== 0) return 'null';
+ if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
+ return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'YYYY-MM-DD HH24:MI:SS')";
+ }
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ // use right() and replace() ?
+ if (!$col) $col = $this->sysDate;
+
+ /* use TO_CHAR() if $fmt is TO_CHAR() allowed fmt */
+ if ($fmt== 'Y-m-d H:i:s')
+ return 'TO_CHAR('.$col.", 'YYYY-MM-DD HH24:MI:SS')";
+
+ $s = '';
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ if ($s) $s .= $this->concat_operator;
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ if ($len==1) return "year($col)";
+ $s .= "char(year($col))";
+ break;
+ case 'M':
+ if ($len==1) return "monthname($col)";
+ $s .= "substr(monthname($col),1,3)";
+ break;
+ case 'm':
+ if ($len==1) return "month($col)";
+ $s .= "right(digits(month($col)),2)";
+ break;
+ case 'D':
+ case 'd':
+ if ($len==1) return "day($col)";
+ $s .= "right(digits(day($col)),2)";
+ break;
+ case 'H':
+ case 'h':
+ if ($len==1) return "hour($col)";
+ if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)";
+ else $s .= "''";
+ break;
+ case 'i':
+ case 'I':
+ if ($len==1) return "minute($col)";
+ if ($col != $this->sysDate)
+ $s .= "right(digits(minute($col)),2)";
+ else $s .= "''";
+ break;
+ case 'S':
+ case 's':
+ if ($len==1) return "second($col)";
+ if ($col != $this->sysDate)
+ $s .= "right(digits(second($col)),2)";
+ else $s .= "''";
+ break;
+ default:
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ $s .= $this->qstr($ch);
+ }
+ }
+ return $s;
+ }
+
+
+ function ServerInfo()
+ {
+
+ if (!empty($this->host) && ADODB_PHPVER >= 0x4300) {
+ $dsn = strtoupper($this->host);
+ $first = true;
+ $found = false;
+
+ if (!function_exists('db2_data_source')) return false;
+
+ while(true) {
+
+ $rez = @db2_data_source($this->_connectionID,
+ $first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT);
+ $first = false;
+ if (!is_array($rez)) break;
+ if (strtoupper($rez['server']) == $dsn) {
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) return ADOConnection::ServerInfo();
+ if (!isset($rez['version'])) $rez['version'] = '';
+ return $rez;
+ } else {
+ return ADOConnection::ServerInfo();
+ }
+ }
+
+
+ function CreateSequence($seqname='adodbseq',$start=1)
+ {
+ if (empty($this->_genSeqSQL)) return false;
+ $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+ if (!$ok) return false;
+ return true;
+ }
+
+ function DropSequence($seqname)
+ {
+ if (empty($this->_dropSeqSQL)) return false;
+ return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+ }
+
+ /*
+ This algorithm is not very efficient, but works even if table locking
+ is not available.
+
+ Will return false if unable to generate an ID after $MAXLOOPS attempts.
+ */
+ function GenID($seq='adodbseq',$start=1)
+ {
+ // if you have to modify the parameter below, your database is overloaded,
+ // or you need to implement generation of id's yourself!
+ $num = $this->GetOne("VALUES NEXTVAL FOR $seq");
+ return $num;
+ }
+
+
+ function ErrorMsg()
+ {
+ if ($this->_haserrorfunctions) {
+ if ($this->_errorMsg !== false) return $this->_errorMsg;
+ if (empty($this->_connectionID)) return @db2_conn_errormsg();
+ return @db2_conn_errormsg($this->_connectionID);
+ } else return ADOConnection::ErrorMsg();
+ }
+
+ function ErrorNo()
+ {
+
+ if ($this->_haserrorfunctions) {
+ if ($this->_errorCode !== false) {
+ // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
+ return (strlen($this->_errorCode)<=2) ? 0 : $this->_errorCode;
+ }
+
+ if (empty($this->_connectionID)) $e = @db2_conn_error();
+ else $e = @db2_conn_error($this->_connectionID);
+
+ // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
+ // so we check and patch
+ if (strlen($e)<=2) return 0;
+ return $e;
+ } else return ADOConnection::ErrorNo();
+ }
+
+
+
+ function BeginTrans()
+ {
+ if (!$this->hasTransactions) return false;
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->_autocommit = false;
+ return db2_autocommit($this->_connectionID,false);
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+ $ret = db2_commit($this->_connectionID);
+ db2_autocommit($this->_connectionID,true);
+ return $ret;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+ $ret = db2_rollback($this->_connectionID);
+ db2_autocommit($this->_connectionID,true);
+ return $ret;
+ }
+
+ function MetaPrimaryKeys($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ if ($this->uCaseTables) $table = strtoupper($table);
+ $schema = '';
+ $this->_findschema($table,$schema);
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = @db2_primarykeys($this->_connectionID,'',$schema,$table);
+
+ if (!$qid) {
+ $ADODB_FETCH_MODE = $savem;
+ return false;
+ }
+ $rs = new ADORecordSet_db2($qid);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$rs) return false;
+
+ $arr =& $rs->GetArray();
+ $rs->Close();
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if ($arr[$i][3]) $arr2[] = $arr[$i][3];
+ }
+ return $arr2;
+ }
+
+ function MetaForeignKeys($table, $owner = FALSE, $upper = FALSE, $asociative = FALSE )
+ {
+ global $ADODB_FETCH_MODE;
+
+ if ($this->uCaseTables) $table = strtoupper($table);
+ $schema = '';
+ $this->_findschema($table,$schema);
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = @db2_foreign_keys($this->_connectionID,'',$schema,$table);
+ if (!$qid) {
+ $ADODB_FETCH_MODE = $savem;
+ return false;
+ }
+ $rs = new ADORecordSet_db2($qid);
+
+ $ADODB_FETCH_MODE = $savem;
+ /*
+ $rs->fields indices
+ 0 PKTABLE_CAT
+ 1 PKTABLE_SCHEM
+ 2 PKTABLE_NAME
+ 3 PKCOLUMN_NAME
+ 4 FKTABLE_CAT
+ 5 FKTABLE_SCHEM
+ 6 FKTABLE_NAME
+ 7 FKCOLUMN_NAME
+ */
+ if (!$rs) return false;
+
+ $foreign_keys = array();
+ while (!$rs->EOF) {
+ if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
+ if (!is_array($foreign_keys[$rs->fields[5].'.'.$rs->fields[6]]))
+ $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]] = array();
+ $foreign_keys[$rs->fields[5].'.'.$rs->fields[6]][$rs->fields[7]] = $rs->fields[3];
+ }
+ $rs->MoveNext();
+ }
+
+ $rs->Close();
+ return $foreign_key;
+ }
+
+
+ function &MetaTables($ttype=false,$schema=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = db2_tables($this->_connectionID);
+
+ $rs = new ADORecordSet_db2($qid);
+
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) {
+ $false = false;
+ return $false;
+ }
+
+ $arr =& $rs->GetArray();
+
+ $rs->Close();
+ $arr2 = array();
+
+ if ($ttype) {
+ $isview = strncmp($ttype,'V',1) === 0;
+ }
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if (!$arr[$i][2]) continue;
+ $type = $arr[$i][3];
+ $schemaval = ($schema) ? $arr[$i][1].'.' : '';
+ if ($ttype) {
+ if ($isview) {
+ if (strncmp($type,'V',1) === 0) $arr2[] = $schemaval.$arr[$i][2];
+ } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2];
+ } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $schemaval.$arr[$i][2];
+ }
+ return $arr2;
+ }
+
+/*
+See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/db2/htm/db2datetime_data_type_changes.asp
+/ SQL data type codes /
+#define SQL_UNKNOWN_TYPE 0
+#define SQL_CHAR 1
+#define SQL_NUMERIC 2
+#define SQL_DECIMAL 3
+#define SQL_INTEGER 4
+#define SQL_SMALLINT 5
+#define SQL_FLOAT 6
+#define SQL_REAL 7
+#define SQL_DOUBLE 8
+#if (DB2VER >= 0x0300)
+#define SQL_DATETIME 9
+#endif
+#define SQL_VARCHAR 12
+
+
+/ One-parameter shortcuts for date/time data types /
+#if (DB2VER >= 0x0300)
+#define SQL_TYPE_DATE 91
+#define SQL_TYPE_TIME 92
+#define SQL_TYPE_TIMESTAMP 93
+
+#define SQL_UNICODE (-95)
+#define SQL_UNICODE_VARCHAR (-96)
+#define SQL_UNICODE_LONGVARCHAR (-97)
+*/
+ function DB2Types($t)
+ {
+ switch ((integer)$t) {
+ case 1:
+ case 12:
+ case 0:
+ case -95:
+ case -96:
+ return 'C';
+ case -97:
+ case -1: //text
+ return 'X';
+ case -4: //image
+ return 'B';
+
+ case 9:
+ case 91:
+ return 'D';
+
+ case 10:
+ case 11:
+ case 92:
+ case 93:
+ return 'T';
+
+ case 4:
+ case 5:
+ case -6:
+ return 'I';
+
+ case -11: // uniqidentifier
+ return 'R';
+ case -7: //bit
+ return 'L';
+
+ default:
+ return 'N';
+ }
+ }
+
+ function &MetaColumns($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $false = false;
+ if ($this->uCaseTables) $table = strtoupper($table);
+ $schema = '';
+ $this->_findschema($table,$schema);
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ $colname = "%";
+ $qid = db2_columns($this->_connectionID, "", $schema, $table, $colname);
+ if (empty($qid)) return $false;
+
+ $rs =& new ADORecordSet_db2($qid);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$rs) return $false;
+ $rs->_fetch();
+
+ $retarr = array();
+
+ /*
+ $rs->fields indices
+ 0 TABLE_QUALIFIER
+ 1 TABLE_SCHEM
+ 2 TABLE_NAME
+ 3 COLUMN_NAME
+ 4 DATA_TYPE
+ 5 TYPE_NAME
+ 6 PRECISION
+ 7 LENGTH
+ 8 SCALE
+ 9 RADIX
+ 10 NULLABLE
+ 11 REMARKS
+ */
+ while (!$rs->EOF) {
+ if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[3];
+ $fld->type = $this->DB2Types($rs->fields[4]);
+
+ // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp
+ // access uses precision to store length for char/varchar
+ if ($fld->type == 'C' or $fld->type == 'X') {
+ if ($rs->fields[4] <= -95) // UNICODE
+ $fld->max_length = $rs->fields[7]/2;
+ else
+ $fld->max_length = $rs->fields[7];
+ } else
+ $fld->max_length = $rs->fields[7];
+ $fld->not_null = !empty($rs->fields[10]);
+ $fld->scale = $rs->fields[8];
+ $fld->primary_key = false;
+ $retarr[strtoupper($fld->name)] = $fld;
+ } else if (sizeof($retarr)>0)
+ break;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ if (empty($retarr)) $retarr = false;
+
+ $qid = db2_primary_keys($this->_connectionID, "", $schema, $table);
+ if (empty($qid)) return $false;
+
+ $rs =& new ADORecordSet_db2($qid);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$rs) return $retarr;
+ $rs->_fetch();
+
+ /*
+ $rs->fields indices
+ 0 TABLE_CAT
+ 1 TABLE_SCHEM
+ 2 TABLE_NAME
+ 3 COLUMN_NAME
+ 4 KEY_SEQ
+ 5 PK_NAME
+ */
+ while (!$rs->EOF) {
+ if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
+ $retarr[strtoupper($rs->fields[3])]->primary_key = true;
+ } else if (sizeof($retarr)>0)
+ break;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ if (empty($retarr)) $retarr = false;
+ return $retarr;
+ }
+
+ function Prepare($sql)
+ {
+ if (! $this->_bindInputArray) return $sql; // no binding
+ $stmt = db2_prepare($this->_connectionID,$sql);
+ if (!$stmt) {
+ // we don't know whether db2 driver is parsing prepared stmts, so just return sql
+ return $sql;
+ }
+ return array($sql,$stmt,false);
+ }
+
+ /* returns queryID or false */
+ function _query($sql,$inputarr=false)
+ {
+ GLOBAL $php_errormsg;
+ if (isset($php_errormsg)) $php_errormsg = '';
+ $this->_error = '';
+
+ if ($inputarr) {
+ if (is_array($sql)) {
+ $stmtid = $sql[1];
+ } else {
+ $stmtid = db2_prepare($this->_connectionID,$sql);
+
+ if ($stmtid == false) {
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ return false;
+ }
+ }
+
+ if (! db2_execute($stmtid,$inputarr)) {
+ if ($this->_haserrorfunctions) {
+ $this->_errorMsg = db2_stmt_errormsg();
+ $this->_errorCode = db2_stmt_error();
+ }
+ return false;
+ }
+
+ } else if (is_array($sql)) {
+ $stmtid = $sql[1];
+ if (!db2_execute($stmtid)) {
+ if ($this->_haserrorfunctions) {
+ $this->_errorMsg = db2_stmt_errormsg();
+ $this->_errorCode = db2_stmt_error();
+ }
+ return false;
+ }
+ } else
+ $stmtid = @db2_exec($this->_connectionID,$sql);
+
+ $this->_lastAffectedRows = 0;
+ if ($stmtid) {
+ if (@db2_num_fields($stmtid) == 0) {
+ $this->_lastAffectedRows = db2_num_rows($stmtid);
+ $stmtid = true;
+ } else {
+ $this->_lastAffectedRows = 0;
+ }
+
+ if ($this->_haserrorfunctions) {
+ $this->_errorMsg = '';
+ $this->_errorCode = 0;
+ } else
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ } else {
+ if ($this->_haserrorfunctions) {
+ $this->_errorMsg = db2_stmt_errormsg();
+ $this->_errorCode = db2_stmt_error();
+ } else
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+
+ }
+ return $stmtid;
+ }
+
+ /*
+ Insert a null into the blob field of the table first.
+ Then use UpdateBlob to store the blob.
+
+ Usage:
+
+ $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+ */
+ function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+ return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ $ret = @db2_close($this->_connectionID);
+ $this->_connectionID = false;
+ return $ret;
+ }
+
+ function _affectedrows()
+ {
+ return $this->_lastAffectedRows;
+ }
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_db2 extends ADORecordSet {
+
+ var $bind = false;
+ var $databaseType = "db2";
+ var $dataProvider = "db2";
+ var $useFetchArray;
+
+ function ADORecordSet_db2($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+
+ $this->_queryID = $id;
+ }
+
+
+ // returns the field object
+ function &FetchField($offset = -1)
+ {
+ $o= new ADOFieldObject();
+ $o->name = @db2_field_name($this->_queryID,$offset);
+ $o->type = @db2_field_type($this->_queryID,$offset);
+ $o->max_length = db2_field_width($this->_queryID,$offset);
+ if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
+ else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
+ return $o;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) 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)]];
+ }
+
+
+ function _initrs()
+ {
+ global $ADODB_COUNTRECS;
+ $this->_numOfRows = ($ADODB_COUNTRECS) ? @db2_num_rows($this->_queryID) : -1;
+ $this->_numOfFields = @db2_num_fields($this->_queryID);
+ // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0
+ if ($this->_numOfRows == 0) $this->_numOfRows = -1;
+ }
+
+ function _seek($row)
+ {
+ return false;
+ }
+
+ // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated
+ function &GetArrayLimit($nrows,$offset=-1)
+ {
+ if ($offset <= 0) {
+ $rs =& $this->GetArray($nrows);
+ return $rs;
+ }
+ $savem = $this->fetchMode;
+ $this->fetchMode = ADODB_FETCH_NUM;
+ $this->Move($offset);
+ $this->fetchMode = $savem;
+
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+
+ $results = array();
+ $cnt = 0;
+ while (!$this->EOF && $nrows != $cnt) {
+ $results[$cnt++] = $this->fields;
+ $this->MoveNext();
+ }
+
+ return $results;
+ }
+
+
+ function MoveNext()
+ {
+ if ($this->_numOfRows != 0 && !$this->EOF) {
+ $this->_currentRow++;
+
+ $this->fields = @db2_fetch_array($this->_queryID);
+ if ($this->fields) {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+ }
+ $this->fields = false;
+ $this->EOF = true;
+ return false;
+ }
+
+ function _fetch()
+ {
+
+ $this->fields = db2_fetch_array($this->_queryID);
+ if ($this->fields) {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+ $this->fields = false;
+ return false;
+ }
+
+ function _close()
+ {
+ return @db2_free_result($this->_queryID);
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-fbsql.inc.php b/lib/adodb/drivers/adodb-fbsql.inc.php
new file mode 100644
index 0000000..6a19bc2
--- /dev/null
+++ b/lib/adodb/drivers/adodb-fbsql.inc.php
@@ -0,0 +1,266 @@
+<?php
+/*
+ @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Contribution by Frank M. Kromann <frank@frontbase.com>.
+ Set tabs to 8.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (! defined("_ADODB_FBSQL_LAYER")) {
+ define("_ADODB_FBSQL_LAYER", 1 );
+
+class ADODB_fbsql extends ADOConnection {
+ var $databaseType = 'fbsql';
+ var $hasInsertID = true;
+ var $hasAffectedRows = true;
+ var $metaTablesSQL = "SHOW TABLES";
+ var $metaColumnsSQL = "SHOW COLUMNS FROM %s";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $hasLimit = false;
+
+ function ADODB_fbsql()
+ {
+ }
+
+ function _insertid()
+ {
+ return fbsql_insert_id($this->_connectionID);
+ }
+
+ function _affectedrows()
+ {
+ return fbsql_affected_rows($this->_connectionID);
+ }
+
+ function &MetaDatabases()
+ {
+ $qid = fbsql_list_dbs($this->_connectionID);
+ $arr = array();
+ $i = 0;
+ $max = fbsql_num_rows($qid);
+ while ($i < $max) {
+ $arr[] = fbsql_tablename($qid,$i);
+ $i += 1;
+ }
+ return $arr;
+ }
+
+ // returns concatenated string
+ function Concat()
+ {
+ $s = "";
+ $arr = func_get_args();
+ $first = true;
+
+ $s = implode(',',$arr);
+ if (sizeof($arr) > 0) return "CONCAT($s)";
+ else return '';
+ }
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ $this->_connectionID = fbsql_connect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ $this->_connectionID = fbsql_pconnect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ function &MetaColumns($table)
+ {
+ if ($this->metaColumnsSQL) {
+
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+
+ if ($rs === false) return false;
+
+ $retarr = array();
+ while (!$rs->EOF){
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+
+ // split type into type(length):
+ if (preg_match("/^(.+)\((\d+)\)$/", $fld->type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = $query_array[2];
+ } else {
+ $fld->max_length = -1;
+ }
+ $fld->not_null = ($rs->fields[2] != 'YES');
+ $fld->primary_key = ($rs->fields[3] == 'PRI');
+ $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
+ $fld->binary = (strpos($fld->type,'blob') !== false);
+
+ $retarr[strtoupper($fld->name)] = $fld;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ return $retarr;
+ }
+ return false;
+ }
+
+ // returns true or false
+ function SelectDB($dbName)
+ {
+ $this->database = $dbName;
+ if ($this->_connectionID) {
+ return @fbsql_select_db($dbName,$this->_connectionID);
+ }
+ else return false;
+ }
+
+
+ // returns queryID or false
+ function _query($sql,$inputarr)
+ {
+ return fbsql_query("$sql;",$this->_connectionID);
+ }
+
+ /* Returns: the last error message from previous database operation */
+ function ErrorMsg()
+ {
+ $this->_errorMsg = @fbsql_error($this->_connectionID);
+ return $this->_errorMsg;
+ }
+
+ /* Returns: the last error number from previous database operation */
+ function ErrorNo()
+ {
+ return @fbsql_errno($this->_connectionID);
+ }
+
+ // returns true or false
+ function _close()
+ {
+ return @fbsql_close($this->_connectionID);
+ }
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_fbsql extends ADORecordSet{
+
+ var $databaseType = "fbsql";
+ var $canSeek = true;
+
+ function ADORecordSet_fbsql($queryID,$mode=false)
+ {
+ if (!$mode) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode) {
+ case ADODB_FETCH_NUM: $this->fetchMode = FBSQL_NUM; break;
+ case ADODB_FETCH_ASSOC: $this->fetchMode = FBSQL_ASSOC; break;
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = FBSQL_BOTH; break;
+ }
+ return $this->ADORecordSet($queryID);
+ }
+
+ function _initrs()
+ {
+ GLOBAL $ADODB_COUNTRECS;
+ $this->_numOfRows = ($ADODB_COUNTRECS) ? @fbsql_num_rows($this->_queryID):-1;
+ $this->_numOfFields = @fbsql_num_fields($this->_queryID);
+ }
+
+
+
+ function &FetchField($fieldOffset = -1) {
+ if ($fieldOffset != -1) {
+ $o = @fbsql_fetch_field($this->_queryID, $fieldOffset);
+ //$o->max_length = -1; // fbsql returns the max length less spaces -- so it is unrealiable
+ $f = @fbsql_field_flags($this->_queryID,$fieldOffset);
+ $o->binary = (strpos($f,'binary')!== false);
+ }
+ else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */
+ $o = @fbsql_fetch_field($this->_queryID);// fbsql returns the max length less spaces -- so it is unrealiable
+ //$o->max_length = -1;
+ }
+
+ return $o;
+ }
+
+ function _seek($row)
+ {
+ return @fbsql_data_seek($this->_queryID,$row);
+ }
+
+ function _fetch($ignore_fields=false)
+ {
+ $this->fields = @fbsql_fetch_array($this->_queryID,$this->fetchMode);
+ return ($this->fields == true);
+ }
+
+ function _close() {
+ return @fbsql_free_result($this->_queryID);
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ $len = -1; // fbsql max_length is not accurate
+ switch (strtoupper($t)) {
+ case 'CHARACTER':
+ case 'CHARACTER VARYING':
+ case 'BLOB':
+ case 'CLOB':
+ case 'BIT':
+ case 'BIT VARYING':
+ if ($len <= $this->blobSize) return 'C';
+
+ // so we have to check whether binary...
+ case 'IMAGE':
+ case 'LONGBLOB':
+ case 'BLOB':
+ case 'MEDIUMBLOB':
+ return !empty($fieldobj->binary) ? 'B' : 'X';
+
+ case 'DATE': return 'D';
+
+ case 'TIME':
+ case 'TIME WITH TIME ZONE':
+ case 'TIMESTAMP':
+ case 'TIMESTAMP WITH TIME ZONE': return 'T';
+
+ case 'PRIMARY_KEY':
+ return 'R';
+ case 'INTEGER':
+ case 'SMALLINT':
+ case 'BOOLEAN':
+
+ if (!empty($fieldobj->primary_key)) return 'R';
+ else return 'I';
+
+ default: return 'N';
+ }
+ }
+
+} //class
+} // defined
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-firebird.inc.php b/lib/adodb/drivers/adodb-firebird.inc.php
new file mode 100644
index 0000000..9b7b59e
--- /dev/null
+++ b/lib/adodb/drivers/adodb-firebird.inc.php
@@ -0,0 +1,77 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR."/drivers/adodb-ibase.inc.php");
+
+class ADODB_firebird extends ADODB_ibase {
+ var $databaseType = "firebird";
+ var $dialect = 3;
+
+ var $sysTimeStamp = "CURRENT_TIMESTAMP"; //"cast('NOW' as timestamp)";
+
+ function ADODB_firebird()
+ {
+ $this->ADODB_ibase();
+ }
+
+ function ServerInfo()
+ {
+ $arr['dialect'] = $this->dialect;
+ switch($arr['dialect']) {
+ case '':
+ case '1': $s = 'Firebird Dialect 1'; break;
+ case '2': $s = 'Firebird Dialect 2'; break;
+ default:
+ case '3': $s = 'Firebird Dialect 3'; break;
+ }
+ $arr['version'] = ADOConnection::_findvers($s);
+ $arr['description'] = $s;
+ return $arr;
+ }
+
+ // Note that Interbase 6.5 uses this ROWS instead - don't you love forking wars!
+ // SELECT col1, col2 FROM table ROWS 5 -- get 5 rows
+ // SELECT col1, col2 FROM TABLE ORDER BY col1 ROWS 3 TO 7 -- first 5 skip 2
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false, $secs=0)
+ {
+ $nrows = (integer) $nrows;
+ $offset = (integer) $offset;
+ $str = 'SELECT ';
+ if ($nrows >= 0) $str .= "FIRST $nrows ";
+ $str .=($offset>=0) ? "SKIP $offset " : '';
+
+ $sql = preg_replace('/^[ \t]*select/i',$str,$sql);
+ if ($secs)
+ $rs =& $this->CacheExecute($secs,$sql,$inputarr);
+ else
+ $rs =& $this->Execute($sql,$inputarr);
+
+ return $rs;
+ }
+
+
+};
+
+
+class ADORecordSet_firebird extends ADORecordSet_ibase {
+
+ var $databaseType = "firebird";
+
+ function ADORecordSet_firebird($id,$mode=false)
+ {
+ $this->ADORecordSet_ibase($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ibase.inc.php b/lib/adodb/drivers/adodb-ibase.inc.php
new file mode 100644
index 0000000..335493d
--- /dev/null
+++ b/lib/adodb/drivers/adodb-ibase.inc.php
@@ -0,0 +1,887 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Interbase data driver. Requires interbase client. Works on Windows and Unix.
+
+ 3 Jan 2002 -- suggestions by Hans-Peter Oeri <kampfcaspar75@oeri.ch>
+ changed transaction handling and added experimental blob stuff
+
+ Docs to interbase at the website
+ http://www.synectics.co.za/php3/tutorial/IB_PHP3_API.html
+
+ To use gen_id(), see
+ http://www.volny.cz/iprenosil/interbase/ip_ib_code.htm#_code_creategen
+
+ $rs = $conn->Execute('select gen_id(adodb,1) from rdb$database');
+ $id = $rs->fields[0];
+ $conn->Execute("insert into table (id, col1,...) values ($id, $val1,...)");
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB_ibase extends ADOConnection {
+ var $databaseType = "ibase";
+ var $dataProvider = "ibase";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $ibase_datefmt = '%Y-%m-%d'; // For hours,mins,secs change to '%Y-%m-%d %H:%M:%S';
+ var $fmtDate = "'Y-m-d'";
+ var $ibase_timestampfmt = "%Y-%m-%d %H:%M:%S";
+ var $ibase_timefmt = "%H:%M:%S";
+ var $fmtTimeStamp = "'Y-m-d, H:i:s'";
+ var $concat_operator='||';
+ var $_transactionID;
+ var $metaTablesSQL = "select rdb\$relation_name from rdb\$relations where rdb\$relation_name not like 'RDB\$%'";
+ //OPN STUFF start
+ var $metaColumnsSQL = "select a.rdb\$field_name, a.rdb\$null_flag, a.rdb\$default_source, b.rdb\$field_length, b.rdb\$field_scale, b.rdb\$field_sub_type, b.rdb\$field_precision, b.rdb\$field_type from rdb\$relation_fields a, rdb\$fields b where a.rdb\$field_source = b.rdb\$field_name and a.rdb\$relation_name = '%s' order by a.rdb\$field_position asc";
+ //OPN STUFF end
+ var $ibasetrans;
+ var $hasGenID = true;
+ var $_bindInputArray = true;
+ var $buffers = 0;
+ var $dialect = 1;
+ var $sysDate = "cast('TODAY' as timestamp)";
+ var $sysTimeStamp = "CURRENT_TIMESTAMP"; //"cast('NOW' as timestamp)";
+ var $ansiOuter = true;
+ var $hasAffectedRows = false;
+ var $poorAffectedRows = true;
+ var $blobEncodeType = 'C';
+ var $role = false;
+
+ function ADODB_ibase()
+ {
+ if (defined('IBASE_DEFAULT')) $this->ibasetrans = IBASE_DEFAULT;
+ }
+
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$persist=false)
+ {
+ if (!function_exists('ibase_pconnect')) return null;
+ if ($argDatabasename) $argHostname .= ':'.$argDatabasename;
+ $fn = ($persist) ? 'ibase_pconnect':'ibase_connect';
+ if ($this->role)
+ $this->_connectionID = $fn($argHostname,$argUsername,$argPassword,
+ $this->charSet,$this->buffers,$this->dialect,$this->role);
+ else
+ $this->_connectionID = $fn($argHostname,$argUsername,$argPassword,
+ $this->charSet,$this->buffers,$this->dialect);
+
+ if ($this->dialect != 1) { // http://www.ibphoenix.com/ibp_60_del_id_ds.html
+ $this->replaceQuote = "''";
+ }
+ if ($this->_connectionID === false) {
+ $this->_handleerror();
+ return false;
+ }
+
+ // PHP5 change.
+ if (function_exists('ibase_timefmt')) {
+ ibase_timefmt($this->ibase_datefmt,IBASE_DATE );
+ if ($this->dialect == 1) ibase_timefmt($this->ibase_datefmt,IBASE_TIMESTAMP );
+ else ibase_timefmt($this->ibase_timestampfmt,IBASE_TIMESTAMP );
+ ibase_timefmt($this->ibase_timefmt,IBASE_TIME );
+
+ } else {
+ ini_set("ibase.timestampformat", $this->ibase_timestampfmt);
+ ini_set("ibase.dateformat", $this->ibase_datefmt);
+ ini_set("ibase.timeformat", $this->ibase_timefmt);
+ }
+ return true;
+ }
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,true);
+ }
+
+
+ function MetaPrimaryKeys($table,$owner_notused=false,$internalKey=false)
+ {
+ if ($internalKey) return array('RDB$DB_KEY');
+
+ $table = strtoupper($table);
+
+ $sql = 'SELECT S.RDB$FIELD_NAME AFIELDNAME
+ FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON I.RDB$INDEX_NAME=S.RDB$INDEX_NAME
+ WHERE I.RDB$RELATION_NAME=\''.$table.'\' and I.RDB$INDEX_NAME like \'RDB$PRIMARY%\'
+ ORDER BY I.RDB$INDEX_NAME,S.RDB$FIELD_POSITION';
+
+ $a = $this->GetCol($sql,false,true);
+ if ($a && sizeof($a)>0) return $a;
+ return false;
+ }
+
+ function ServerInfo()
+ {
+ $arr['dialect'] = $this->dialect;
+ switch($arr['dialect']) {
+ case '':
+ case '1': $s = 'Interbase 5.5 or earlier'; break;
+ case '2': $s = 'Interbase 5.6'; break;
+ default:
+ case '3': $s = 'Interbase 6.0'; break;
+ }
+ $arr['version'] = ADOConnection::_findvers($s);
+ $arr['description'] = $s;
+ return $arr;
+ }
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->autoCommit = false;
+ $this->_transactionID = $this->_connectionID;//ibase_trans($this->ibasetrans, $this->_connectionID);
+ return $this->_transactionID;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $ret = false;
+ $this->autoCommit = true;
+ if ($this->_transactionID) {
+ //print ' commit ';
+ $ret = ibase_commit($this->_transactionID);
+ }
+ $this->_transactionID = false;
+ return $ret;
+ }
+
+ // there are some compat problems with ADODB_COUNTRECS=false and $this->_logsql currently.
+ // it appears that ibase extension cannot support multiple concurrent queryid's
+ function &_Execute($sql,$inputarr=false)
+ {
+ global $ADODB_COUNTRECS;
+
+ if ($this->_logsql) {
+ $savecrecs = $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = true; // force countrecs
+ $ret =& ADOConnection::_Execute($sql,$inputarr);
+ $ADODB_COUNTRECS = $savecrecs;
+ } else {
+ $ret =& ADOConnection::_Execute($sql,$inputarr);
+ }
+ return $ret;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $ret = false;
+ $this->autoCommit = true;
+ if ($this->_transactionID)
+ $ret = ibase_rollback($this->_transactionID);
+ $this->_transactionID = false;
+
+ return $ret;
+ }
+
+ function &MetaIndexes ($table, $primary = FALSE, $owner=false)
+ {
+ // save old fetch mode
+ global $ADODB_FETCH_MODE;
+ $false = false;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+ $table = strtoupper($table);
+ $sql = "SELECT * FROM RDB\$INDICES WHERE RDB\$RELATION_NAME = '".$table."'";
+ if (!$primary) {
+ $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$%'";
+ } else {
+ $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$FOREIGN%'";
+ }
+ // get index details
+ $rs = $this->Execute($sql);
+ if (!is_object($rs)) {
+ // restore fetchmode
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+ return $false;
+ }
+
+ $indexes = array();
+ while ($row = $rs->FetchRow()) {
+ $index = $row[0];
+ if (!isset($indexes[$index])) {
+ if (is_null($row[3])) {$row[3] = 0;}
+ $indexes[$index] = array(
+ 'unique' => ($row[3] == 1),
+ 'columns' => array()
+ );
+ }
+ $sql = "SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '".$index."' ORDER BY RDB\$FIELD_POSITION ASC";
+ $rs1 = $this->Execute($sql);
+ while ($row1 = $rs1->FetchRow()) {
+ $indexes[$index]['columns'][$row1[2]] = $row1[1];
+ }
+ }
+ // restore fetchmode
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ return $indexes;
+ }
+
+
+ // See http://community.borland.com/article/0,1410,25844,00.html
+ function RowLock($tables,$where,$col)
+ {
+ if ($this->autoCommit) $this->BeginTrans();
+ $this->Execute("UPDATE $table SET $col=$col WHERE $where "); // is this correct - jlim?
+ return 1;
+ }
+
+
+ function CreateSequence($seqname,$startID=1)
+ {
+ $ok = $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" ));
+ if (!$ok) return false;
+ return $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');
+ }
+
+ function DropSequence($seqname)
+ {
+ $seqname = strtoupper($seqname);
+ $this->Execute("delete from RDB\$GENERATORS where RDB\$GENERATOR_NAME='$seqname'");
+ }
+
+ function GenID($seqname='adodbseq',$startID=1)
+ {
+ $getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE");
+ $rs = @$this->Execute($getnext);
+ if (!$rs) {
+ $this->Execute(("INSERT INTO RDB\$GENERATORS (RDB\$GENERATOR_NAME) VALUES (UPPER('$seqname'))" ));
+ $this->Execute("SET GENERATOR $seqname TO ".($startID-1).';');
+ $rs = $this->Execute($getnext);
+ }
+ if ($rs && !$rs->EOF) $this->genID = (integer) reset($rs->fields);
+ else $this->genID = 0; // false
+
+ if ($rs) $rs->Close();
+
+ return $this->genID;
+ }
+
+ function SelectDB($dbName)
+ {
+ return false;
+ }
+
+ function _handleerror()
+ {
+ $this->_errorMsg = ibase_errmsg();
+ }
+
+ function ErrorNo()
+ {
+ if (preg_match('/error code = ([\-0-9]*)/i', $this->_errorMsg,$arr)) return (integer) $arr[1];
+ else return 0;
+ }
+
+ function ErrorMsg()
+ {
+ return $this->_errorMsg;
+ }
+
+ function Prepare($sql)
+ {
+ $stmt = ibase_prepare($this->_connectionID,$sql);
+ if (!$stmt) return false;
+ return array($sql,$stmt);
+ }
+
+ // returns query ID if successful, otherwise false
+ // there have been reports of problems with nested queries - the code is probably not re-entrant?
+ function _query($sql,$iarr=false)
+ {
+
+ if (!$this->autoCommit && $this->_transactionID) {
+ $conn = $this->_transactionID;
+ $docommit = false;
+ } else {
+ $conn = $this->_connectionID;
+ $docommit = true;
+ }
+ if (is_array($sql)) {
+ $fn = 'ibase_execute';
+ $sql = $sql[1];
+ if (is_array($iarr)) {
+ if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4
+ if ( !isset($iarr[0]) ) $iarr[0] = ''; // PHP5 compat hack
+ $fnarr =& array_merge( array($sql) , $iarr);
+ $ret = call_user_func_array($fn,$fnarr);
+ } else {
+ switch(sizeof($iarr)) {
+ case 1: $ret = $fn($sql,$iarr[0]); break;
+ case 2: $ret = $fn($sql,$iarr[0],$iarr[1]); break;
+ case 3: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2]); break;
+ case 4: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break;
+ case 5: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break;
+ case 6: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break;
+ case 7: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break;
+ default: ADOConnection::outp( "Too many parameters to ibase query $sql");
+ case 8: $ret = $fn($sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break;
+ }
+ }
+ } else $ret = $fn($sql);
+ } else {
+ $fn = 'ibase_query';
+
+ if (is_array($iarr)) {
+ if (ADODB_PHPVER >= 0x4050) { // actually 4.0.4
+ if (sizeof($iarr) == 0) $iarr[0] = ''; // PHP5 compat hack
+ $fnarr =& array_merge( array($conn,$sql) , $iarr);
+ $ret = call_user_func_array($fn,$fnarr);
+ } else {
+ switch(sizeof($iarr)) {
+ case 1: $ret = $fn($conn,$sql,$iarr[0]); break;
+ case 2: $ret = $fn($conn,$sql,$iarr[0],$iarr[1]); break;
+ case 3: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2]); break;
+ case 4: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3]); break;
+ case 5: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4]); break;
+ case 6: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5]); break;
+ case 7: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6]); break;
+ default: ADOConnection::outp( "Too many parameters to ibase query $sql");
+ case 8: $ret = $fn($conn,$sql,$iarr[0],$iarr[1],$iarr[2],$iarr[3],$iarr[4],$iarr[5],$iarr[6],$iarr[7]); break;
+ }
+ }
+ } else $ret = $fn($conn,$sql);
+ }
+ if ($docommit && $ret === true) ibase_commit($this->_connectionID);
+
+ $this->_handleerror();
+ return $ret;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ if (!$this->autoCommit) @ibase_rollback($this->_connectionID);
+ return @ibase_close($this->_connectionID);
+ }
+
+ //OPN STUFF start
+ function _ConvertFieldType(&$fld, $ftype, $flen, $fscale, $fsubtype, $fprecision, $dialect3)
+ {
+ $fscale = abs($fscale);
+ $fld->max_length = $flen;
+ $fld->scale = null;
+ switch($ftype){
+ case 7:
+ case 8:
+ if ($dialect3) {
+ switch($fsubtype){
+ case 0:
+ $fld->type = ($ftype == 7 ? 'smallint' : 'integer');
+ break;
+ case 1:
+ $fld->type = 'numeric';
+ $fld->max_length = $fprecision;
+ $fld->scale = $fscale;
+ break;
+ case 2:
+ $fld->type = 'decimal';
+ $fld->max_length = $fprecision;
+ $fld->scale = $fscale;
+ break;
+ } // switch
+ } else {
+ if ($fscale !=0) {
+ $fld->type = 'decimal';
+ $fld->scale = $fscale;
+ $fld->max_length = ($ftype == 7 ? 4 : 9);
+ } else {
+ $fld->type = ($ftype == 7 ? 'smallint' : 'integer');
+ }
+ }
+ break;
+ case 16:
+ if ($dialect3) {
+ switch($fsubtype){
+ case 0:
+ $fld->type = 'decimal';
+ $fld->max_length = 18;
+ $fld->scale = 0;
+ break;
+ case 1:
+ $fld->type = 'numeric';
+ $fld->max_length = $fprecision;
+ $fld->scale = $fscale;
+ break;
+ case 2:
+ $fld->type = 'decimal';
+ $fld->max_length = $fprecision;
+ $fld->scale = $fscale;
+ break;
+ } // switch
+ }
+ break;
+ case 10:
+ $fld->type = 'float';
+ break;
+ case 14:
+ $fld->type = 'char';
+ break;
+ case 27:
+ if ($fscale !=0) {
+ $fld->type = 'decimal';
+ $fld->max_length = 15;
+ $fld->scale = 5;
+ } else {
+ $fld->type = 'double';
+ }
+ break;
+ case 35:
+ if ($dialect3) {
+ $fld->type = 'timestamp';
+ } else {
+ $fld->type = 'date';
+ }
+ break;
+ case 12:
+ $fld->type = 'date';
+ break;
+ case 13:
+ $fld->type = 'time';
+ break;
+ case 37:
+ $fld->type = 'varchar';
+ break;
+ case 40:
+ $fld->type = 'cstring';
+ break;
+ case 261:
+ $fld->type = 'blob';
+ $fld->max_length = -1;
+ break;
+ } // switch
+ }
+ //OPN STUFF end
+ // returns array of ADOFieldObjects for current table
+ function &MetaColumns($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
+
+ $ADODB_FETCH_MODE = $save;
+ $false = false;
+ if ($rs === false) {
+ return $false;
+ }
+
+ $retarr = array();
+ //OPN STUFF start
+ $dialect3 = ($this->dialect==3 ? true : false);
+ //OPN STUFF end
+ while (!$rs->EOF) { //print_r($rs->fields);
+ $fld = new ADOFieldObject();
+ $fld->name = trim($rs->fields[0]);
+ //OPN STUFF start
+ $this->_ConvertFieldType($fld, $rs->fields[7], $rs->fields[3], $rs->fields[4], $rs->fields[5], $rs->fields[6], $dialect3);
+ if (isset($rs->fields[1]) && $rs->fields[1]) {
+ $fld->not_null = true;
+ }
+ if (isset($rs->fields[2])) {
+
+ $fld->has_default = true;
+ $d = substr($rs->fields[2],strlen('default '));
+ switch ($fld->type)
+ {
+ case 'smallint':
+ case 'integer': $fld->default_value = (int) $d; break;
+ case 'char':
+ case 'blob':
+ case 'text':
+ case 'varchar': $fld->default_value = (string) substr($d,1,strlen($d)-2); break;
+ case 'double':
+ case 'float': $fld->default_value = (float) $d; break;
+ default: $fld->default_value = $d; break;
+ }
+ // case 35:$tt = 'TIMESTAMP'; break;
+ }
+ if ((isset($rs->fields[5])) && ($fld->type == 'blob')) {
+ $fld->sub_type = $rs->fields[5];
+ } else {
+ $fld->sub_type = null;
+ }
+ //OPN STUFF end
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
+ else $retarr[strtoupper($fld->name)] = $fld;
+
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ if ( empty($retarr)) return $false;
+ else return $retarr;
+ }
+
+ function BlobEncode( $blob )
+ {
+ $blobid = ibase_blob_create( $this->_connectionID);
+ ibase_blob_add( $blobid, $blob );
+ return ibase_blob_close( $blobid );
+ }
+
+ // since we auto-decode all blob's since 2.42,
+ // BlobDecode should not do any transforms
+ function BlobDecode($blob)
+ {
+ return $blob;
+ }
+
+
+
+
+ // old blobdecode function
+ // still used to auto-decode all blob's
+ function _BlobDecode_old( $blob )
+ {
+ $blobid = ibase_blob_open($this->_connectionID, $blob );
+ $realblob = ibase_blob_get( $blobid,$this->maxblobsize); // 2nd param is max size of blob -- Kevin Boillet <kevinboillet@yahoo.fr>
+ while($string = ibase_blob_get($blobid, 8192)){
+ $realblob .= $string;
+ }
+ ibase_blob_close( $blobid );
+
+ return( $realblob );
+ }
+
+ function _BlobDecode( $blob )
+ {
+ if (ADODB_PHPVER >= 0x5000) {
+ $blob_data = ibase_blob_info($this->_connectionID, $blob );
+ $blobid = ibase_blob_open($this->_connectionID, $blob );
+ } else {
+
+ $blob_data = ibase_blob_info( $blob );
+ $blobid = ibase_blob_open( $blob );
+ }
+
+ if( $blob_data[0] > $this->maxblobsize ) {
+
+ $realblob = ibase_blob_get($blobid, $this->maxblobsize);
+
+ while($string = ibase_blob_get($blobid, 8192)){
+ $realblob .= $string;
+ }
+ } else {
+ $realblob = ibase_blob_get($blobid, $blob_data[0]);
+ }
+
+ ibase_blob_close( $blobid );
+ return( $realblob );
+ }
+
+ function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+ {
+ $fd = fopen($path,'rb');
+ if ($fd === false) return false;
+ $blob_id = ibase_blob_create($this->_connectionID);
+
+ /* fill with data */
+
+ while ($val = fread($fd,32768)){
+ ibase_blob_add($blob_id, $val);
+ }
+
+ /* close and get $blob_id_str for inserting into table */
+ $blob_id_str = ibase_blob_close($blob_id);
+
+ fclose($fd);
+ return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
+ }
+
+ /*
+ Insert a null into the blob field of the table first.
+ Then use UpdateBlob to store the blob.
+
+ Usage:
+
+ $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+ */
+ function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+ $blob_id = ibase_blob_create($this->_connectionID);
+
+ // ibase_blob_add($blob_id, $val);
+
+ // replacement that solves the problem by which only the first modulus 64K /
+ // of $val are stored at the blob field ////////////////////////////////////
+ // Thx Abel Berenstein aberenstein#afip.gov.ar
+ $len = strlen($val);
+ $chunk_size = 32768;
+ $tail_size = $len % $chunk_size;
+ $n_chunks = ($len - $tail_size) / $chunk_size;
+
+ for ($n = 0; $n < $n_chunks; $n++) {
+ $start = $n * $chunk_size;
+ $data = substr($val, $start, $chunk_size);
+ ibase_blob_add($blob_id, $data);
+ }
+
+ if ($tail_size) {
+ $start = $n_chunks * $chunk_size;
+ $data = substr($val, $start, $tail_size);
+ ibase_blob_add($blob_id, $data);
+ }
+ // end replacement /////////////////////////////////////////////////////////
+
+ $blob_id_str = ibase_blob_close($blob_id);
+
+ return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
+
+ }
+
+
+ function OldUpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+ $blob_id = ibase_blob_create($this->_connectionID);
+ ibase_blob_add($blob_id, $val);
+ $blob_id_str = ibase_blob_close($blob_id);
+ return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blob_id_str)) != false;
+ }
+
+ // Format date column in sql string given an input format that understands Y M D
+ // Only since Interbase 6.0 - uses EXTRACT
+ // problem - does not zero-fill the day and month yet
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysDate;
+ $s = '';
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ if ($s) $s .= '||';
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= "extract(year from $col)";
+ break;
+ case 'M':
+ case 'm':
+ $s .= "extract(month from $col)";
+ break;
+ case 'Q':
+ case 'q':
+ $s .= "cast(((extract(month from $col)+2) / 3) as integer)";
+ break;
+ case 'D':
+ case 'd':
+ $s .= "(extract(day from $col))";
+ break;
+ case 'H':
+ case 'h':
+ $s .= "(extract(hour from $col))";
+ break;
+ case 'I':
+ case 'i':
+ $s .= "(extract(minute from $col))";
+ break;
+ case 'S':
+ case 's':
+ $s .= "CAST((extract(second from $col)) AS INTEGER)";
+ break;
+
+ default:
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ $s .= $this->qstr($ch);
+ break;
+ }
+ }
+ return $s;
+ }
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_ibase extends ADORecordSet
+{
+
+ var $databaseType = "ibase";
+ var $bind=false;
+ var $_cacheType;
+
+ function ADORecordset_ibase($id,$mode=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $this->fetchMode = ($mode === false) ? $ADODB_FETCH_MODE : $mode;
+ $this->ADORecordSet($id);
+ }
+
+ /* Returns: an object containing field information.
+ Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+ fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+ fetchField() is retrieved. */
+
+ function &FetchField($fieldOffset = -1)
+ {
+ $fld = new ADOFieldObject;
+ $ibf = ibase_field_info($this->_queryID,$fieldOffset);
+ switch (ADODB_ASSOC_CASE) {
+ case 2: // the default
+ $fld->name = ($ibf['alias']);
+ if (empty($fld->name)) $fld->name = ($ibf['name']);
+ break;
+ case 0:
+ $fld->name = strtoupper($ibf['alias']);
+ if (empty($fld->name)) $fld->name = strtoupper($ibf['name']);
+ break;
+ case 1:
+ $fld->name = strtolower($ibf['alias']);
+ if (empty($fld->name)) $fld->name = strtolower($ibf['name']);
+ break;
+ }
+
+ $fld->type = $ibf['type'];
+ $fld->max_length = $ibf['length'];
+
+ /* This needs to be populated from the metadata */
+ $fld->not_null = false;
+ $fld->has_default = false;
+ $fld->default_value = 'null';
+ return $fld;
+ }
+
+ function _initrs()
+ {
+ $this->_numOfRows = -1;
+ $this->_numOfFields = @ibase_num_fields($this->_queryID);
+
+ // cache types for blob decode check
+ for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {
+ $f1 = $this->FetchField($i);
+ $this->_cacheType[] = $f1->type;
+ }
+ }
+
+ function _seek($row)
+ {
+ return false;
+ }
+
+ function _fetch()
+ {
+ $f = @ibase_fetch_row($this->_queryID);
+ if ($f === false) {
+ $this->fields = false;
+ return false;
+ }
+ // OPN stuff start - optimized
+ // fix missing nulls and decode blobs automatically
+
+ global $ADODB_ANSI_PADDING_OFF;
+ //$ADODB_ANSI_PADDING_OFF=1;
+ $rtrim = !empty($ADODB_ANSI_PADDING_OFF);
+
+ for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {
+ if ($this->_cacheType[$i]=="BLOB") {
+ if (isset($f[$i])) {
+ $f[$i] = $this->connection->_BlobDecode($f[$i]);
+ } else {
+ $f[$i] = null;
+ }
+ } else {
+ if (!isset($f[$i])) {
+ $f[$i] = null;
+ } else if ($rtrim && is_string($f[$i])) {
+ $f[$i] = rtrim($f[$i]);
+ }
+ }
+ }
+ // OPN stuff end
+
+ $this->fields = $f;
+ if ($this->fetchMode == ADODB_FETCH_ASSOC) {
+ $this->fields = &$this->GetRowAssoc(ADODB_ASSOC_CASE);
+ } else if ($this->fetchMode == ADODB_FETCH_BOTH) {
+ $this->fields =& array_merge($this->fields,$this->GetRowAssoc(ADODB_ASSOC_CASE));
+ }
+ return true;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) 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)]];
+
+ }
+
+
+ function _close()
+ {
+ return @ibase_free_result($this->_queryID);
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ switch (strtoupper($t)) {
+ case 'CHAR':
+ return 'C';
+
+ case 'TEXT':
+ case 'VARCHAR':
+ case 'VARYING':
+ if ($len <= $this->blobSize) return 'C';
+ return 'X';
+ case 'BLOB':
+ return 'B';
+
+ case 'TIMESTAMP':
+ case 'DATE': return 'D';
+ case 'TIME': return 'T';
+ //case 'T': return 'T';
+
+ //case 'L': return 'L';
+ case 'INT':
+ case 'SHORT':
+ case 'INTEGER': return 'I';
+ default: return 'N';
+ }
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-informix.inc.php b/lib/adodb/drivers/adodb-informix.inc.php
new file mode 100644
index 0000000..eed00b0
--- /dev/null
+++ b/lib/adodb/drivers/adodb-informix.inc.php
@@ -0,0 +1,40 @@
+<?php
+/**
+* @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+* Released under both BSD license and Lesser GPL library license.
+* Whenever there is any discrepancy between the two licenses,
+* the BSD license will take precedence.
+*
+* Set tabs to 4 for best viewing.
+*
+* Latest version is available at http://php.weblogs.com
+*
+* Informix 9 driver that supports SELECT FIRST
+*
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR.'/drivers/adodb-informix72.inc.php');
+
+class ADODB_informix extends ADODB_informix72 {
+ var $databaseType = "informix";
+ var $hasTop = 'FIRST';
+ var $ansiOuter = true;
+
+ function IfNull( $field, $ifNull )
+ {
+ return " NVL($field, $ifNull) "; // if Informix 9.X or 10.X
+ }
+}
+
+class ADORecordset_informix extends ADORecordset_informix72 {
+ var $databaseType = "informix";
+
+ function ADORecordset_informix($id,$mode=false)
+ {
+ $this->ADORecordset_informix72($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-informix72.inc.php b/lib/adodb/drivers/adodb-informix72.inc.php
new file mode 100644
index 0000000..3bf65ef
--- /dev/null
+++ b/lib/adodb/drivers/adodb-informix72.inc.php
@@ -0,0 +1,475 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Informix port by Mitchell T. Young (mitch@youngfamily.org)
+
+ Further mods by "Samuel CARRIERE" <samuel_carriere@hotmail.com>
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('IFX_SCROLL')) define('IFX_SCROLL',1);
+
+class ADODB_informix72 extends ADOConnection {
+ var $databaseType = "informix72";
+ var $dataProvider = "informix";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $hasInsertID = true;
+ var $hasAffectedRows = true;
+ var $substr = 'substr';
+ var $metaTablesSQL="select tabname,tabtype from systables where tabtype in ('T','V') and owner!='informix'"; //Don't get informix tables and pseudo-tables
+
+
+ var $metaColumnsSQL =
+ "select c.colname, c.coltype, c.collength, d.default,c.colno
+ from syscolumns c, systables t,outer sysdefaults d
+ where c.tabid=t.tabid and d.tabid=t.tabid and d.colno=c.colno
+ and tabname='%s' order by c.colno";
+
+ var $metaPrimaryKeySQL =
+ "select part1,part2,part3,part4,part5,part6,part7,part8 from
+ systables t,sysconstraints s,sysindexes i where t.tabname='%s'
+ and s.tabid=t.tabid and s.constrtype='P'
+ and i.idxname=s.idxname";
+
+ var $concat_operator = '||';
+
+ var $lastQuery = false;
+ var $has_insertid = true;
+
+ var $_autocommit = true;
+ var $_bindInputArray = true; // set to true if ADOConnection.Execute() permits binding of array parameters.
+ var $sysDate = 'TODAY';
+ var $sysTimeStamp = 'CURRENT';
+ var $cursorType = IFX_SCROLL; // IFX_SCROLL or IFX_HOLD or 0
+
+ function ADODB_informix72()
+ {
+ // alternatively, use older method:
+ //putenv("DBDATE=Y4MD-");
+
+ // force ISO date format
+ putenv('GL_DATE=%Y-%m-%d');
+
+ if (function_exists('ifx_byteasvarchar')) {
+ ifx_byteasvarchar(1); // Mode "0" will return a blob id, and mode "1" will return a varchar with text content.
+ ifx_textasvarchar(1); // Mode "0" will return a blob id, and mode "1" will return a varchar with text content.
+ ifx_blobinfile_mode(0); // Mode "0" means save Byte-Blobs in memory, and mode "1" means save Byte-Blobs in a file.
+ }
+ }
+
+ function ServerInfo()
+ {
+ if (isset($this->version)) return $this->version;
+
+ $arr['description'] = $this->GetOne("select DBINFO('version','full') from systables where tabid = 1");
+ $arr['version'] = $this->GetOne("select DBINFO('version','major') || DBINFO('version','minor') from systables where tabid = 1");
+ $this->version = $arr;
+ return $arr;
+ }
+
+
+
+ function _insertid()
+ {
+ $sqlca =ifx_getsqlca($this->lastQuery);
+ return @$sqlca["sqlerrd1"];
+ }
+
+ function _affectedrows()
+ {
+ if ($this->lastQuery) {
+ return @ifx_affected_rows ($this->lastQuery);
+ }
+ return 0;
+ }
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->Execute('BEGIN');
+ $this->_autocommit = false;
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->Execute('COMMIT');
+ $this->_autocommit = true;
+ return true;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->Execute('ROLLBACK');
+ $this->_autocommit = true;
+ return true;
+ }
+
+ function RowLock($tables,$where,$flds='1 as ignore')
+ {
+ if ($this->_autocommit) $this->BeginTrans();
+ return $this->GetOne("select $flds from $tables where $where for update");
+ }
+
+ /* Returns: the last error message from previous database operation
+ Note: This function is NOT available for Microsoft SQL Server. */
+
+ function ErrorMsg()
+ {
+ if (!empty($this->_logsql)) return $this->_errorMsg;
+ $this->_errorMsg = ifx_errormsg();
+ return $this->_errorMsg;
+ }
+
+ function ErrorNo()
+ {
+ preg_match("/.*SQLCODE=([^\]]*)/",ifx_error(),$parse);
+ if (is_array($parse) && isset($parse[1])) return (int)$parse[1];
+ return 0;
+ }
+
+
+ function &MetaColumns($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $false = false;
+ if (!empty($this->metaColumnsSQL)) {
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ if ($rs === false) return $false;
+ $rspkey = $this->Execute(sprintf($this->metaPrimaryKeySQL,$table)); //Added to get primary key colno items
+
+ $retarr = array();
+ while (!$rs->EOF) { //print_r($rs->fields);
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+/* //!eos.
+ $rs->fields[1] is not the correct adodb type
+ $rs->fields[2] is not correct max_length, because can include not-null bit
+
+ $fld->type = $rs->fields[1];
+ $fld->primary_key=$rspkey->fields && array_search($rs->fields[4],$rspkey->fields); //Added to set primary key flag
+ $fld->max_length = $rs->fields[2];*/
+ $pr=ifx_props($rs->fields[1],$rs->fields[2]); //!eos
+ $fld->type = $pr[0] ;//!eos
+ $fld->primary_key=$rspkey->fields && array_search($rs->fields[4],$rspkey->fields);
+ $fld->max_length = $pr[1]; //!eos
+ $fld->precision = $pr[2] ;//!eos
+ $fld->not_null = $pr[3]=="N"; //!eos
+
+ if (trim($rs->fields[3]) != "AAAAAA 0") {
+ $fld->has_default = 1;
+ $fld->default_value = $rs->fields[3];
+ } else {
+ $fld->has_default = 0;
+ }
+
+ $retarr[strtolower($fld->name)] = $fld;
+ $rs->MoveNext();
+ }
+
+ $rs->Close();
+ $rspkey->Close(); //!eos
+ return $retarr;
+ }
+
+ return $false;
+ }
+
+ function &xMetaColumns($table)
+ {
+ return ADOConnection::MetaColumns($table,false);
+ }
+
+ function MetaForeignKeys($table, $owner=false, $upper=false) //!Eos
+ {
+ $sql = "
+ select tr.tabname,updrule,delrule,
+ i.part1 o1,i2.part1 d1,i.part2 o2,i2.part2 d2,i.part3 o3,i2.part3 d3,i.part4 o4,i2.part4 d4,
+ i.part5 o5,i2.part5 d5,i.part6 o6,i2.part6 d6,i.part7 o7,i2.part7 d7,i.part8 o8,i2.part8 d8
+ from systables t,sysconstraints s,sysindexes i,
+ sysreferences r,systables tr,sysconstraints s2,sysindexes i2
+ where t.tabname='$table'
+ and s.tabid=t.tabid and s.constrtype='R' and r.constrid=s.constrid
+ and i.idxname=s.idxname and tr.tabid=r.ptabid
+ and s2.constrid=r.primary and i2.idxname=s2.idxname";
+
+ $rs = $this->Execute($sql);
+ if (!$rs || $rs->EOF) return false;
+ $arr =& $rs->GetArray();
+ $a = array();
+ foreach($arr as $v) {
+ $coldest=$this->metaColumnNames($v["tabname"]);
+ $colorig=$this->metaColumnNames($table);
+ $colnames=array();
+ for($i=1;$i<=8 && $v["o$i"] ;$i++) {
+ $colnames[]=$coldest[$v["d$i"]-1]."=".$colorig[$v["o$i"]-1];
+ }
+ if($upper)
+ $a[strtoupper($v["tabname"])] = $colnames;
+ else
+ $a[$v["tabname"]] = $colnames;
+ }
+ return $a;
+ }
+
+ function UpdateBlob($table, $column, $val, $where, $blobtype = 'BLOB')
+ {
+ $type = ($blobtype == 'TEXT') ? 1 : 0;
+ $blobid = ifx_create_blob($type,0,$val);
+ return $this->Execute("UPDATE $table SET $column=(?) WHERE $where",array($blobid));
+ }
+
+ function BlobDecode($blobid)
+ {
+ return function_exists('ifx_byteasvarchar') ? $blobid : @ifx_get_blob($blobid);
+ }
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!function_exists('ifx_connect')) return null;
+
+ $dbs = $argDatabasename . "@" . $argHostname;
+ if ($argHostname) putenv("INFORMIXSERVER=$argHostname");
+ putenv("INFORMIXSERVER=".trim($argHostname));
+ $this->_connectionID = ifx_connect($dbs,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ #if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!function_exists('ifx_connect')) return null;
+
+ $dbs = $argDatabasename . "@" . $argHostname;
+ putenv("INFORMIXSERVER=".trim($argHostname));
+ $this->_connectionID = ifx_pconnect($dbs,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ #if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+/*
+ // ifx_do does not accept bind parameters - weird ???
+ function Prepare($sql)
+ {
+ $stmt = ifx_prepare($sql);
+ if (!$stmt) return $sql;
+ else return array($sql,$stmt);
+ }
+*/
+ // returns query ID if successful, otherwise false
+ function _query($sql,$inputarr)
+ {
+ global $ADODB_COUNTRECS;
+
+ // String parameters have to be converted using ifx_create_char
+ if ($inputarr) {
+ foreach($inputarr as $v) {
+ if (gettype($v) == 'string') {
+ $tab[] = ifx_create_char($v);
+ }
+ else {
+ $tab[] = $v;
+ }
+ }
+ }
+
+ // In case of select statement, we use a scroll cursor in order
+ // to be able to call "move", or "movefirst" statements
+ if (!$ADODB_COUNTRECS && preg_match("/^\s*select/is", $sql)) {
+ if ($inputarr) {
+ $this->lastQuery = ifx_query($sql,$this->_connectionID, $this->cursorType, $tab);
+ }
+ else {
+ $this->lastQuery = ifx_query($sql,$this->_connectionID, $this->cursorType);
+ }
+ }
+ else {
+ if ($inputarr) {
+ $this->lastQuery = ifx_query($sql,$this->_connectionID, $tab);
+ }
+ else {
+ $this->lastQuery = ifx_query($sql,$this->_connectionID);
+ }
+ }
+
+ // Following line have been commented because autocommit mode is
+ // not supported by informix SE 7.2
+
+ //if ($this->_autocommit) ifx_query('COMMIT',$this->_connectionID);
+
+ return $this->lastQuery;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ $this->lastQuery = false;
+ return ifx_close($this->_connectionID);
+ }
+}
+
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_informix72 extends ADORecordSet {
+
+ var $databaseType = "informix72";
+ var $canSeek = true;
+ var $_fieldprops = false;
+
+ function ADORecordset_informix72($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+ return $this->ADORecordSet($id);
+ }
+
+
+
+ /* Returns: an object containing field information.
+ Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+ fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+ fetchField() is retrieved. */
+ function &FetchField($fieldOffset = -1)
+ {
+ if (empty($this->_fieldprops)) {
+ $fp = ifx_fieldproperties($this->_queryID);
+ foreach($fp as $k => $v) {
+ $o = new ADOFieldObject;
+ $o->name = $k;
+ $arr = split(';',$v); //"SQLTYPE;length;precision;scale;ISNULLABLE"
+ $o->type = $arr[0];
+ $o->max_length = $arr[1];
+ $this->_fieldprops[] = $o;
+ $o->not_null = $arr[4]=="N";
+ }
+ }
+ $ret = $this->_fieldprops[$fieldOffset];
+ return $ret;
+ }
+
+ function _initrs()
+ {
+ $this->_numOfRows = -1; // ifx_affected_rows not reliable, only returns estimate -- ($ADODB_COUNTRECS)? ifx_affected_rows($this->_queryID):-1;
+ $this->_numOfFields = ifx_num_fields($this->_queryID);
+ }
+
+ function _seek($row)
+ {
+ return @ifx_fetch_row($this->_queryID, (int) $row);
+ }
+
+ function MoveLast()
+ {
+ $this->fields = @ifx_fetch_row($this->_queryID, "LAST");
+ if ($this->fields) $this->EOF = false;
+ $this->_currentRow = -1;
+
+ if ($this->fetchMode == ADODB_FETCH_NUM) {
+ foreach($this->fields as $v) {
+ $arr[] = $v;
+ }
+ $this->fields = $arr;
+ }
+
+ return true;
+ }
+
+ function MoveFirst()
+ {
+ $this->fields = @ifx_fetch_row($this->_queryID, "FIRST");
+ if ($this->fields) $this->EOF = false;
+ $this->_currentRow = 0;
+
+ if ($this->fetchMode == ADODB_FETCH_NUM) {
+ foreach($this->fields as $v) {
+ $arr[] = $v;
+ }
+ $this->fields = $arr;
+ }
+
+ return true;
+ }
+
+ function _fetch($ignore_fields=false)
+ {
+
+ $this->fields = @ifx_fetch_row($this->_queryID);
+
+ if (!is_array($this->fields)) return false;
+
+ if ($this->fetchMode == ADODB_FETCH_NUM) {
+ foreach($this->fields as $v) {
+ $arr[] = $v;
+ }
+ $this->fields = $arr;
+ }
+ return true;
+ }
+
+ /* close() only needs to be called if you are worried about using too much memory while your script
+ is running. All associated result memory for the specified result identifier will automatically be freed. */
+ function _close()
+ {
+ return ifx_free_result($this->_queryID);
+ }
+
+}
+/** !Eos
+* Auxiliar function to Parse coltype,collength. Used by Metacolumns
+* return: array ($mtype,$length,$precision,$nullable) (similar to ifx_fieldpropierties)
+*/
+function ifx_props($coltype,$collength){
+ $itype=fmod($coltype+1,256);
+ $nullable=floor(($coltype+1) /256) ?"N":"Y";
+ $mtype=substr(" CIIFFNNDN TBXCC ",$itype,1);
+ switch ($itype){
+ case 2:
+ $length=4;
+ case 6:
+ case 9:
+ case 14:
+ $length=floor($collength/256);
+ $precision=fmod($collength,256);
+ break;
+ default:
+ $precision=0;
+ $length=$collength;
+ }
+ return array($mtype,$length,$precision,$nullable);
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-ldap.inc.php b/lib/adodb/drivers/adodb-ldap.inc.php
new file mode 100644
index 0000000..bbf0cbf
--- /dev/null
+++ b/lib/adodb/drivers/adodb-ldap.inc.php
@@ -0,0 +1,406 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+ Revision 1: (02/25/2005) Updated codebase to include the _inject_bind_options function. This allows
+ users to access the options in the ldap_set_option function appropriately. Most importantly
+ LDAP Version 3 is now supported. See the examples for more information. Also fixed some minor
+ bugs that surfaced when PHP error levels were set high.
+
+ Joshua Eldridge (joshuae74#hotmail.com)
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('LDAP_ASSOC')) {
+ define('LDAP_ASSOC',ADODB_FETCH_ASSOC);
+ define('LDAP_NUM',ADODB_FETCH_NUM);
+ define('LDAP_BOTH',ADODB_FETCH_BOTH);
+}
+
+class ADODB_ldap extends ADOConnection {
+ var $databaseType = 'ldap';
+ var $dataProvider = 'ldap';
+
+ # Connection information
+ var $username = false;
+ var $password = false;
+
+ # Used during searches
+ var $filter;
+ var $dn;
+ var $version;
+ var $port = 389;
+
+ # Options configuration information
+ var $LDAP_CONNECT_OPTIONS;
+
+ function ADODB_ldap()
+ {
+ }
+
+ // returns true or false
+
+ function _connect( $host, $username, $password, $ldapbase)
+ {
+ global $LDAP_CONNECT_OPTIONS;
+
+ if ( !function_exists( 'ldap_connect' ) ) return null;
+
+ $conn_info = array( $host,$this->port);
+
+ if ( strstr( $host, ':' ) ) {
+ $conn_info = split( ':', $host );
+ }
+
+ $this->_connectionID = ldap_connect( $conn_info[0], $conn_info[1] );
+ if (!$this->_connectionID) {
+ $e = 'Could not connect to ' . $conn_info[0];
+ $this->_errorMsg = $e;
+ if ($this->debug) ADOConnection::outp($e);
+ return false;
+ }
+ if( count( $LDAP_CONNECT_OPTIONS ) > 0 ) {
+ $this->_inject_bind_options( $LDAP_CONNECT_OPTIONS );
+ }
+
+ if ($username) {
+ $bind = ldap_bind( $this->_connectionID, $username, $password );
+ } else {
+ $username = 'anonymous';
+ $bind = ldap_bind( $this->_connectionID );
+ }
+
+ if (!$bind) {
+ $e = 'Could not bind to ' . $conn_info[0] . " as ".$username;
+ $this->_errorMsg = $e;
+ if ($this->debug) ADOConnection::outp($e);
+ return false;
+ }
+ $this->_errorMsg = '';
+ $this->database = $ldapbase;
+ return $this->_connectionID;
+ }
+
+/*
+ Valid Domain Values for LDAP Options:
+
+ LDAP_OPT_DEREF (integer)
+ LDAP_OPT_SIZELIMIT (integer)
+ LDAP_OPT_TIMELIMIT (integer)
+ LDAP_OPT_PROTOCOL_VERSION (integer)
+ LDAP_OPT_ERROR_NUMBER (integer)
+ LDAP_OPT_REFERRALS (boolean)
+ LDAP_OPT_RESTART (boolean)
+ LDAP_OPT_HOST_NAME (string)
+ LDAP_OPT_ERROR_STRING (string)
+ LDAP_OPT_MATCHED_DN (string)
+ LDAP_OPT_SERVER_CONTROLS (array)
+ LDAP_OPT_CLIENT_CONTROLS (array)
+
+ Make sure to set this BEFORE calling Connect()
+
+ Example:
+
+ $LDAP_CONNECT_OPTIONS = Array(
+ Array (
+ "OPTION_NAME"=>LDAP_OPT_DEREF,
+ "OPTION_VALUE"=>2
+ ),
+ Array (
+ "OPTION_NAME"=>LDAP_OPT_SIZELIMIT,
+ "OPTION_VALUE"=>100
+ ),
+ Array (
+ "OPTION_NAME"=>LDAP_OPT_TIMELIMIT,
+ "OPTION_VALUE"=>30
+ ),
+ Array (
+ "OPTION_NAME"=>LDAP_OPT_PROTOCOL_VERSION,
+ "OPTION_VALUE"=>3
+ ),
+ Array (
+ "OPTION_NAME"=>LDAP_OPT_ERROR_NUMBER,
+ "OPTION_VALUE"=>13
+ ),
+ Array (
+ "OPTION_NAME"=>LDAP_OPT_REFERRALS,
+ "OPTION_VALUE"=>FALSE
+ ),
+ Array (
+ "OPTION_NAME"=>LDAP_OPT_RESTART,
+ "OPTION_VALUE"=>FALSE
+ )
+ );
+*/
+
+ function _inject_bind_options( $options ) {
+ foreach( $options as $option ) {
+ ldap_set_option( $this->_connectionID, $option["OPTION_NAME"], $option["OPTION_VALUE"] )
+ or die( "Unable to set server option: " . $option["OPTION_NAME"] );
+ }
+ }
+
+ /* returns _queryID or false */
+ function _query($sql,$inputarr)
+ {
+ $rs = ldap_search( $this->_connectionID, $this->database, $sql );
+ $this->_errorMsg = ($rs) ? '' : 'Search error on '.$sql;
+ return $rs;
+ }
+
+ /* closes the LDAP connection */
+ function _close()
+ {
+ @ldap_close( $this->_connectionID );
+ $this->_connectionID = false;
+ }
+
+ function SelectDB($db) {
+ $this->database = $db;
+ return true;
+ } // SelectDB
+
+ function ServerInfo()
+ {
+ if( !empty( $this->version ) ) return $this->version;
+ $version = array();
+ /*
+ Determines how aliases are handled during search.
+ LDAP_DEREF_NEVER (0x00)
+ LDAP_DEREF_SEARCHING (0x01)
+ LDAP_DEREF_FINDING (0x02)
+ LDAP_DEREF_ALWAYS (0x03)
+ The LDAP_DEREF_SEARCHING value means aliases are dereferenced during the search but
+ not when locating the base object of the search. The LDAP_DEREF_FINDING value means
+ aliases are dereferenced when locating the base object but not during the search.
+ Default: LDAP_DEREF_NEVER
+ */
+ ldap_get_option( $this->_connectionID, LDAP_OPT_DEREF, $version['LDAP_OPT_DEREF'] ) ;
+ switch ( $version['LDAP_OPT_DEREF'] ) {
+ case 0:
+ $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_NEVER';
+ case 1:
+ $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_SEARCHING';
+ case 2:
+ $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_FINDING';
+ case 3:
+ $version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_ALWAYS';
+ }
+
+ /*
+ A limit on the number of entries to return from a search.
+ LDAP_NO_LIMIT (0) means no limit.
+ Default: LDAP_NO_LIMIT
+ */
+ ldap_get_option( $this->_connectionID, LDAP_OPT_SIZELIMIT, $version['LDAP_OPT_SIZELIMIT'] );
+ if ( $version['LDAP_OPT_SIZELIMIT'] == 0 ) {
+ $version['LDAP_OPT_SIZELIMIT'] = 'LDAP_NO_LIMIT';
+ }
+
+ /*
+ A limit on the number of seconds to spend on a search.
+ LDAP_NO_LIMIT (0) means no limit.
+ Default: LDAP_NO_LIMIT
+ */
+ ldap_get_option( $this->_connectionID, LDAP_OPT_TIMELIMIT, $version['LDAP_OPT_TIMELIMIT'] );
+ if ( $version['LDAP_OPT_TIMELIMIT'] == 0 ) {
+ $version['LDAP_OPT_TIMELIMIT'] = 'LDAP_NO_LIMIT';
+ }
+
+ /*
+ Determines whether the LDAP library automatically follows referrals returned by LDAP servers or not.
+ LDAP_OPT_ON
+ LDAP_OPT_OFF
+ Default: ON
+ */
+ ldap_get_option( $this->_connectionID, LDAP_OPT_REFERRALS, $version['LDAP_OPT_REFERRALS'] );
+ if ( $version['LDAP_OPT_REFERRALS'] == 0 ) {
+ $version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_OFF';
+ } else {
+ $version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_ON';
+
+ }
+ /*
+ Determines whether LDAP I/O operations are automatically restarted if they abort prematurely.
+ LDAP_OPT_ON
+ LDAP_OPT_OFF
+ Default: OFF
+ */
+ ldap_get_option( $this->_connectionID, LDAP_OPT_RESTART, $version['LDAP_OPT_RESTART'] );
+ if ( $version['LDAP_OPT_RESTART'] == 0 ) {
+ $version['LDAP_OPT_RESTART'] = 'LDAP_OPT_OFF';
+ } else {
+ $version['LDAP_OPT_RESTART'] = 'LDAP_OPT_ON';
+
+ }
+ /*
+ This option indicates the version of the LDAP protocol used when communicating with the primary LDAP server.
+ LDAP_VERSION2 (2)
+ LDAP_VERSION3 (3)
+ Default: LDAP_VERSION2 (2)
+ */
+ ldap_get_option( $this->_connectionID, LDAP_OPT_PROTOCOL_VERSION, $version['LDAP_OPT_PROTOCOL_VERSION'] );
+ if ( $version['LDAP_OPT_PROTOCOL_VERSION'] == 2 ) {
+ $version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION2';
+ } else {
+ $version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION3';
+
+ }
+ /* The host name (or list of hosts) for the primary LDAP server. */
+ ldap_get_option( $this->_connectionID, LDAP_OPT_HOST_NAME, $version['LDAP_OPT_HOST_NAME'] );
+ ldap_get_option( $this->_connectionID, LDAP_OPT_ERROR_NUMBER, $version['LDAP_OPT_ERROR_NUMBER'] );
+ ldap_get_option( $this->_connectionID, LDAP_OPT_ERROR_STRING, $version['LDAP_OPT_ERROR_STRING'] );
+ ldap_get_option( $this->_connectionID, LDAP_OPT_MATCHED_DN, $version['LDAP_OPT_MATCHED_DN'] );
+
+ return $this->version = $version;
+
+ }
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_ldap extends ADORecordSet{
+
+ var $databaseType = "ldap";
+ var $canSeek = false;
+ var $_entryID; /* keeps track of the entry resource identifier */
+
+ function ADORecordSet_ldap($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode)
+ {
+ case ADODB_FETCH_NUM:
+ $this->fetchMode = LDAP_NUM;
+ break;
+ case ADODB_FETCH_ASSOC:
+ $this->fetchMode = LDAP_ASSOC;
+ break;
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = LDAP_BOTH;
+ break;
+ }
+
+ $this->ADORecordSet($queryID);
+ }
+
+ function _initrs()
+ {
+ /*
+ This could be teaked to respect the $COUNTRECS directive from ADODB
+ It's currently being used in the _fetch() function and the
+ GetAssoc() function
+ */
+ $this->_numOfRows = ldap_count_entries( $this->connection->_connectionID, $this->_queryID );
+
+ }
+
+ /*
+ Return whole recordset as a multi-dimensional associative array
+ */
+ function &GetAssoc($force_array = false, $first2cols = false)
+ {
+ $records = $this->_numOfRows;
+ $results = array();
+ for ( $i=0; $i < $records; $i++ ) {
+ foreach ( $this->fields as $k=>$v ) {
+ if ( is_array( $v ) ) {
+ if ( $v['count'] == 1 ) {
+ $results[$i][$k] = $v[0];
+ } else {
+ array_shift( $v );
+ $results[$i][$k] = $v;
+ }
+ }
+ }
+ }
+
+ return $results;
+ }
+
+ function &GetRowAssoc()
+ {
+ $results = array();
+ foreach ( $this->fields as $k=>$v ) {
+ if ( is_array( $v ) ) {
+ if ( $v['count'] == 1 ) {
+ $results[$k] = $v[0];
+ } else {
+ array_shift( $v );
+ $results[$k] = $v;
+ }
+ }
+ }
+
+ return $results;
+ }
+
+ function GetRowNums()
+ {
+ $results = array();
+ foreach ( $this->fields as $k=>$v ) {
+ static $i = 0;
+ if (is_array( $v )) {
+ if ( $v['count'] == 1 ) {
+ $results[$i] = $v[0];
+ } else {
+ array_shift( $v );
+ $results[$i] = $v;
+ }
+ $i++;
+ }
+ }
+ return $results;
+ }
+
+ function _fetch()
+ {
+ if ( $this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0 )
+ return false;
+
+ if ( $this->_currentRow == 0 ) {
+ $this->_entryID = ldap_first_entry( $this->connection->_connectionID, $this->_queryID );
+ } else {
+ $this->_entryID = ldap_next_entry( $this->connection->_connectionID, $this->_entryID );
+ }
+
+ $this->fields = ldap_get_attributes( $this->connection->_connectionID, $this->_entryID );
+ $this->_numOfFields = $this->fields['count'];
+ switch ( $this->fetchMode ) {
+
+ case LDAP_ASSOC:
+ $this->fields = $this->GetRowAssoc();
+ break;
+
+ case LDAP_NUM:
+ $this->fields = array_merge($this->GetRowNums(),$this->GetRowAssoc());
+ break;
+
+ case LDAP_BOTH:
+ default:
+ $this->fields = $this->GetRowNums();
+ break;
+ }
+ return ( is_array( $this->fields ) );
+ }
+
+ function _close() {
+ @ldap_free_result( $this->_queryID );
+ $this->_queryID = false;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-mssql.inc.php b/lib/adodb/drivers/adodb-mssql.inc.php
new file mode 100644
index 0000000..8eebd91
--- /dev/null
+++ b/lib/adodb/drivers/adodb-mssql.inc.php
@@ -0,0 +1,1037 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Native mssql driver. Requires mssql client. Works on Windows.
+ To configure for Unix, see
+ http://phpbuilder.com/columns/alberto20000919.php3
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+//----------------------------------------------------------------
+// MSSQL returns dates with the format Oct 13 2002 or 13 Oct 2002
+// and this causes tons of problems because localized versions of
+// MSSQL will return the dates in dmy or mdy order; and also the
+// month strings depends on what language has been configured. The
+// following two variables allow you to control the localization
+// settings - Ugh.
+//
+// MORE LOCALIZATION INFO
+// ----------------------
+// To configure datetime, look for and modify sqlcommn.loc,
+// typically found in c:\mssql\install
+// Also read :
+// http://support.microsoft.com/default.aspx?scid=kb;EN-US;q220918
+// Alternatively use:
+// CONVERT(char(12),datecol,120)
+//----------------------------------------------------------------
+
+
+// has datetime converstion to YYYY-MM-DD format, and also mssql_fetch_assoc
+if (ADODB_PHPVER >= 0x4300) {
+// docs say 4.2.0, but testing shows only since 4.3.0 does it work!
+ ini_set('mssql.datetimeconvert',0);
+} else {
+global $ADODB_mssql_mths; // array, months must be upper-case
+
+
+ $ADODB_mssql_date_order = 'mdy';
+ $ADODB_mssql_mths = array(
+ 'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
+ 'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
+}
+
+//---------------------------------------------------------------------------
+// Call this to autoset $ADODB_mssql_date_order at the beginning of your code,
+// just after you connect to the database. Supports mdy and dmy only.
+// Not required for PHP 4.2.0 and above.
+function AutoDetect_MSSQL_Date_Order($conn)
+{
+global $ADODB_mssql_date_order;
+ $adate = $conn->GetOne('select getdate()');
+ if ($adate) {
+ $anum = (int) $adate;
+ if ($anum > 0) {
+ if ($anum > 31) {
+ //ADOConnection::outp( "MSSQL: YYYY-MM-DD date format not supported currently");
+ } else
+ $ADODB_mssql_date_order = 'dmy';
+ } else
+ $ADODB_mssql_date_order = 'mdy';
+ }
+}
+
+class ADODB_mssql extends ADOConnection {
+ var $databaseType = "mssql";
+ var $dataProvider = "mssql";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $hasInsertID = true;
+ var $substr = "substring";
+ var $length = 'len';
+ var $hasAffectedRows = true;
+ var $metaDatabasesSQL = "select name from sysdatabases where name <> 'master'";
+ var $metaTablesSQL="select name,case when type='U' then 'T' else 'V' end from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE','dtproperties'))";
+ var $metaColumnsSQL = # xtype==61 is datetime
+"select c.name,t.name,c.length,
+ (case when c.xusertype=61 then 0 else c.xprec end),
+ (case when c.xusertype=61 then 0 else c.xscale end)
+ from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";
+ var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE
+ var $hasGenID = true;
+ var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
+ var $sysTimeStamp = 'GetDate()';
+ var $_has_mssql_init;
+ var $maxParameterLen = 4000;
+ var $arrayClass = 'ADORecordSet_array_mssql';
+ var $uniqueSort = true;
+ var $leftOuter = '*=';
+ var $rightOuter = '=*';
+ var $ansiOuter = true; // for mssql7 or later
+ var $poorAffectedRows = true;
+ var $identitySQL = 'select @@IDENTITY'; // 'select SCOPE_IDENTITY'; # for mssql 2000
+ var $uniqueOrderBy = true;
+ var $_bindInputArray = true;
+
+ function ADODB_mssql()
+ {
+ $this->_has_mssql_init = (strnatcmp(PHP_VERSION,'4.1.0')>=0);
+ }
+
+ function ServerInfo()
+ {
+ global $ADODB_FETCH_MODE;
+
+
+ if ($this->fetchMode === false) {
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ } else
+ $savem = $this->SetFetchMode(ADODB_FETCH_NUM);
+
+ if (0) {
+ $stmt = $this->PrepareSP('sp_server_info');
+ $val = 2;
+ $this->Parameter($stmt,$val,'attribute_id');
+ $row = $this->GetRow($stmt);
+ }
+
+ $row = $this->GetRow("execute sp_server_info 2");
+
+
+ if ($this->fetchMode === false) {
+ $ADODB_FETCH_MODE = $savem;
+ } else
+ $this->SetFetchMode($savem);
+
+ $arr['description'] = $row[2];
+ $arr['version'] = ADOConnection::_findvers($arr['description']);
+ return $arr;
+ }
+
+ function IfNull( $field, $ifNull )
+ {
+ return " ISNULL($field, $ifNull) "; // if MS SQL Server
+ }
+
+ function _insertid()
+ {
+ // SCOPE_IDENTITY()
+ // Returns the last IDENTITY value inserted into an IDENTITY column in
+ // the same scope. A scope is a module -- a stored procedure, trigger,
+ // function, or batch. Thus, two statements are in the same scope if
+ // they are in the same stored procedure, function, or batch.
+ return $this->GetOne($this->identitySQL);
+ }
+
+ function _affectedrows()
+ {
+ return $this->GetOne('select @@rowcount');
+ }
+
+ var $_dropSeqSQL = "drop table %s";
+
+ function CreateSequence($seq='adodbseq',$start=1)
+ {
+
+ $this->Execute('BEGIN TRANSACTION adodbseq');
+ $start -= 1;
+ $this->Execute("create table $seq (id float(53))");
+ $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
+ if (!$ok) {
+ $this->Execute('ROLLBACK TRANSACTION adodbseq');
+ return false;
+ }
+ $this->Execute('COMMIT TRANSACTION adodbseq');
+ return true;
+ }
+
+ function GenID($seq='adodbseq',$start=1)
+ {
+ //$this->debug=1;
+ $this->Execute('BEGIN TRANSACTION adodbseq');
+ $ok = $this->Execute("update $seq with (tablock,holdlock) set id = id + 1");
+ if (!$ok) {
+ $this->Execute("create table $seq (id float(53))");
+ $ok = $this->Execute("insert into $seq with (tablock,holdlock) values($start)");
+ if (!$ok) {
+ $this->Execute('ROLLBACK TRANSACTION adodbseq');
+ return false;
+ }
+ $this->Execute('COMMIT TRANSACTION adodbseq');
+ return $start;
+ }
+ $num = $this->GetOne("select id from $seq");
+ $this->Execute('COMMIT TRANSACTION adodbseq');
+ return $num;
+
+ // in old implementation, pre 1.90, we returned GUID...
+ //return $this->GetOne("SELECT CONVERT(varchar(255), NEWID()) AS 'Char'");
+ }
+
+
+ function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
+ {
+ if ($nrows > 0 && $offset <= 0) {
+ $sql = preg_replace(
+ '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql);
+ $rs =& $this->Execute($sql,$inputarr);
+ } else
+ $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+
+ return $rs;
+ }
+
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysTimeStamp;
+ $s = '';
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ if ($s) $s .= '+';
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= "datename(yyyy,$col)";
+ break;
+ case 'M':
+ $s .= "convert(char(3),$col,0)";
+ break;
+ case 'm':
+ $s .= "replace(str(month($col),2),' ','0')";
+ break;
+ case 'Q':
+ case 'q':
+ $s .= "datename(quarter,$col)";
+ break;
+ case 'D':
+ case 'd':
+ $s .= "replace(str(day($col),2),' ','0')";
+ break;
+ case 'h':
+ $s .= "substring(convert(char(14),$col,0),13,2)";
+ break;
+
+ case 'H':
+ $s .= "replace(str(datepart(hh,$col),2),' ','0')";
+ break;
+
+ case 'i':
+ $s .= "replace(str(datepart(mi,$col),2),' ','0')";
+ break;
+ case 's':
+ $s .= "replace(str(datepart(ss,$col),2),' ','0')";
+ break;
+ case 'a':
+ case 'A':
+ $s .= "substring(convert(char(19),$col,0),18,2)";
+ break;
+
+ default:
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ $s .= $this->qstr($ch);
+ break;
+ }
+ }
+ return $s;
+ }
+
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->Execute('BEGIN TRAN');
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->Execute('COMMIT TRAN');
+ return true;
+ }
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->Execute('ROLLBACK TRAN');
+ return true;
+ }
+
+ function SetTransactionMode( $transaction_mode )
+ {
+ $this->_transmode = $transaction_mode;
+ if (empty($transaction_mode)) {
+ $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+ return;
+ }
+ if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+ $this->Execute("SET TRANSACTION ".$transaction_mode);
+ }
+
+ /*
+ Usage:
+
+ $this->BeginTrans();
+ $this->RowLock('table1,table2','table1.id=33 and table2.id=table1.id'); # lock row 33 for both tables
+
+ # some operation on both tables table1 and table2
+
+ $this->CommitTrans();
+
+ See http://www.swynk.com/friends/achigrik/SQL70Locks.asp
+ */
+ function RowLock($tables,$where,$flds='top 1 null as ignore')
+ {
+ if (!$this->transCnt) $this->BeginTrans();
+ return $this->GetOne("select $flds from $tables with (ROWLOCK,HOLDLOCK) where $where");
+ }
+
+
+ function &MetaIndexes($table,$primary=false)
+ {
+ $table = $this->qstr($table);
+
+ $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno,
+ CASE WHEN I.indid BETWEEN 1 AND 254 AND (I.status & 2048 = 2048 OR I.Status = 16402 AND O.XType = 'V') THEN 1 ELSE 0 END AS IsPK,
+ CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique
+ FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id
+ INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid
+ INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid
+ WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table
+ ORDER BY O.name, I.Name, K.keyno";
+
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+
+ $rs = $this->Execute($sql);
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ if (!is_object($rs)) {
+ return FALSE;
+ }
+
+ $indexes = array();
+ while ($row = $rs->FetchRow()) {
+ if (!$primary && $row[5]) continue;
+
+ $indexes[$row[0]]['unique'] = $row[6];
+ $indexes[$row[0]]['columns'][] = $row[1];
+ }
+ return $indexes;
+ }
+
+ function MetaForeignKeys($table, $owner=false, $upper=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $table = $this->qstr(strtoupper($table));
+
+ $sql =
+"select object_name(constid) as constraint_name,
+ col_name(fkeyid, fkey) as column_name,
+ object_name(rkeyid) as referenced_table_name,
+ col_name(rkeyid, rkey) as referenced_column_name
+from sysforeignkeys
+where upper(object_name(fkeyid)) = $table
+order by constraint_name, referenced_table_name, keyno";
+
+ $constraints =& $this->GetArray($sql);
+
+ $ADODB_FETCH_MODE = $save;
+
+ $arr = false;
+ foreach($constraints as $constr) {
+ //print_r($constr);
+ $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3];
+ }
+ if (!$arr) return false;
+
+ $arr2 = false;
+
+ foreach($arr as $k => $v) {
+ foreach($v as $a => $b) {
+ if ($upper) $a = strtoupper($a);
+ $arr2[$a] = $b;
+ }
+ }
+ return $arr2;
+ }
+
+ //From: Fernando Moreira <FMoreira@imediata.pt>
+ function MetaDatabases()
+ {
+ if(@mssql_select_db("master")) {
+ $qry=$this->metaDatabasesSQL;
+ if($rs=@mssql_query($qry,$this->_connectionID)){
+ $tmpAr=$ar=array();
+ while($tmpAr=@mssql_fetch_row($rs))
+ $ar[]=$tmpAr[0];
+ @mssql_select_db($this->database);
+ if(sizeof($ar))
+ return($ar);
+ else
+ return(false);
+ } else {
+ @mssql_select_db($this->database);
+ return(false);
+ }
+ }
+ return(false);
+ }
+
+ // "Stein-Aksel Basma" <basma@accelero.no>
+ // tested with MSSQL 2000
+ function &MetaPrimaryKeys($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $schema = '';
+ $this->_findschema($table,$schema);
+ if (!$schema) $schema = $this->database;
+ if ($schema) $schema = "and k.table_catalog like '$schema%'";
+
+ $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k,
+ information_schema.table_constraints tc
+ where tc.constraint_name = k.constraint_name and tc.constraint_type =
+ 'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position ";
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $a = $this->GetCol($sql);
+ $ADODB_FETCH_MODE = $savem;
+
+ if ($a && sizeof($a)>0) return $a;
+ $false = false;
+ return $false;
+ }
+
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ if ($mask) {
+ $save = $this->metaTablesSQL;
+ $mask = $this->qstr(($mask));
+ $this->metaTablesSQL .= " AND name like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ if ($mask) {
+ $this->metaTablesSQL = $save;
+ }
+ return $ret;
+ }
+
+ function SelectDB($dbName)
+ {
+ $this->database = $dbName;
+ $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
+ if ($this->_connectionID) {
+ return @mssql_select_db($dbName);
+ }
+ else return false;
+ }
+
+ function ErrorMsg()
+ {
+ if (empty($this->_errorMsg)){
+ $this->_errorMsg = mssql_get_last_message();
+ }
+ return $this->_errorMsg;
+ }
+
+ function ErrorNo()
+ {
+ if ($this->_logsql && $this->_errorCode !== false) return $this->_errorCode;
+ if (empty($this->_errorMsg)) {
+ $this->_errorMsg = mssql_get_last_message();
+ }
+ $id = @mssql_query("select @@ERROR",$this->_connectionID);
+ if (!$id) return false;
+ $arr = mssql_fetch_array($id);
+ @mssql_free_result($id);
+ if (is_array($arr)) return $arr[0];
+ else return -1;
+ }
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!function_exists('mssql_pconnect')) return null;
+ $this->_connectionID = mssql_connect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!function_exists('mssql_pconnect')) return null;
+ $this->_connectionID = mssql_pconnect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+
+ // persistent connections can forget to rollback on crash, so we do it here.
+ if ($this->autoRollback) {
+ $cnt = $this->GetOne('select @@TRANCOUNT');
+ while (--$cnt >= 0) $this->Execute('ROLLBACK TRAN');
+ }
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ function Prepare($sql)
+ {
+ $sqlarr = explode('?',$sql);
+ if (sizeof($sqlarr) <= 1) return $sql;
+ $sql2 = $sqlarr[0];
+ for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {
+ $sql2 .= '@P'.($i-1) . $sqlarr[$i];
+ }
+ return array($sql,$this->qstr($sql2),$max);
+ }
+
+ function PrepareSP($sql)
+ {
+ if (!$this->_has_mssql_init) {
+ ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");
+ return $sql;
+ }
+ $stmt = mssql_init($sql,$this->_connectionID);
+ if (!$stmt) return $sql;
+ return array($sql,$stmt);
+ }
+
+ // returns concatenated string
+ // MSSQL requires integers to be cast as strings
+ // automatically cast every datatype to VARCHAR(255)
+ // @author David Rogers (introspectshun)
+ function Concat()
+ {
+ $s = "";
+ $arr = func_get_args();
+
+ // Split single record on commas, if possible
+ if (sizeof($arr) == 1) {
+ foreach ($arr as $arg) {
+ $args = explode(',', $arg);
+ }
+ $arr = $args;
+ }
+
+ array_walk($arr, create_function('&$v', '$v = "CAST(" . $v . " AS VARCHAR(255))";'));
+ $s = implode('+',$arr);
+ if (sizeof($arr) > 0) return "$s";
+
+ return '';
+ }
+
+ /*
+ Usage:
+ $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group
+
+ # note that the parameter does not have @ in front!
+ $db->Parameter($stmt,$id,'myid');
+ $db->Parameter($stmt,$group,'group',false,64);
+ $db->Execute($stmt);
+
+ @param $stmt Statement returned by Prepare() or PrepareSP().
+ @param $var PHP variable to bind to. Can set to null (for isNull support).
+ @param $name Name of stored procedure variable name to bind to.
+ @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
+ @param [$maxLen] Holds an maximum length of the variable.
+ @param [$type] The data type of $var. Legal values depend on driver.
+
+ See mssql_bind documentation at php.net.
+ */
+ function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=4000, $type=false)
+ {
+ if (!$this->_has_mssql_init) {
+ ADOConnection::outp( "Parameter: mssql_bind only available since PHP 4.1.0");
+ return false;
+ }
+
+ $isNull = is_null($var); // php 4.0.4 and above...
+
+ if ($type === false)
+ switch(gettype($var)) {
+ default:
+ case 'string': $type = SQLCHAR; break;
+ case 'double': $type = SQLFLT8; break;
+ case 'integer': $type = SQLINT4; break;
+ case 'boolean': $type = SQLINT1; break; # SQLBIT not supported in 4.1.0
+ }
+
+ if ($this->debug) {
+ $prefix = ($isOutput) ? 'Out' : 'In';
+ $ztype = (empty($type)) ? 'false' : $type;
+ ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
+ }
+ /*
+ See http://phplens.com/lens/lensforum/msgs.php?id=7231
+
+ RETVAL is HARD CODED into php_mssql extension:
+ The return value (a long integer value) is treated like a special OUTPUT parameter,
+ called "RETVAL" (without the @). See the example at mssql_execute to
+ see how it works. - type: one of this new supported PHP constants.
+ SQLTEXT, SQLVARCHAR,SQLCHAR, SQLINT1,SQLINT2, SQLINT4, SQLBIT,SQLFLT8
+ */
+ if ($name !== 'RETVAL') $name = '@'.$name;
+ return mssql_bind($stmt[1], $name, $var, $type, $isOutput, $isNull, $maxLen);
+ }
+
+ /*
+ Unfortunately, it appears that mssql cannot handle varbinary > 255 chars
+ So all your blobs must be of type "image".
+
+ Remember to set in php.ini the following...
+
+ ; Valid range 0 - 2147483647. Default = 4096.
+ mssql.textlimit = 0 ; zero to pass through
+
+ ; Valid range 0 - 2147483647. Default = 4096.
+ mssql.textsize = 0 ; zero to pass through
+ */
+ function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+
+ if (strtoupper($blobtype) == 'CLOB') {
+ $sql = "UPDATE $table SET $column='" . $val . "' WHERE $where";
+ return $this->Execute($sql) != false;
+ }
+ $sql = "UPDATE $table SET $column=0x".bin2hex($val)." WHERE $where";
+ return $this->Execute($sql) != false;
+ }
+
+ // returns query ID if successful, otherwise false
+ function _query($sql,$inputarr)
+ {
+ $this->_errorMsg = false;
+ if (is_array($inputarr)) {
+
+ # bind input params with sp_executesql:
+ # see http://www.quest-pipelines.com/newsletter-v3/0402_F.htm
+ # works only with sql server 7 and newer
+ if (!is_array($sql)) $sql = $this->Prepare($sql);
+ $params = '';
+ $decl = '';
+ $i = 0;
+ foreach($inputarr as $v) {
+ if ($decl) {
+ $decl .= ', ';
+ $params .= ', ';
+ }
+ if (is_string($v)) {
+ $len = strlen($v);
+ if ($len == 0) $len = 1;
+
+ if ($len > 4000 ) {
+ // NVARCHAR is max 4000 chars. Let's use NTEXT
+ $decl .= "@P$i NTEXT";
+ } else {
+ $decl .= "@P$i NVARCHAR($len)";
+ }
+
+ $params .= "@P$i=N". (strncmp($v,"'",1)==0? $v : $this->qstr($v));
+ } else if (is_integer($v)) {
+ $decl .= "@P$i INT";
+ $params .= "@P$i=".$v;
+ } else if (is_float($v)) {
+ $decl .= "@P$i FLOAT";
+ $params .= "@P$i=".$v;
+ } else if (is_bool($v)) {
+ $decl .= "@P$i INT"; # Used INT just in case BIT in not supported on the user's MSSQL version. It will cast appropriately.
+ $params .= "@P$i=".(($v)?'1':'0'); # True == 1 in MSSQL BIT fields and acceptable for storing logical true in an int field
+ } else {
+ $decl .= "@P$i CHAR"; # Used char because a type is required even when the value is to be NULL.
+ $params .= "@P$i=NULL";
+ }
+ $i += 1;
+ }
+ $decl = $this->qstr($decl);
+ if ($this->debug) ADOConnection::outp("<font size=-1>sp_executesql N{$sql[1]},N$decl,$params</font>");
+ $rez = mssql_query("sp_executesql N{$sql[1]},N$decl,$params", $this->_connectionID);
+
+ } else if (is_array($sql)) {
+ # PrepareSP()
+ $rez = mssql_execute($sql[1]);
+
+ } else {
+ $rez = mssql_query($sql,$this->_connectionID);
+ }
+ return $rez;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ if ($this->transCnt) $this->RollbackTrans();
+ $rez = @mssql_close($this->_connectionID);
+ $this->_connectionID = false;
+ return $rez;
+ }
+
+ // mssql uses a default date like Dec 30 2000 12:00AM
+ function UnixDate($v)
+ {
+ return ADORecordSet_array_mssql::UnixDate($v);
+ }
+
+ function UnixTimeStamp($v)
+ {
+ return ADORecordSet_array_mssql::UnixTimeStamp($v);
+ }
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_mssql extends ADORecordSet {
+
+ var $databaseType = "mssql";
+ var $canSeek = true;
+ var $hasFetchAssoc; // see http://phplens.com/lens/lensforum/msgs.php?id=6083
+ // _mths works only in non-localised system
+
+ function ADORecordset_mssql($id,$mode=false)
+ {
+ // freedts check...
+ $this->hasFetchAssoc = function_exists('mssql_fetch_assoc');
+
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+
+ }
+ $this->fetchMode = $mode;
+ return $this->ADORecordSet($id,$mode);
+ }
+
+
+ function _initrs()
+ {
+ GLOBAL $ADODB_COUNTRECS;
+ $this->_numOfRows = ($ADODB_COUNTRECS)? @mssql_num_rows($this->_queryID):-1;
+ $this->_numOfFields = @mssql_num_fields($this->_queryID);
+ }
+
+
+ //Contributed by "Sven Axelsson" <sven.axelsson@bokochwebb.se>
+ // get next resultset - requires PHP 4.0.5 or later
+ function NextRecordSet()
+ {
+ if (!mssql_next_result($this->_queryID)) return false;
+ $this->_inited = false;
+ $this->bind = false;
+ $this->_currentRow = -1;
+ $this->Init();
+ return true;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode != ADODB_FETCH_NUM) 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)]];
+ }
+
+ /* Returns: an object containing field information.
+ Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+ fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+ fetchField() is retrieved. */
+
+ function &FetchField($fieldOffset = -1)
+ {
+ if ($fieldOffset != -1) {
+ $f = @mssql_fetch_field($this->_queryID, $fieldOffset);
+ }
+ else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */
+ $f = @mssql_fetch_field($this->_queryID);
+ }
+ $false = false;
+ if (empty($f)) return $false;
+ return $f;
+ }
+
+ function _seek($row)
+ {
+ return @mssql_data_seek($this->_queryID, $row);
+ }
+
+ // speedup
+ function MoveNext()
+ {
+ if ($this->EOF) return false;
+
+ $this->_currentRow++;
+
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ if ($this->fetchMode & ADODB_FETCH_NUM) {
+ //ADODB_FETCH_BOTH mode
+ $this->fields = @mssql_fetch_array($this->_queryID);
+ }
+ else {
+ if ($this->hasFetchAssoc) {// only for PHP 4.2.0 or later
+ $this->fields = @mssql_fetch_assoc($this->_queryID);
+ } else {
+ $flds = @mssql_fetch_array($this->_queryID);
+ if (is_array($flds)) {
+ $fassoc = array();
+ foreach($flds as $k => $v) {
+ if (is_numeric($k)) continue;
+ $fassoc[$k] = $v;
+ }
+ $this->fields = $fassoc;
+ } else
+ $this->fields = false;
+ }
+ }
+
+ if (is_array($this->fields)) {
+ if (ADODB_ASSOC_CASE == 0) {
+ foreach($this->fields as $k=>$v) {
+ $this->fields[strtolower($k)] = $v;
+ }
+ } else if (ADODB_ASSOC_CASE == 1) {
+ foreach($this->fields as $k=>$v) {
+ $this->fields[strtoupper($k)] = $v;
+ }
+ }
+ }
+ } else {
+ $this->fields = @mssql_fetch_row($this->_queryID);
+ }
+ if ($this->fields) return true;
+ $this->EOF = true;
+
+ return false;
+ }
+
+
+ // INSERT UPDATE DELETE returns false even if no error occurs in 4.0.4
+ // also the date format has been changed from YYYY-mm-dd to dd MMM YYYY in 4.0.4. Idiot!
+ function _fetch($ignore_fields=false)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ if ($this->fetchMode & ADODB_FETCH_NUM) {
+ //ADODB_FETCH_BOTH mode
+ $this->fields = @mssql_fetch_array($this->_queryID);
+ } else {
+ if ($this->hasFetchAssoc) // only for PHP 4.2.0 or later
+ $this->fields = @mssql_fetch_assoc($this->_queryID);
+ else {
+ $this->fields = @mssql_fetch_array($this->_queryID);
+ if (@is_array($$this->fields)) {
+ $fassoc = array();
+ foreach($$this->fields as $k => $v) {
+ if (is_integer($k)) continue;
+ $fassoc[$k] = $v;
+ }
+ $this->fields = $fassoc;
+ }
+ }
+ }
+
+ if (!$this->fields) {
+ } else if (ADODB_ASSOC_CASE == 0) {
+ foreach($this->fields as $k=>$v) {
+ $this->fields[strtolower($k)] = $v;
+ }
+ } else if (ADODB_ASSOC_CASE == 1) {
+ foreach($this->fields as $k=>$v) {
+ $this->fields[strtoupper($k)] = $v;
+ }
+ }
+ } else {
+ $this->fields = @mssql_fetch_row($this->_queryID);
+ }
+ return $this->fields;
+ }
+
+ /* close() only needs to be called if you are worried about using too much memory while your script
+ is running. All associated result memory for the specified result identifier will automatically be freed. */
+
+ function _close()
+ {
+ $rez = mssql_free_result($this->_queryID);
+ $this->_queryID = false;
+ return $rez;
+ }
+ // mssql uses a default date like Dec 30 2000 12:00AM
+ function UnixDate($v)
+ {
+ return ADORecordSet_array_mssql::UnixDate($v);
+ }
+
+ function UnixTimeStamp($v)
+ {
+ return ADORecordSet_array_mssql::UnixTimeStamp($v);
+ }
+
+}
+
+
+class ADORecordSet_array_mssql extends ADORecordSet_array {
+ function ADORecordSet_array_mssql($id=-1,$mode=false)
+ {
+ $this->ADORecordSet_array($id,$mode);
+ }
+
+ // mssql uses a default date like Dec 30 2000 12:00AM
+ function UnixDate($v)
+ {
+
+ if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixDate($v);
+
+ global $ADODB_mssql_mths,$ADODB_mssql_date_order;
+
+ //Dec 30 2000 12:00AM
+ if ($ADODB_mssql_date_order == 'dmy') {
+ if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
+ return parent::UnixDate($v);
+ }
+ if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+
+ $theday = $rr[1];
+ $themth = substr(strtoupper($rr[2]),0,3);
+ } else {
+ if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})|" ,$v, $rr)) {
+ return parent::UnixDate($v);
+ }
+ if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+
+ $theday = $rr[2];
+ $themth = substr(strtoupper($rr[1]),0,3);
+ }
+ $themth = $ADODB_mssql_mths[$themth];
+ if ($themth <= 0) return false;
+ // h-m-s-MM-DD-YY
+ return mktime(0,0,0,$themth,$theday,$rr[3]);
+ }
+
+ function UnixTimeStamp($v)
+ {
+
+ if (is_numeric(substr($v,0,1)) && ADODB_PHPVER >= 0x4200) return parent::UnixTimeStamp($v);
+
+ global $ADODB_mssql_mths,$ADODB_mssql_date_order;
+
+ //Dec 30 2000 12:00AM
+ if ($ADODB_mssql_date_order == 'dmy') {
+ if (!preg_match( "|^([0-9]{1,2})[-/\. ]+([A-Za-z]{3})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|"
+ ,$v, $rr)) return parent::UnixTimeStamp($v);
+ if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+
+ $theday = $rr[1];
+ $themth = substr(strtoupper($rr[2]),0,3);
+ } else {
+ if (!preg_match( "|^([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})|"
+ ,$v, $rr)) return parent::UnixTimeStamp($v);
+ if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+
+ $theday = $rr[2];
+ $themth = substr(strtoupper($rr[1]),0,3);
+ }
+
+ $themth = $ADODB_mssql_mths[$themth];
+ if ($themth <= 0) return false;
+
+ switch (strtoupper($rr[6])) {
+ case 'P':
+ if ($rr[4]<12) $rr[4] += 12;
+ break;
+ case 'A':
+ if ($rr[4]==12) $rr[4] = 0;
+ break;
+ default:
+ break;
+ }
+ // h-m-s-MM-DD-YY
+ return mktime($rr[4],$rr[5],0,$themth,$theday,$rr[3]);
+ }
+}
+
+/*
+Code Example 1:
+
+select object_name(constid) as constraint_name,
+ object_name(fkeyid) as table_name,
+ col_name(fkeyid, fkey) as column_name,
+ object_name(rkeyid) as referenced_table_name,
+ col_name(rkeyid, rkey) as referenced_column_name
+from sysforeignkeys
+where object_name(fkeyid) = x
+order by constraint_name, table_name, referenced_table_name, keyno
+
+Code Example 2:
+select constraint_name,
+ column_name,
+ ordinal_position
+from information_schema.key_column_usage
+where constraint_catalog = db_name()
+and table_name = x
+order by constraint_name, ordinal_position
+
+http://www.databasejournal.com/scripts/article.php/1440551
+*/
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-mssql_n.inc.php b/lib/adodb/drivers/adodb-mssql_n.inc.php
new file mode 100644
index 0000000..d112f89
--- /dev/null
+++ b/lib/adodb/drivers/adodb-mssql_n.inc.php
@@ -0,0 +1,166 @@
+<?php
+
+/// $Id $
+
+///////////////////////////////////////////////////////////////////////////
+// //
+// NOTICE OF COPYRIGHT //
+// //
+// ADOdb - Database Abstraction Library for PHP //
+// http://adodb.sourceforge.net/ //
+// //
+// Copyright (C) 2000-2007 John Lim (jlim\@natsoft.com.my) //
+// All rights reserved. //
+// Released under both BSD license and LGPL library license. //
+// Whenever there is any discrepancy between the two licenses, //
+// the BSD license will take precedence //
+// //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment //
+// http://moodle.com //
+// //
+// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
+// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation; either version 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License for more details: //
+// //
+// http://www.gnu.org/copyleft/gpl.html //
+// //
+///////////////////////////////////////////////////////////////////////////
+
+/**
+* MSSQL Driver with auto-prepended "N" for correct unicode storage
+* of SQL literal strings. Intended to be used with MSSQL drivers that
+* are sending UCS-2 data to MSSQL (FreeTDS and ODBTP) in order to get
+* true cross-db compatibility from the application point of view.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+// one useful constant
+if (!defined('SINGLEQUOTE')) define('SINGLEQUOTE', "'");
+
+include_once(ADODB_DIR.'/drivers/adodb-mssql.inc.php');
+
+class ADODB_mssql_n extends ADODB_mssql {
+ var $databaseType = "mssql_n";
+
+ function ADODB_mssqlpo()
+ {
+ ADODB_mssql::ADODB_mssql();
+ }
+
+ function _query($sql,$inputarr)
+ {
+ $sql = $this->_appendN($sql);
+ return ADODB_mssql::_query($sql,$inputarr);
+ }
+
+ /**
+ * This function will intercept all the literals used in the SQL, prepending the "N" char to them
+ * in order to allow mssql to store properly data sent in the correct UCS-2 encoding (by freeTDS
+ * and ODBTP) keeping SQL compatibility at ADOdb level (instead of hacking every project to add
+ * the "N" notation when working against MSSQL.
+ *
+ * Note that this hack only must be used if ALL the char-based columns in your DB are of type nchar,
+ * nvarchar and ntext
+ */
+ function _appendN($sql) {
+
+ $result = $sql;
+
+ /// Check we have some single quote in the query. Exit ok.
+ if (strpos($sql, SINGLEQUOTE) === false) {
+ return $sql;
+ }
+
+ /// Check we haven't an odd number of single quotes (this can cause problems below
+ /// and should be considered one wrong SQL). Exit with debug info.
+ if ((substr_count($sql, SINGLEQUOTE) & 1)) {
+ if ($this->debug) {
+ ADOConnection::outp("{$this->databaseType} internal transformation: not converted. Wrong number of quotes (odd)");
+ }
+ return $sql;
+ }
+
+ /// Check we haven't any backslash + single quote combination. It should mean wrong
+ /// backslashes use (bad magic_quotes_sybase?). Exit with debug info.
+ $regexp = '/(\\\\' . SINGLEQUOTE . '[^' . SINGLEQUOTE . '])/';
+ if (preg_match($regexp, $sql)) {
+ if ($this->debug) {
+ ADOConnection::outp("{$this->databaseType} internal transformation: not converted. Found bad use of backslash + single quote");
+ }
+ return $sql;
+ }
+
+ /// Remove pairs of single-quotes
+ $pairs = array();
+ $regexp = '/(' . SINGLEQUOTE . SINGLEQUOTE . ')/';
+ preg_match_all($regexp, $result, $list_of_pairs);
+ if ($list_of_pairs) {
+ foreach (array_unique($list_of_pairs[0]) as $key=>$value) {
+ $pairs['<@#@#@PAIR-'.$key.'@#@#@>'] = $value;
+ }
+ if (!empty($pairs)) {
+ $result = str_replace($pairs, array_keys($pairs), $result);
+ }
+ }
+
+ /// Remove the rest of literals present in the query
+ $literals = array();
+ $regexp = '/(N?' . SINGLEQUOTE . '.*?' . SINGLEQUOTE . ')/is';
+ preg_match_all($regexp, $result, $list_of_literals);
+ if ($list_of_literals) {
+ foreach (array_unique($list_of_literals[0]) as $key=>$value) {
+ $literals['<#@#@#LITERAL-'.$key.'#@#@#>'] = $value;
+ }
+ if (!empty($literals)) {
+ $result = str_replace($literals, array_keys($literals), $result);
+ }
+ }
+
+ /// Analyse literals to prepend the N char to them if their contents aren't numeric
+ if (!empty($literals)) {
+ foreach ($literals as $key=>$value) {
+ if (!is_numeric(trim($value, SINGLEQUOTE))) {
+ /// Non numeric string, prepend our dear N
+ $literals[$key] = 'N' . trim($value, 'N'); //Trimming potentially existing previous "N"
+ }
+ }
+ }
+
+ /// Re-apply literals to the text
+ if (!empty($literals)) {
+ $result = str_replace(array_keys($literals), $literals, $result);
+ }
+
+ /// Re-apply pairs of single-quotes to the text
+ if (!empty($pairs)) {
+ $result = str_replace(array_keys($pairs), $pairs, $result);
+ }
+
+ /// Print transformation if debug = on
+ if ($result != $sql && $this->debug) {
+ ADOConnection::outp("{$this->databaseType} internal transformation:<br>{$sql}<br>to<br>{$result}");
+ }
+
+ return $result;
+ }
+}
+
+class ADORecordset_mssql_n extends ADORecordset_mssql {
+ var $databaseType = "mssql_n";
+ function ADORecordset_mssql_n($id,$mode=false)
+ {
+ $this->ADORecordset_mssql($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-mssqlpo.inc.php b/lib/adodb/drivers/adodb-mssqlpo.inc.php
new file mode 100644
index 0000000..df48286
--- /dev/null
+++ b/lib/adodb/drivers/adodb-mssqlpo.inc.php
@@ -0,0 +1,62 @@
+<?php
+/**
+* @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+* Released under both BSD license and Lesser GPL library license.
+* Whenever there is any discrepancy between the two licenses,
+* the BSD license will take precedence.
+*
+* Set tabs to 4 for best viewing.
+*
+* Latest version is available at http://php.weblogs.com
+*
+* Portable MSSQL Driver that supports || instead of +
+*
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+
+/*
+ The big difference between mssqlpo and it's parent mssql is that mssqlpo supports
+ the more standard || string concatenation operator.
+*/
+
+include_once(ADODB_DIR.'/drivers/adodb-mssql.inc.php');
+
+class ADODB_mssqlpo extends ADODB_mssql {
+ var $databaseType = "mssqlpo";
+ var $concat_operator = '||';
+
+ function ADODB_mssqlpo()
+ {
+ ADODB_mssql::ADODB_mssql();
+ }
+
+ function PrepareSP($sql)
+ {
+ if (!$this->_has_mssql_init) {
+ ADOConnection::outp( "PrepareSP: mssql_init only available since PHP 4.1.0");
+ return $sql;
+ }
+ if (is_string($sql)) $sql = str_replace('||','+',$sql);
+ $stmt = mssql_init($sql,$this->_connectionID);
+ if (!$stmt) return $sql;
+ return array($sql,$stmt);
+ }
+
+ function _query($sql,$inputarr)
+ {
+ if (is_string($sql)) $sql = str_replace('||','+',$sql);
+ return ADODB_mssql::_query($sql,$inputarr);
+ }
+}
+
+class ADORecordset_mssqlpo extends ADORecordset_mssql {
+ var $databaseType = "mssqlpo";
+ function ADORecordset_mssqlpo($id,$mode=false)
+ {
+ $this->ADORecordset_mssql($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-mysql.inc.php b/lib/adodb/drivers/adodb-mysql.inc.php
new file mode 100644
index 0000000..14d288e
--- /dev/null
+++ b/lib/adodb/drivers/adodb-mysql.inc.php
@@ -0,0 +1,782 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+ MySQL code that does not support transactions. Use mysqlt if you need transactions.
+ Requires mysql client. Works on Windows and Unix.
+
+ 28 Feb 2001: MetaColumns bug fix - suggested by Freek Dijkstra (phpeverywhere@macfreek.com)
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (! defined("_ADODB_MYSQL_LAYER")) {
+ define("_ADODB_MYSQL_LAYER", 1 );
+
+class ADODB_mysql extends ADOConnection {
+ var $databaseType = 'mysql';
+ var $dataProvider = 'mysql';
+ var $hasInsertID = true;
+ var $hasAffectedRows = true;
+ var $metaTablesSQL = "SHOW TABLES";
+ var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $hasLimit = true;
+ var $hasMoveFirst = true;
+ var $hasGenID = true;
+ var $isoDates = true; // accepts dates in ISO format
+ var $sysDate = 'CURDATE()';
+ var $sysTimeStamp = 'NOW()';
+ var $hasTransactions = false;
+ var $forceNewConnect = false;
+ var $poorAffectedRows = true;
+ var $clientFlags = 0;
+ var $substr = "substring";
+ var $nameQuote = '`'; /// string to use to quote identifiers and names
+ var $compat323 = false; // true if compat with mysql 3.23
+
+ function ADODB_mysql()
+ {
+ if (defined('ADODB_EXTENSION')) $this->rsPrefix .= 'ext_';
+ }
+
+ function ServerInfo()
+ {
+ $arr['description'] = ADOConnection::GetOne("select version()");
+ $arr['version'] = ADOConnection::_findvers($arr['description']);
+ return $arr;
+ }
+
+ function IfNull( $field, $ifNull )
+ {
+ return " IFNULL($field, $ifNull) "; // if MySQL
+ }
+
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ $save = $this->metaTablesSQL;
+ if ($showSchema && is_string($showSchema)) {
+ $this->metaTablesSQL .= " from $showSchema";
+ }
+
+ if ($mask) {
+ $mask = $this->qstr($mask);
+ $this->metaTablesSQL .= " like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ $this->metaTablesSQL = $save;
+ return $ret;
+ }
+
+
+ function &MetaIndexes ($table, $primary = FALSE, $owner=false)
+ {
+ // save old fetch mode
+ global $ADODB_FETCH_MODE;
+
+ $false = false;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+
+ // get index details
+ $rs = $this->Execute(sprintf('SHOW INDEX FROM %s',$table));
+
+ // restore fetchmode
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ if (!is_object($rs)) {
+ return $false;
+ }
+
+ $indexes = array ();
+
+ // parse index data into array
+ while ($row = $rs->FetchRow()) {
+ if ($primary == FALSE AND $row[2] == 'PRIMARY') {
+ continue;
+ }
+
+ if (!isset($indexes[$row[2]])) {
+ $indexes[$row[2]] = array(
+ 'unique' => ($row[1] == 0),
+ 'columns' => array()
+ );
+ }
+
+ $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
+ }
+
+ // sort columns by order in the index
+ foreach ( array_keys ($indexes) as $index )
+ {
+ ksort ($indexes[$index]['columns']);
+ }
+
+ return $indexes;
+ }
+
+
+ // if magic quotes disabled, use mysql_real_escape_string()
+ function qstr($s,$magic_quotes=false)
+ {
+ if (!$magic_quotes) {
+
+ if (ADODB_PHPVER >= 0x4300) {
+ if (is_resource($this->_connectionID))
+ return "'".mysql_real_escape_string($s,$this->_connectionID)."'";
+ }
+ if ($this->replaceQuote[0] == '\\'){
+ $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+ }
+ return "'".str_replace("'",$this->replaceQuote,$s)."'";
+ }
+
+ // undo magic quotes for "
+ $s = str_replace('\\"','"',$s);
+ return "'$s'";
+ }
+
+ function _insertid()
+ {
+ return ADOConnection::GetOne('SELECT LAST_INSERT_ID()');
+ //return mysql_insert_id($this->_connectionID);
+ }
+
+ function GetOne($sql,$inputarr=false)
+ {
+ if ($this->compat323 == false && strncasecmp($sql,'sele',4) == 0) {
+ $rs =& $this->SelectLimit($sql,1,-1,$inputarr);
+ if ($rs) {
+ $rs->Close();
+ if ($rs->EOF) return false;
+ return reset($rs->fields);
+ }
+ } else {
+ return ADOConnection::GetOne($sql,$inputarr);
+ }
+ return false;
+ }
+
+ function BeginTrans()
+ {
+ if ($this->debug) ADOConnection::outp("Transactions not supported in 'mysql' driver. Use 'mysqlt' or 'mysqli' driver");
+ }
+
+ function _affectedrows()
+ {
+ return mysql_affected_rows($this->_connectionID);
+ }
+
+ // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
+ // Reference on Last_Insert_ID on the recommended way to simulate sequences
+ var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
+ var $_genSeqSQL = "create table %s (id int not null)";
+ var $_genSeq2SQL = "insert into %s values (%s)";
+ var $_dropSeqSQL = "drop table %s";
+
+ function CreateSequence($seqname='adodbseq',$startID=1)
+ {
+ if (empty($this->_genSeqSQL)) return false;
+ $u = strtoupper($seqname);
+
+ $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+ if (!$ok) return false;
+ return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
+ }
+
+
+ function GenID($seqname='adodbseq',$startID=1)
+ {
+ // post-nuke sets hasGenID to false
+ if (!$this->hasGenID) return false;
+
+ $savelog = $this->_logsql;
+ $this->_logsql = false;
+ $getnext = sprintf($this->_genIDSQL,$seqname);
+ $holdtransOK = $this->_transOK; // save the current status
+ $rs = @$this->Execute($getnext);
+ if (!$rs) {
+ if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
+ $u = strtoupper($seqname);
+ $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+ $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
+ $rs = $this->Execute($getnext);
+ }
+ $this->genID = mysql_insert_id($this->_connectionID);
+
+ if ($rs) $rs->Close();
+
+ $this->_logsql = $savelog;
+ return $this->genID;
+ }
+
+ function &MetaDatabases()
+ {
+ $qid = mysql_list_dbs($this->_connectionID);
+ $arr = array();
+ $i = 0;
+ $max = mysql_num_rows($qid);
+ while ($i < $max) {
+ $db = mysql_tablename($qid,$i);
+ if ($db != 'mysql') $arr[] = $db;
+ $i += 1;
+ }
+ return $arr;
+ }
+
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysTimeStamp;
+ $s = 'DATE_FORMAT('.$col.",'";
+ $concat = false;
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ $ch = $fmt[$i];
+ switch($ch) {
+
+ default:
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ /** FALL THROUGH */
+ case '-':
+ case '/':
+ $s .= $ch;
+ break;
+
+ case 'Y':
+ case 'y':
+ $s .= '%Y';
+ break;
+ case 'M':
+ $s .= '%b';
+ break;
+
+ case 'm':
+ $s .= '%m';
+ break;
+ case 'D':
+ case 'd':
+ $s .= '%d';
+ break;
+
+ case 'Q':
+ case 'q':
+ $s .= "'),Quarter($col)";
+
+ if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
+ else $s .= ",('";
+ $concat = true;
+ break;
+
+ case 'H':
+ $s .= '%H';
+ break;
+
+ case 'h':
+ $s .= '%I';
+ break;
+
+ case 'i':
+ $s .= '%i';
+ break;
+
+ case 's':
+ $s .= '%s';
+ break;
+
+ case 'a':
+ case 'A':
+ $s .= '%p';
+ break;
+
+ case 'w':
+ $s .= '%w';
+ break;
+
+ case 'W':
+ $s .= '%U';
+ break;
+
+ case 'l':
+ $s .= '%W';
+ break;
+ }
+ }
+ $s.="')";
+ if ($concat) $s = "CONCAT($s)";
+ return $s;
+ }
+
+
+ // returns concatenated string
+ // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
+ function Concat()
+ {
+ $s = "";
+ $arr = func_get_args();
+
+ // suggestion by andrew005@mnogo.ru
+ $s = implode(',',$arr);
+ if (strlen($s) > 0) return "CONCAT($s)";
+ else return '';
+ }
+
+ function OffsetDate($dayFraction,$date=false)
+ {
+ if (!$date) $date = $this->sysDate;
+
+ $fraction = $dayFraction * 24 * 3600;
+ return $date . ' + INTERVAL ' . $fraction.' SECOND';
+
+// return "from_unixtime(unix_timestamp($date)+$fraction)";
+ }
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!empty($this->port)) $argHostname .= ":".$this->port;
+
+ if (ADODB_PHPVER >= 0x4300)
+ $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword,
+ $this->forceNewConnect,$this->clientFlags);
+ else if (ADODB_PHPVER >= 0x4200)
+ $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword,
+ $this->forceNewConnect);
+ else
+ $this->_connectionID = mysql_connect($argHostname,$argUsername,$argPassword);
+
+ if ($this->_connectionID === false) return false;
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!empty($this->port)) $argHostname .= ":".$this->port;
+
+ if (ADODB_PHPVER >= 0x4300)
+ $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword,$this->clientFlags);
+ else
+ $this->_connectionID = mysql_pconnect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($this->autoRollback) $this->RollbackTrans();
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ $this->forceNewConnect = true;
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
+ }
+
+ function &MetaColumns($table)
+ {
+ $this->_findschema($table,$schema);
+ if ($schema) {
+ $dbName = $this->database;
+ $this->SelectDB($schema);
+ }
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+
+ if ($schema) {
+ $this->SelectDB($dbName);
+ }
+
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ if (!is_object($rs)) {
+ $false = false;
+ return $false;
+ }
+
+ $retarr = array();
+ while (!$rs->EOF){
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $type = $rs->fields[1];
+
+ // split type into type(length):
+ $fld->scale = null;
+ if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
+ $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
+ } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
+ } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $arr = explode(",",$query_array[2]);
+ $fld->enums = $arr;
+ $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
+ $fld->max_length = ($zlen > 0) ? $zlen : 1;
+ } else {
+ $fld->type = $type;
+ $fld->max_length = -1;
+ }
+ $fld->not_null = ($rs->fields[2] != 'YES');
+ $fld->primary_key = ($rs->fields[3] == 'PRI');
+ $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
+ $fld->binary = (strpos($type,'blob') !== false);
+ $fld->unsigned = (strpos($type,'unsigned') !== false);
+
+ if (!$fld->binary) {
+ $d = $rs->fields[4];
+ if ($d != '' && $d != 'NULL') {
+ $fld->has_default = true;
+ $fld->default_value = $d;
+ } else {
+ $fld->has_default = false;
+ }
+ }
+
+ if ($save == ADODB_FETCH_NUM) {
+ $retarr[] = $fld;
+ } else {
+ $retarr[strtoupper($fld->name)] = $fld;
+ }
+ $rs->MoveNext();
+ }
+
+ $rs->Close();
+ return $retarr;
+ }
+
+ // returns true or false
+ function SelectDB($dbName)
+ {
+ $this->database = $dbName;
+ $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
+ if ($this->_connectionID) {
+ return @mysql_select_db($dbName,$this->_connectionID);
+ }
+ else return false;
+ }
+
+ // parameters use PostgreSQL convention, not MySQL
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0)
+ {
+ $offsetStr =($offset>=0) ? ((integer)$offset)."," : '';
+ // jason judge, see http://phplens.com/lens/lensforum/msgs.php?id=9220
+ if ($nrows < 0) $nrows = '18446744073709551615';
+
+ if ($secs)
+ $rs =& $this->CacheExecute($secs,$sql." LIMIT $offsetStr".((integer)$nrows),$inputarr);
+ else
+ $rs =& $this->Execute($sql." LIMIT $offsetStr".((integer)$nrows),$inputarr);
+ return $rs;
+ }
+
+ // returns queryID or false
+ function _query($sql,$inputarr)
+ {
+ //global $ADODB_COUNTRECS;
+ //if($ADODB_COUNTRECS)
+ return mysql_query($sql,$this->_connectionID);
+ //else return @mysql_unbuffered_query($sql,$this->_connectionID); // requires PHP >= 4.0.6
+ }
+
+ /* Returns: the last error message from previous database operation */
+ function ErrorMsg()
+ {
+
+ if ($this->_logsql) return $this->_errorMsg;
+ if (empty($this->_connectionID)) $this->_errorMsg = @mysql_error();
+ else $this->_errorMsg = @mysql_error($this->_connectionID);
+ return $this->_errorMsg;
+ }
+
+ /* Returns: the last error number from previous database operation */
+ function ErrorNo()
+ {
+ if ($this->_logsql) return $this->_errorCode;
+ if (empty($this->_connectionID)) return @mysql_errno();
+ else return @mysql_errno($this->_connectionID);
+ }
+
+ // returns true or false
+ function _close()
+ {
+ @mysql_close($this->_connectionID);
+ $this->_connectionID = false;
+ }
+
+
+ /*
+ * Maximum size of C field
+ */
+ function CharMax()
+ {
+ return 255;
+ }
+
+ /*
+ * Maximum size of X field
+ */
+ function TextMax()
+ {
+ return 4294967295;
+ }
+
+ // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
+ function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
+ {
+ global $ADODB_FETCH_MODE;
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
+
+ if ( !empty($owner) ) {
+ $table = "$owner.$table";
+ }
+ $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
+ if ($associative) $create_sql = $a_create_table["Create Table"];
+ else $create_sql = $a_create_table[1];
+
+ $matches = array();
+
+ if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
+ $foreign_keys = array();
+ $num_keys = count($matches[0]);
+ for ( $i = 0; $i < $num_keys; $i ++ ) {
+ $my_field = explode('`, `', $matches[1][$i]);
+ $ref_table = $matches[2][$i];
+ $ref_field = explode('`, `', $matches[3][$i]);
+
+ if ( $upper ) {
+ $ref_table = strtoupper($ref_table);
+ }
+
+ $foreign_keys[$ref_table] = array();
+ $num_fields = count($my_field);
+ for ( $j = 0; $j < $num_fields; $j ++ ) {
+ if ( $associative ) {
+ $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
+ } else {
+ $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
+ }
+ }
+ }
+
+ return $foreign_keys;
+ }
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+
+class ADORecordSet_mysql extends ADORecordSet{
+
+ var $databaseType = "mysql";
+ var $canSeek = true;
+
+ function ADORecordSet_mysql($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode)
+ {
+ case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
+ case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = MYSQL_BOTH; break;
+ }
+ $this->adodbFetchMode = $mode;
+ $this->ADORecordSet($queryID);
+ }
+
+ function _initrs()
+ {
+ //GLOBAL $ADODB_COUNTRECS;
+ // $this->_numOfRows = ($ADODB_COUNTRECS) ? @mysql_num_rows($this->_queryID):-1;
+ $this->_numOfRows = @mysql_num_rows($this->_queryID);
+ $this->_numOfFields = @mysql_num_fields($this->_queryID);
+ }
+
+ function &FetchField($fieldOffset = -1)
+ {
+ if ($fieldOffset != -1) {
+ $o = @mysql_fetch_field($this->_queryID, $fieldOffset);
+ $f = @mysql_field_flags($this->_queryID,$fieldOffset);
+ $o->max_length = @mysql_field_len($this->_queryID,$fieldOffset); // suggested by: Jim Nicholson (jnich#att.com)
+ //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
+ $o->binary = (strpos($f,'binary')!== false);
+ }
+ else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */
+ $o = @mysql_fetch_field($this->_queryID);
+ $o->max_length = @mysql_field_len($this->_queryID); // suggested by: Jim Nicholson (jnich#att.com)
+ //$o->max_length = -1; // mysql returns the max length less spaces -- so it is unrealiable
+ }
+
+ return $o;
+ }
+
+ function &GetRowAssoc($upper=true)
+ {
+ if ($this->fetchMode == MYSQL_ASSOC && !$upper) $row = $this->fields;
+ else $row =& ADORecordSet::GetRowAssoc($upper);
+ return $row;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ // added @ by "Michael William Miller" <mille562@pilot.msu.edu>
+ if ($this->fetchMode != MYSQL_NUM) 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)]];
+ }
+
+ function _seek($row)
+ {
+ if ($this->_numOfRows == 0) return false;
+ return @mysql_data_seek($this->_queryID,$row);
+ }
+
+ function MoveNext()
+ {
+ //return adodb_movenext($this);
+ //if (defined('ADODB_EXTENSION')) return adodb_movenext($this);
+ if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) {
+ $this->_currentRow += 1;
+ return true;
+ }
+ if (!$this->EOF) {
+ $this->_currentRow += 1;
+ $this->EOF = true;
+ }
+ return false;
+ }
+
+ function _fetch()
+ {
+ $this->fields = @mysql_fetch_array($this->_queryID,$this->fetchMode);
+ return is_array($this->fields);
+ }
+
+ function _close() {
+ @mysql_free_result($this->_queryID);
+ $this->_queryID = false;
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+ $len = -1; // mysql max_length is not accurate
+ switch (strtoupper($t)) {
+ case 'STRING':
+ case 'CHAR':
+ case 'VARCHAR':
+ case 'TINYBLOB':
+ case 'TINYTEXT':
+ case 'ENUM':
+ case 'SET':
+ if ($len <= $this->blobSize) return 'C';
+
+ case 'TEXT':
+ case 'LONGTEXT':
+ case 'MEDIUMTEXT':
+ return 'X';
+
+ // php_mysql extension always returns 'blob' even if 'text'
+ // so we have to check whether binary...
+ case 'IMAGE':
+ case 'LONGBLOB':
+ case 'BLOB':
+ case 'MEDIUMBLOB':
+ return !empty($fieldobj->binary) ? 'B' : 'X';
+
+ case 'YEAR':
+ case 'DATE': return 'D';
+
+ case 'TIME':
+ case 'DATETIME':
+ case 'TIMESTAMP': return 'T';
+
+ case 'INT':
+ case 'INTEGER':
+ case 'BIGINT':
+ case 'TINYINT':
+ case 'MEDIUMINT':
+ case 'SMALLINT':
+
+ if (!empty($fieldobj->primary_key)) return 'R';
+ else return 'I';
+
+ default: return 'N';
+ }
+ }
+
+}
+
+class ADORecordSet_ext_mysql extends ADORecordSet_mysql {
+ function ADORecordSet_ext_mysql($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode)
+ {
+ case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
+ case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = MYSQL_BOTH; break;
+ }
+ $this->adodbFetchMode = $mode;
+ $this->ADORecordSet($queryID);
+ }
+
+ function MoveNext()
+ {
+ return @adodb_movenext($this);
+ }
+}
+
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-mysqli.inc.php b/lib/adodb/drivers/adodb-mysqli.inc.php
new file mode 100644
index 0000000..00b53cc
--- /dev/null
+++ b/lib/adodb/drivers/adodb-mysqli.inc.php
@@ -0,0 +1,1020 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+ MySQL code that does not support transactions. Use mysqlt if you need transactions.
+ Requires mysql client. Works on Windows and Unix.
+
+21 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl)
+Based on adodb 3.40
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (! defined("_ADODB_MYSQLI_LAYER")) {
+ define("_ADODB_MYSQLI_LAYER", 1 );
+
+ // PHP5 compat...
+ if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128);
+ if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1);
+
+ // disable adodb extension - currently incompatible.
+ global $ADODB_EXTENSION; $ADODB_EXTENSION = false;
+
+class ADODB_mysqli extends ADOConnection {
+ var $databaseType = 'mysqli';
+ var $dataProvider = 'native';
+ var $hasInsertID = true;
+ var $hasAffectedRows = true;
+ var $metaTablesSQL = "SHOW TABLES";
+ var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $hasLimit = true;
+ var $hasMoveFirst = true;
+ var $hasGenID = true;
+ var $isoDates = true; // accepts dates in ISO format
+ var $sysDate = 'CURDATE()';
+ var $sysTimeStamp = 'NOW()';
+ var $hasTransactions = true;
+ var $forceNewConnect = false;
+ var $poorAffectedRows = true;
+ var $clientFlags = 0;
+ var $substr = "substring";
+ var $port = false;
+ var $socket = false;
+ var $_bindInputArray = false;
+ var $nameQuote = '`'; /// string to use to quote identifiers and names
+ var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0));
+
+ function ADODB_mysqli()
+ {
+ // if(!extension_loaded("mysqli"))
+ ;//trigger_error("You must have the mysqli extension installed.", E_USER_ERROR);
+
+ }
+
+ function SetTransactionMode( $transaction_mode )
+ {
+ $this->_transmode = $transaction_mode;
+ if (empty($transaction_mode)) {
+ $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
+ return;
+ }
+ if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+ $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
+ }
+
+ // returns true or false
+ // To add: parameter int $port,
+ // parameter string $socket
+ function _connect($argHostname = NULL,
+ $argUsername = NULL,
+ $argPassword = NULL,
+ $argDatabasename = NULL, $persist=false)
+ {
+ if(!extension_loaded("mysqli")) {
+ return null;
+ }
+ $this->_connectionID = @mysqli_init();
+
+ if (is_null($this->_connectionID)) {
+ // mysqli_init only fails if insufficient memory
+ if ($this->debug)
+ ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg());
+ return false;
+ }
+ /*
+ I suggest a simple fix which would enable adodb and mysqli driver to
+ read connection options from the standard mysql configuration file
+ /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com>
+ */
+ foreach($this->optionFlags as $arr) {
+ mysqli_options($this->_connectionID,$arr[0],$arr[1]);
+ }
+
+ #if (!empty($this->port)) $argHostname .= ":".$this->port;
+ $ok = mysqli_real_connect($this->_connectionID,
+ $argHostname,
+ $argUsername,
+ $argPassword,
+ $argDatabasename,
+ $this->port,
+ $this->socket,
+ $this->clientFlags);
+
+ if ($ok) {
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ } else {
+ if ($this->debug)
+ ADOConnection::outp("Could't connect : " . $this->ErrorMsg());
+ return false;
+ }
+ }
+
+ // returns true or false
+ // How to force a persistent connection
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
+
+ }
+
+ // When is this used? Close old connection first?
+ // In _connect(), check $this->forceNewConnect?
+ function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ $this->forceNewConnect = true;
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
+ }
+
+ function IfNull( $field, $ifNull )
+ {
+ return " IFNULL($field, $ifNull) "; // if MySQL
+ }
+
+ // do not use $ADODB_COUNTRECS
+ function GetOne($sql,$inputarr=false)
+ {
+ $ret = false;
+ $rs = &$this->Execute($sql,$inputarr);
+ if ($rs) {
+ if (!$rs->EOF) $ret = reset($rs->fields);
+ $rs->Close();
+ }
+ return $ret;
+ }
+
+ function ServerInfo()
+ {
+ $arr['description'] = $this->GetOne("select version()");
+ $arr['version'] = ADOConnection::_findvers($arr['description']);
+ return $arr;
+ }
+
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+
+ //$this->Execute('SET AUTOCOMMIT=0');
+ mysqli_autocommit($this->_connectionID, false);
+ $this->Execute('BEGIN');
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->Execute('COMMIT');
+
+ //$this->Execute('SET AUTOCOMMIT=1');
+ mysqli_autocommit($this->_connectionID, true);
+ return true;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->Execute('ROLLBACK');
+ //$this->Execute('SET AUTOCOMMIT=1');
+ mysqli_autocommit($this->_connectionID, true);
+ return true;
+ }
+
+ function RowLock($tables,$where='',$flds='1 as adodb_ignore')
+ {
+ if ($this->transCnt==0) $this->BeginTrans();
+ if ($where) $where = ' where '.$where;
+ $rs =& $this->Execute("select $flds from $tables $where for update");
+ return !empty($rs);
+ }
+
+ // if magic quotes disabled, use mysql_real_escape_string()
+ // From readme.htm:
+ // Quotes a string to be sent to the database. The $magic_quotes_enabled
+ // parameter may look funny, but the idea is if you are quoting a
+ // string extracted from a POST/GET variable, then
+ // pass get_magic_quotes_gpc() as the second parameter. This will
+ // ensure that the variable is not quoted twice, once by qstr and once
+ // by the magic_quotes_gpc.
+ //
+ //Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc());
+ function qstr($s, $magic_quotes = false)
+ {
+ if (!$magic_quotes) {
+ if (PHP_VERSION >= 5)
+ return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'";
+
+ if ($this->replaceQuote[0] == '\\')
+ $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s);
+ return "'".str_replace("'",$this->replaceQuote,$s)."'";
+ }
+ // undo magic quotes for "
+ $s = str_replace('\\"','"',$s);
+ return "'$s'";
+ }
+
+ function _insertid()
+ {
+ $result = @mysqli_insert_id($this->_connectionID);
+ if ($result == -1){
+ if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg());
+ }
+ return $result;
+ }
+
+ // Only works for INSERT, UPDATE and DELETE query's
+ function _affectedrows()
+ {
+ $result = @mysqli_affected_rows($this->_connectionID);
+ if ($result == -1) {
+ if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg());
+ }
+ return $result;
+ }
+
+ // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html
+ // Reference on Last_Insert_ID on the recommended way to simulate sequences
+ var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
+ var $_genSeqSQL = "create table %s (id int not null)";
+ var $_genSeq2SQL = "insert into %s values (%s)";
+ var $_dropSeqSQL = "drop table %s";
+
+ function CreateSequence($seqname='adodbseq',$startID=1)
+ {
+ if (empty($this->_genSeqSQL)) return false;
+ $u = strtoupper($seqname);
+
+ $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+ if (!$ok) return false;
+ return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
+ }
+
+ function GenID($seqname='adodbseq',$startID=1)
+ {
+ // post-nuke sets hasGenID to false
+ if (!$this->hasGenID) return false;
+
+ $getnext = sprintf($this->_genIDSQL,$seqname);
+ $holdtransOK = $this->_transOK; // save the current status
+ $rs = @$this->Execute($getnext);
+ if (!$rs) {
+ if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset
+ $u = strtoupper($seqname);
+ $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+ $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1));
+ $rs = $this->Execute($getnext);
+ }
+ $this->genID = mysqli_insert_id($this->_connectionID);
+
+ if ($rs) $rs->Close();
+
+ return $this->genID;
+ }
+
+ function &MetaDatabases()
+ {
+ $query = "SHOW DATABASES";
+ $ret =& $this->Execute($query);
+ if ($ret && is_object($ret)){
+ $arr = array();
+ while (!$ret->EOF){
+ $db = $ret->Fields('Database');
+ if ($db != 'mysql') $arr[] = $db;
+ $ret->MoveNext();
+ }
+ return $arr;
+ }
+ return $ret;
+ }
+
+
+ function &MetaIndexes ($table, $primary = FALSE)
+ {
+ // save old fetch mode
+ global $ADODB_FETCH_MODE;
+
+ $false = false;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+
+ // get index details
+ $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table));
+
+ // restore fetchmode
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ if (!is_object($rs)) {
+ return $false;
+ }
+
+ $indexes = array ();
+
+ // parse index data into array
+ while ($row = $rs->FetchRow()) {
+ if ($primary == FALSE AND $row[2] == 'PRIMARY') {
+ continue;
+ }
+
+ if (!isset($indexes[$row[2]])) {
+ $indexes[$row[2]] = array(
+ 'unique' => ($row[1] == 0),
+ 'columns' => array()
+ );
+ }
+
+ $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
+ }
+
+ // sort columns by order in the index
+ foreach ( array_keys ($indexes) as $index )
+ {
+ ksort ($indexes[$index]['columns']);
+ }
+
+ return $indexes;
+ }
+
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysTimeStamp;
+ $s = 'DATE_FORMAT('.$col.",'";
+ $concat = false;
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= '%Y';
+ break;
+ case 'Q':
+ case 'q':
+ $s .= "'),Quarter($col)";
+
+ if ($len > $i+1) $s .= ",DATE_FORMAT($col,'";
+ else $s .= ",('";
+ $concat = true;
+ break;
+ case 'M':
+ $s .= '%b';
+ break;
+
+ case 'm':
+ $s .= '%m';
+ break;
+ case 'D':
+ case 'd':
+ $s .= '%d';
+ break;
+
+ case 'H':
+ $s .= '%H';
+ break;
+
+ case 'h':
+ $s .= '%I';
+ break;
+
+ case 'i':
+ $s .= '%i';
+ break;
+
+ case 's':
+ $s .= '%s';
+ break;
+
+ case 'a':
+ case 'A':
+ $s .= '%p';
+ break;
+
+ case 'w':
+ $s .= '%w';
+ break;
+
+ case 'l':
+ $s .= '%W';
+ break;
+
+ default:
+
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ $s .= $ch;
+ break;
+ }
+ }
+ $s.="')";
+ if ($concat) $s = "CONCAT($s)";
+ return $s;
+ }
+
+ // returns concatenated string
+ // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator
+ function Concat()
+ {
+ $s = "";
+ $arr = func_get_args();
+
+ // suggestion by andrew005@mnogo.ru
+ $s = implode(',',$arr);
+ if (strlen($s) > 0) return "CONCAT($s)";
+ else return '';
+ }
+
+ // dayFraction is a day in floating point
+ function OffsetDate($dayFraction,$date=false)
+ {
+ if (!$date) $date = $this->sysDate;
+
+ $fraction = $dayFraction * 24 * 3600;
+ return $date . ' + INTERVAL ' . $fraction.' SECOND';
+
+// return "from_unixtime(unix_timestamp($date)+$fraction)";
+ }
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ $save = $this->metaTablesSQL;
+ if ($showSchema && is_string($showSchema)) {
+ $this->metaTablesSQL .= " from $showSchema";
+ }
+
+ if ($mask) {
+ $mask = $this->qstr($mask);
+ $this->metaTablesSQL .= " like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ $this->metaTablesSQL = $save;
+ return $ret;
+ }
+
+ // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx>
+ function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE )
+ {
+ global $ADODB_FETCH_MODE;
+
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true;
+
+ if ( !empty($owner) ) {
+ $table = "$owner.$table";
+ }
+ $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
+ if ($associative) $create_sql = $a_create_table["Create Table"];
+ else $create_sql = $a_create_table[1];
+
+ $matches = array();
+
+ if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false;
+ $foreign_keys = array();
+ $num_keys = count($matches[0]);
+ for ( $i = 0; $i < $num_keys; $i ++ ) {
+ $my_field = explode('`, `', $matches[1][$i]);
+ $ref_table = $matches[2][$i];
+ $ref_field = explode('`, `', $matches[3][$i]);
+
+ if ( $upper ) {
+ $ref_table = strtoupper($ref_table);
+ }
+
+ $foreign_keys[$ref_table] = array();
+ $num_fields = count($my_field);
+ for ( $j = 0; $j < $num_fields; $j ++ ) {
+ if ( $associative ) {
+ $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
+ } else {
+ $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
+ }
+ }
+ }
+
+ return $foreign_keys;
+ }
+
+ function &MetaColumns($table)
+ {
+ $false = false;
+ if (!$this->metaColumnsSQL)
+ return $false;
+
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false)
+ $savem = $this->SetFetchMode(false);
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ if (!is_object($rs))
+ return $false;
+
+ $retarr = array();
+ while (!$rs->EOF) {
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $type = $rs->fields[1];
+
+ // split type into type(length):
+ $fld->scale = null;
+ if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
+ $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
+ } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
+ } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = max(array_map("strlen",explode(",",$query_array[2]))) - 2; // PHP >= 4.0.6
+ $fld->max_length = ($fld->max_length == 0 ? 1 : $fld->max_length);
+ } else {
+ $fld->type = $type;
+ $fld->max_length = -1;
+ }
+ $fld->not_null = ($rs->fields[2] != 'YES');
+ $fld->primary_key = ($rs->fields[3] == 'PRI');
+ $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
+ $fld->binary = (strpos($type,'blob') !== false);
+ $fld->unsigned = (strpos($type,'unsigned') !== false);
+
+ if (!$fld->binary) {
+ $d = $rs->fields[4];
+ if ($d != '' && $d != 'NULL') {
+ $fld->has_default = true;
+ $fld->default_value = $d;
+ } else {
+ $fld->has_default = false;
+ }
+ }
+
+ if ($save == ADODB_FETCH_NUM) {
+ $retarr[] = $fld;
+ } else {
+ $retarr[strtoupper($fld->name)] = $fld;
+ }
+ $rs->MoveNext();
+ }
+
+ $rs->Close();
+ return $retarr;
+ }
+
+ // returns true or false
+ function SelectDB($dbName)
+ {
+// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID);
+ $this->database = $dbName;
+ $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
+
+ if ($this->_connectionID) {
+ $result = @mysqli_select_db($this->_connectionID, $dbName);
+ if (!$result) {
+ ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg());
+ }
+ return $result;
+ }
+ return false;
+ }
+
+ // parameters use PostgreSQL convention, not MySQL
+ function &SelectLimit($sql,
+ $nrows = -1,
+ $offset = -1,
+ $inputarr = false,
+ $arg3 = false,
+ $secs = 0)
+ {
+ $offsetStr = ($offset >= 0) ? "$offset," : '';
+ if ($nrows < 0) $nrows = '18446744073709551615';
+
+ if ($secs)
+ $rs =& $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr , $arg3);
+ else
+ $rs =& $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr , $arg3);
+
+ return $rs;
+ }
+
+
+ function Prepare($sql)
+ {
+ return $sql;
+
+ $stmt = $this->_connectionID->prepare($sql);
+ if (!$stmt) {
+ echo $this->ErrorMsg();
+ return $sql;
+ }
+ return array($sql,$stmt);
+ }
+
+
+ // returns queryID or false
+ function _query($sql, $inputarr)
+ {
+ global $ADODB_COUNTRECS;
+
+ if (is_array($sql)) {
+ $stmt = $sql[1];
+ $a = '';
+ foreach($inputarr as $k => $v) {
+ if (is_string($v)) $a .= 's';
+ else if (is_integer($v)) $a .= 'i';
+ else $a .= 'd';
+ }
+
+ $fnarr = array_merge( array($stmt,$a) , $inputarr);
+ $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr);
+
+ $ret = mysqli_stmt_execute($stmt);
+ return $ret;
+ }
+ if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) {
+ if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());
+ return false;
+ }
+
+ return $mysql_res;
+ }
+
+ /* Returns: the last error message from previous database operation */
+ function ErrorMsg()
+ {
+ if (empty($this->_connectionID))
+ $this->_errorMsg = @mysqli_connect_error();
+ else
+ $this->_errorMsg = @mysqli_error($this->_connectionID);
+ return $this->_errorMsg;
+ }
+
+ /* Returns: the last error number from previous database operation */
+ function ErrorNo()
+ {
+ if (empty($this->_connectionID))
+ return @mysqli_connect_errno();
+ else
+ return @mysqli_errno($this->_connectionID);
+ }
+
+ // returns true or false
+ function _close()
+ {
+ @mysqli_close($this->_connectionID);
+ $this->_connectionID = false;
+ }
+
+ /*
+ * Maximum size of C field
+ */
+ function CharMax()
+ {
+ return 255;
+ }
+
+ /*
+ * Maximum size of X field
+ */
+ function TextMax()
+ {
+ return 4294967295;
+ }
+
+
+
+ // this is a set of functions for managing client encoding - very important if the encodings
+ // of your database and your output target (i.e. HTML) don't match
+ // for instance, you may have UTF8 database and server it on-site as latin1 etc.
+ // GetCharSet - get the name of the character set the client is using now
+ // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported
+ // depends on compile flags of mysql distribution
+
+ function GetCharSet()
+ {
+ //we will use ADO's builtin property charSet
+ if (!method_exists($this->_connectionID,'character_set_name'))
+ return false;
+
+ $this->charSet = @$this->_connectionID->character_set_name();
+ if (!$this->charSet) {
+ return false;
+ } else {
+ return $this->charSet;
+ }
+ }
+
+ // SetCharSet - switch the client encoding
+ function SetCharSet($charset_name)
+ {
+ if (!method_exists($this->_connectionID,'set_charset'))
+ return false;
+
+ if ($this->charSet !== $charset_name) {
+ $if = @$this->_connectionID->set_charset($charset_name);
+ if ($if == "0" & $this->GetCharSet() == $charset_name) {
+ return true;
+ } else return false;
+ } else return true;
+ }
+
+
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_mysqli extends ADORecordSet{
+
+ var $databaseType = "mysqli";
+ var $canSeek = true;
+
+ function ADORecordSet_mysqli($queryID, $mode = false)
+ {
+ if ($mode === false)
+ {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+
+ switch ($mode)
+ {
+ case ADODB_FETCH_NUM:
+ $this->fetchMode = MYSQLI_NUM;
+ break;
+ case ADODB_FETCH_ASSOC:
+ $this->fetchMode = MYSQLI_ASSOC;
+ break;
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = MYSQLI_BOTH;
+ break;
+ }
+ $this->adodbFetchMode = $mode;
+ $this->ADORecordSet($queryID);
+ }
+
+ function _initrs()
+ {
+ global $ADODB_COUNTRECS;
+
+ $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1;
+ $this->_numOfFields = @mysqli_num_fields($this->_queryID);
+ }
+
+/*
+1 = MYSQLI_NOT_NULL_FLAG
+2 = MYSQLI_PRI_KEY_FLAG
+4 = MYSQLI_UNIQUE_KEY_FLAG
+8 = MYSQLI_MULTIPLE_KEY_FLAG
+16 = MYSQLI_BLOB_FLAG
+32 = MYSQLI_UNSIGNED_FLAG
+64 = MYSQLI_ZEROFILL_FLAG
+128 = MYSQLI_BINARY_FLAG
+256 = MYSQLI_ENUM_FLAG
+512 = MYSQLI_AUTO_INCREMENT_FLAG
+1024 = MYSQLI_TIMESTAMP_FLAG
+2048 = MYSQLI_SET_FLAG
+32768 = MYSQLI_NUM_FLAG
+16384 = MYSQLI_PART_KEY_FLAG
+32768 = MYSQLI_GROUP_FLAG
+65536 = MYSQLI_UNIQUE_FLAG
+131072 = MYSQLI_BINCMP_FLAG
+*/
+
+ function &FetchField($fieldOffset = -1)
+ {
+ $fieldnr = $fieldOffset;
+ if ($fieldOffset != -1) {
+ $fieldOffset = mysqli_field_seek($this->_queryID, $fieldnr);
+ }
+ $o = mysqli_fetch_field($this->_queryID);
+ /* Properties of an ADOFieldObject as set by MetaColumns */
+ $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG;
+ $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG;
+ $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG;
+ $o->binary = $o->flags & MYSQLI_BINARY_FLAG;
+ // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */
+ $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG;
+
+ return $o;
+ }
+
+ function &GetRowAssoc($upper = true)
+ {
+ if ($this->fetchMode == MYSQLI_ASSOC && !$upper)
+ return $this->fields;
+ $row =& ADORecordSet::GetRowAssoc($upper);
+ return $row;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode != MYSQLI_NUM)
+ 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)]];
+ }
+
+ function _seek($row)
+ {
+ if ($this->_numOfRows == 0)
+ return false;
+
+ if ($row < 0)
+ return false;
+
+ mysqli_data_seek($this->_queryID, $row);
+ $this->EOF = false;
+ return true;
+ }
+
+ // 10% speedup to move MoveNext to child class
+ // This is the only implementation that works now (23-10-2003).
+ // Other functions return no or the wrong results.
+ function MoveNext()
+ {
+ if ($this->EOF) return false;
+ $this->_currentRow++;
+ $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode);
+
+ if (is_array($this->fields)) return true;
+ $this->EOF = true;
+ return false;
+ }
+
+ function _fetch()
+ {
+ $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode);
+ return is_array($this->fields);
+ }
+
+ function _close()
+ {
+ mysqli_free_result($this->_queryID);
+ $this->_queryID = false;
+ }
+
+/*
+
+0 = MYSQLI_TYPE_DECIMAL
+1 = MYSQLI_TYPE_CHAR
+1 = MYSQLI_TYPE_TINY
+2 = MYSQLI_TYPE_SHORT
+3 = MYSQLI_TYPE_LONG
+4 = MYSQLI_TYPE_FLOAT
+5 = MYSQLI_TYPE_DOUBLE
+6 = MYSQLI_TYPE_NULL
+7 = MYSQLI_TYPE_TIMESTAMP
+8 = MYSQLI_TYPE_LONGLONG
+9 = MYSQLI_TYPE_INT24
+10 = MYSQLI_TYPE_DATE
+11 = MYSQLI_TYPE_TIME
+12 = MYSQLI_TYPE_DATETIME
+13 = MYSQLI_TYPE_YEAR
+14 = MYSQLI_TYPE_NEWDATE
+247 = MYSQLI_TYPE_ENUM
+248 = MYSQLI_TYPE_SET
+249 = MYSQLI_TYPE_TINY_BLOB
+250 = MYSQLI_TYPE_MEDIUM_BLOB
+251 = MYSQLI_TYPE_LONG_BLOB
+252 = MYSQLI_TYPE_BLOB
+253 = MYSQLI_TYPE_VAR_STRING
+254 = MYSQLI_TYPE_STRING
+255 = MYSQLI_TYPE_GEOMETRY
+*/
+
+ function MetaType($t, $len = -1, $fieldobj = false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+
+ $len = -1; // mysql max_length is not accurate
+ switch (strtoupper($t)) {
+ case 'STRING':
+ case 'CHAR':
+ case 'VARCHAR':
+ case 'TINYBLOB':
+ case 'TINYTEXT':
+ case 'ENUM':
+ case 'SET':
+
+ case MYSQLI_TYPE_TINY_BLOB :
+ case MYSQLI_TYPE_CHAR :
+ case MYSQLI_TYPE_STRING :
+ case MYSQLI_TYPE_ENUM :
+ case MYSQLI_TYPE_SET :
+ case 253 :
+ if ($len <= $this->blobSize) return 'C';
+
+ case 'TEXT':
+ case 'LONGTEXT':
+ case 'MEDIUMTEXT':
+ return 'X';
+
+
+ // php_mysql extension always returns 'blob' even if 'text'
+ // so we have to check whether binary...
+ case 'IMAGE':
+ case 'LONGBLOB':
+ case 'BLOB':
+ case 'MEDIUMBLOB':
+
+ case MYSQLI_TYPE_BLOB :
+ case MYSQLI_TYPE_LONG_BLOB :
+ case MYSQLI_TYPE_MEDIUM_BLOB :
+
+ return !empty($fieldobj->binary) ? 'B' : 'X';
+ case 'YEAR':
+ case 'DATE':
+ case MYSQLI_TYPE_DATE :
+ case MYSQLI_TYPE_YEAR :
+
+ return 'D';
+
+ case 'TIME':
+ case 'DATETIME':
+ case 'TIMESTAMP':
+
+ case MYSQLI_TYPE_DATETIME :
+ case MYSQLI_TYPE_NEWDATE :
+ case MYSQLI_TYPE_TIME :
+ case MYSQLI_TYPE_TIMESTAMP :
+
+ return 'T';
+
+ case 'INT':
+ case 'INTEGER':
+ case 'BIGINT':
+ case 'TINYINT':
+ case 'MEDIUMINT':
+ case 'SMALLINT':
+
+ case MYSQLI_TYPE_INT24 :
+ case MYSQLI_TYPE_LONG :
+ case MYSQLI_TYPE_LONGLONG :
+ case MYSQLI_TYPE_SHORT :
+ case MYSQLI_TYPE_TINY :
+
+ if (!empty($fieldobj->primary_key)) return 'R';
+
+ return 'I';
+
+
+ // Added floating-point types
+ // Maybe not necessery.
+ case 'FLOAT':
+ case 'DOUBLE':
+ // case 'DOUBLE PRECISION':
+ case 'DECIMAL':
+ case 'DEC':
+ case 'FIXED':
+ default:
+ //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>";
+ return 'N';
+ }
+ } // function
+
+
+} // rs class
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-mysqlt.inc.php b/lib/adodb/drivers/adodb-mysqlt.inc.php
new file mode 100644
index 0000000..9f1b53a
--- /dev/null
+++ b/lib/adodb/drivers/adodb-mysqlt.inc.php
@@ -0,0 +1,155 @@
+<?php
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+ MySQL code that supports transactions. For MySQL 3.23 or later.
+ Code from James Poon <jpoon88@yahoo.com>
+
+ Requires mysql client. Works on Windows and Unix.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR."/drivers/adodb-mysql.inc.php");
+
+
+class ADODB_mysqlt extends ADODB_mysql {
+ var $databaseType = 'mysqlt';
+ var $ansiOuter = true; // for Version 3.23.17 or later
+ var $hasTransactions = true;
+ var $autoRollback = true; // apparently mysql does not autorollback properly
+
+ function ADODB_mysqlt()
+ {
+ global $ADODB_EXTENSION; if ($ADODB_EXTENSION) $this->rsPrefix .= 'ext_';
+ }
+
+ /* set transaction mode
+
+ SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
+{ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
+
+ */
+ function SetTransactionMode( $transaction_mode )
+ {
+ $this->_transmode = $transaction_mode;
+ if (empty($transaction_mode)) {
+ $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
+ return;
+ }
+ if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+ $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
+ }
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->Execute('SET AUTOCOMMIT=0');
+ $this->Execute('BEGIN');
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->Execute('COMMIT');
+ $this->Execute('SET AUTOCOMMIT=1');
+ return true;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->Execute('ROLLBACK');
+ $this->Execute('SET AUTOCOMMIT=1');
+ return true;
+ }
+
+ function RowLock($tables,$where='',$flds='1 as adodb_ignore')
+ {
+ if ($this->transCnt==0) $this->BeginTrans();
+ if ($where) $where = ' where '.$where;
+ $rs =& $this->Execute("select $flds from $tables $where for update");
+ return !empty($rs);
+ }
+
+}
+
+class ADORecordSet_mysqlt extends ADORecordSet_mysql{
+ var $databaseType = "mysqlt";
+
+ function ADORecordSet_mysqlt($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+
+ switch ($mode)
+ {
+ case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
+ case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
+
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default: $this->fetchMode = MYSQL_BOTH; break;
+ }
+
+ $this->adodbFetchMode = $mode;
+ $this->ADORecordSet($queryID);
+ }
+
+ function MoveNext()
+ {
+ if (@$this->fields = mysql_fetch_array($this->_queryID,$this->fetchMode)) {
+ $this->_currentRow += 1;
+ return true;
+ }
+ if (!$this->EOF) {
+ $this->_currentRow += 1;
+ $this->EOF = true;
+ }
+ return false;
+ }
+}
+
+class ADORecordSet_ext_mysqlt extends ADORecordSet_mysqlt {
+
+ function ADORecordSet_ext_mysqlt($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode)
+ {
+ case ADODB_FETCH_NUM: $this->fetchMode = MYSQL_NUM; break;
+ case ADODB_FETCH_ASSOC:$this->fetchMode = MYSQL_ASSOC; break;
+
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default:
+ $this->fetchMode = MYSQL_BOTH; break;
+ }
+ $this->adodbFetchMode = $mode;
+ $this->ADORecordSet($queryID);
+ }
+
+ function MoveNext()
+ {
+ return adodb_movenext($this);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-netezza.inc.php b/lib/adodb/drivers/adodb-netezza.inc.php
new file mode 100644
index 0000000..eedf51d
--- /dev/null
+++ b/lib/adodb/drivers/adodb-netezza.inc.php
@@ -0,0 +1,170 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+
+ First cut at the Netezza Driver by Josh Eldridge joshuae74#hotmail.com
+ Based on the previous postgres drivers.
+ http://www.netezza.com/
+ Major Additions/Changes:
+ MetaDatabasesSQL, MetaTablesSQL, MetaColumnsSQL
+ Note: You have to have admin privileges to access the system tables
+ Removed non-working keys code (Netezza has no concept of keys)
+ Fixed the way data types and lengths are returned in MetaColumns()
+ as well as added the default lengths for certain types
+ Updated public variables for Netezza
+ Still need to remove blob functions, as Netezza doesn't suppport blob
+*/
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR.'/drivers/adodb-postgres64.inc.php');
+
+class ADODB_netezza extends ADODB_postgres64 {
+ var $databaseType = 'netezza';
+ var $dataProvider = 'netezza';
+ var $hasInsertID = false;
+ var $_resultid = false;
+ var $concat_operator='||';
+ var $random = 'random';
+ var $metaDatabasesSQL = "select objname from _v_object_data where objtype='database' order by 1";
+ var $metaTablesSQL = "select objname from _v_object_data where objtype='table' order by 1";
+ var $isoDates = true; // accepts dates in ISO format
+ var $sysDate = "CURRENT_DATE";
+ var $sysTimeStamp = "CURRENT_TIMESTAMP";
+ var $blobEncodeType = 'C';
+ var $metaColumnsSQL = "SELECT attname, atttype FROM _v_relation_column_def WHERE name = '%s' AND attnum > 0 ORDER BY attnum";
+ var $metaColumnsSQL1 = "SELECT attname, atttype FROM _v_relation_column_def WHERE name = '%s' AND attnum > 0 ORDER BY attnum";
+ // netezza doesn't have keys. it does have distributions, so maybe this is
+ // something that can be pulled from the system tables
+ var $metaKeySQL = "";
+ var $hasAffectedRows = true;
+ var $hasLimit = true;
+ var $true = 't'; // string that represents TRUE for a database
+ var $false = 'f'; // string that represents FALSE for a database
+ var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database
+ var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt.
+ var $ansiOuter = true;
+ var $autoRollback = true; // apparently pgsql does not autorollback properly before 4.3.4
+ // http://bugs.php.net/bug.php?id=25404
+
+
+ function ADODB_netezza()
+ {
+
+ }
+
+ function &MetaColumns($table,$upper=true)
+ {
+
+ // Changed this function to support Netezza which has no concept of keys
+ // could posisbly work on other things from the system table later.
+
+ global $ADODB_FETCH_MODE;
+
+ $table = strtolower($table);
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+
+ $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table));
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if ($rs === false) return false;
+
+ $retarr = array();
+ while (!$rs->EOF) {
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+
+ // since we're returning type and length as one string,
+ // split them out here.
+
+ if ($first = strstr($rs->fields[1], "(")) {
+ $fld->max_length = trim($first, "()");
+ } else {
+ $fld->max_length = -1;
+ }
+
+ if ($first = strpos($rs->fields[1], "(")) {
+ $fld->type = substr($rs->fields[1], 0, $first);
+ } else {
+ $fld->type = $rs->fields[1];
+ }
+
+ switch ($fld->type) {
+ case "byteint":
+ case "boolean":
+ $fld->max_length = 1;
+ break;
+ case "smallint":
+ $fld->max_length = 2;
+ break;
+ case "integer":
+ case "numeric":
+ case "date":
+ $fld->max_length = 4;
+ break;
+ case "bigint":
+ case "time":
+ case "timestamp":
+ $fld->max_length = 8;
+ break;
+ case "timetz":
+ case "time with time zone":
+ $fld->max_length = 12;
+ break;
+ }
+
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
+ else $retarr[($upper) ? strtoupper($fld->name) : $fld->name] = $fld;
+
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ return $retarr;
+
+ }
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_netezza extends ADORecordSet_postgres64
+{
+ var $databaseType = "netezza";
+ var $canSeek = true;
+
+ function ADORecordSet_netezza($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode)
+ {
+ case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;
+ case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;
+
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default: $this->fetchMode = PGSQL_BOTH; break;
+ }
+ $this->adodbFetchMode = $mode;
+ $this->ADORecordSet($queryID);
+ }
+
+ // _initrs modified to disable blob handling
+ function _initrs()
+ {
+ global $ADODB_COUNTRECS;
+ $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($this->_queryID):-1;
+ $this->_numOfFields = @pg_numfields($this->_queryID);
+ }
+
+}
+?>
diff --git a/lib/adodb/drivers/adodb-oci8.inc.php b/lib/adodb/drivers/adodb-oci8.inc.php
new file mode 100644
index 0000000..3681876
--- /dev/null
+++ b/lib/adodb/drivers/adodb-oci8.inc.php
@@ -0,0 +1,1512 @@
+<?php
+/*
+
+ version V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved.
+
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Code contributed by George Fourlanos <fou@infomap.gr>
+
+ 13 Nov 2000 jlim - removed all ora_* references.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+/*
+NLS_Date_Format
+Allows you to use a date format other than the Oracle Lite default. When a literal
+character string appears where a date value is expected, the Oracle Lite database
+tests the string to see if it matches the formats of Oracle, SQL-92, or the value
+specified for this parameter in the POLITE.INI file. Setting this parameter also
+defines the default format used in the TO_CHAR or TO_DATE functions when no
+other format string is supplied.
+
+For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is
+yy-mm-dd or yyyy-mm-dd.
+
+Using 'RR' in the format forces two-digit years less than or equal to 49 to be
+interpreted as years in the 21st century (2000–2049), and years over 50 as years in
+the 20th century (1950–1999). Setting the RR format as the default for all two-digit
+year entries allows you to become year-2000 compliant. For example:
+NLS_DATE_FORMAT='RR-MM-DD'
+
+You can also modify the date format using the ALTER SESSION command.
+*/
+
+# define the LOB descriptor type for the given type
+# returns false if no LOB descriptor
+function oci_lob_desc($type) {
+ switch ($type) {
+ case OCI_B_BFILE: $result = OCI_D_FILE; break;
+ case OCI_B_CFILEE: $result = OCI_D_FILE; break;
+ case OCI_B_CLOB: $result = OCI_D_LOB; break;
+ case OCI_B_BLOB: $result = OCI_D_LOB; break;
+ case OCI_B_ROWID: $result = OCI_D_ROWID; break;
+ default: $result = false; break;
+ }
+ return $result;
+}
+
+class ADODB_oci8 extends ADOConnection {
+ var $databaseType = 'oci8';
+ var $dataProvider = 'oci8';
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $concat_operator='||';
+ var $sysDate = "TRUNC(SYSDATE)";
+ var $sysTimeStamp = 'SYSDATE';
+ var $metaDatabasesSQL = "SELECT USERNAME FROM ALL_USERS WHERE USERNAME NOT IN ('SYS','SYSTEM','DBSNMP','OUTLN') ORDER BY 1";
+ var $_stmt;
+ var $_commit = OCI_COMMIT_ON_SUCCESS;
+ var $_initdate = true; // init date to YYYY-MM-DD
+ var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW') and table_name not like 'BIN\$%'"; // bin$ tables are recycle bin tables
+ var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net
+ var $_bindInputArray = true;
+ var $hasGenID = true;
+ var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL";
+ var $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s";
+ var $_dropSeqSQL = "DROP SEQUENCE %s";
+ var $hasAffectedRows = true;
+ var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)";
+ var $noNullStrings = false;
+ var $connectSID = false;
+ var $_bind = false;
+ var $_nestedSQL = true;
+ var $_hasOCIFetchStatement = false;
+ var $_getarray = false; // currently not working
+ var $leftOuter = ''; // oracle wierdness, $col = $value (+) for LEFT OUTER, $col (+)= $value for RIGHT OUTER
+ var $session_sharing_force_blob = false; // alter session on updateblob if set to true
+ var $firstrows = true; // enable first rows optimization on SelectLimit()
+ var $selectOffsetAlg1 = 100; // when to use 1st algorithm of selectlimit.
+ var $NLS_DATE_FORMAT = 'YYYY-MM-DD'; // To include time, use 'RRRR-MM-DD HH24:MI:SS'
+ var $useDBDateFormatForTextInput=false;
+ var $datetime = false; // MetaType('DATE') returns 'D' (datetime==false) or 'T' (datetime == true)
+ var $_refLOBs = array();
+
+ // var $ansiOuter = true; // if oracle9
+
+ function ADODB_oci8()
+ {
+ $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;
+ if (defined('ADODB_EXTENSION')) $this->rsPrefix .= 'ext_';
+ }
+
+ /* Function &MetaColumns($table) added by smondino@users.sourceforge.net*/
+ function &MetaColumns($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $false = false;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
+
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ if (!$rs) {
+ return $false;
+ }
+ $retarr = array();
+ while (!$rs->EOF) { //print_r($rs->fields);
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+ $fld->max_length = $rs->fields[2];
+ $fld->scale = $rs->fields[3];
+ if ($rs->fields[1] == 'NUMBER') {
+ if ($rs->fields[3] == 0) $fld->type = 'INT';
+ $fld->max_length = $rs->fields[4];
+ }
+ $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
+ $fld->binary = (strpos($fld->type,'BLOB') !== false);
+ $fld->default_value = $rs->fields[6];
+
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
+ else $retarr[strtoupper($fld->name)] = $fld;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ if (empty($retarr))
+ return $false;
+ else
+ return $retarr;
+ }
+
+ function Time()
+ {
+ $rs =& $this->Execute("select TO_CHAR($this->sysTimeStamp,'YYYY-MM-DD HH24:MI:SS') from dual");
+ if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
+
+ return false;
+ }
+
+/*
+
+ Multiple modes of connection are supported:
+
+ a. Local Database
+ $conn->Connect(false,'scott','tiger');
+
+ b. From tnsnames.ora
+ $conn->Connect(false,'scott','tiger',$tnsname);
+ $conn->Connect($tnsname,'scott','tiger');
+
+ c. Server + service name
+ $conn->Connect($serveraddress,'scott,'tiger',$service_name);
+
+ d. Server + SID
+ $conn->connectSID = true;
+ $conn->Connect($serveraddress,'scott,'tiger',$SID);
+
+
+Example TNSName:
+---------------
+NATSOFT.DOMAIN =
+ (DESCRIPTION =
+ (ADDRESS_LIST =
+ (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523))
+ )
+ (CONNECT_DATA =
+ (SERVICE_NAME = natsoft.domain)
+ )
+ )
+
+ There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection
+
+*/
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0)
+ {
+ if (!function_exists('OCIPLogon')) return null;
+
+
+ $this->_errorMsg = false;
+ $this->_errorCode = false;
+
+ if($argHostname) { // added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi>
+ if (empty($argDatabasename)) $argDatabasename = $argHostname;
+ else {
+ if(strpos($argHostname,":")) {
+ $argHostinfo=explode(":",$argHostname);
+ $argHostname=$argHostinfo[0];
+ $argHostport=$argHostinfo[1];
+ } else {
+ $argHostport = empty($this->port)? "1521" : $this->port;
+ }
+
+ if ($this->connectSID) {
+ $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
+ .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";
+ } else
+ $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
+ .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";
+ }
+ }
+
+ //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";
+ if ($mode==1) {
+ $this->_connectionID = ($this->charSet) ?
+ OCIPLogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
+ :
+ OCIPLogon($argUsername,$argPassword, $argDatabasename)
+ ;
+ if ($this->_connectionID && $this->autoRollback) OCIrollback($this->_connectionID);
+ } else if ($mode==2) {
+ $this->_connectionID = ($this->charSet) ?
+ OCINLogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
+ :
+ OCINLogon($argUsername,$argPassword, $argDatabasename);
+
+ } else {
+ $this->_connectionID = ($this->charSet) ?
+ OCILogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
+ :
+ OCILogon($argUsername,$argPassword, $argDatabasename);
+ }
+ if (!$this->_connectionID) return false;
+ if ($this->_initdate) {
+ $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
+ }
+
+ // looks like:
+ // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production
+ // $vers = OCIServerVersion($this->_connectionID);
+ // if (strpos($vers,'8i') !== false) $this->ansiOuter = true;
+ return true;
+ }
+
+ function ServerInfo()
+ {
+ $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level');
+ $arr['description'] = @OCIServerVersion($this->_connectionID);
+ $arr['version'] = ADOConnection::_findvers($arr['description']);
+ return $arr;
+ }
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1);
+ }
+
+ // returns true or false
+ function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2);
+ }
+
+ function _affectedrows()
+ {
+ if (is_resource($this->_stmt)) return @OCIRowCount($this->_stmt);
+ return 0;
+ }
+
+ function IfNull( $field, $ifNull )
+ {
+ return " NVL($field, $ifNull) "; // if Oracle
+ }
+
+ // format and return date string in database date format
+ function DBDate($d)
+ {
+ if (empty($d) && $d !== 0) return 'null';
+
+ if (is_string($d)) $d = ADORecordSet::UnixDate($d);
+ return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->NLS_DATE_FORMAT."')";
+ }
+
+ function BindDate($d)
+ {
+ $d = ADOConnection::DBDate($d);
+ if (strncmp($d,"'",1)) return $d;
+
+ return substr($d,1,strlen($d)-2);
+ }
+
+ function BindTimeStamp($d)
+ {
+ $d = ADOConnection::DBTimeStamp($d);
+ if (strncmp($d,"'",1)) return $d;
+
+ return substr($d,1,strlen($d)-2);
+ }
+
+ // format and return date string in database timestamp format
+ function DBTimeStamp($ts)
+ {
+ if (empty($ts) && $ts !== 0) return 'null';
+ if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
+ return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";
+ }
+
+ function RowLock($tables,$where,$flds='1 as ignore')
+ {
+ if ($this->autoCommit) $this->BeginTrans();
+ return $this->GetOne("select $flds from $tables where $where for update");
+ }
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ if ($mask) {
+ $save = $this->metaTablesSQL;
+ $mask = $this->qstr(strtoupper($mask));
+ $this->metaTablesSQL .= " AND upper(table_name) like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ if ($mask) {
+ $this->metaTablesSQL = $save;
+ }
+ return $ret;
+ }
+
+ // Mark Newnham
+ function &MetaIndexes ($table, $primary = FALSE, $owner=false)
+ {
+ // save old fetch mode
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+
+ // get index details
+ $table = strtoupper($table);
+
+ // get Primary index
+ $primary_key = '';
+
+ $false = false;
+ $rs = $this->Execute(sprintf("SELECT * FROM ALL_CONSTRAINTS WHERE UPPER(TABLE_NAME)='%s' AND CONSTRAINT_TYPE='P'",$table));
+ if ($row = $rs->FetchRow())
+ $primary_key = $row[1]; //constraint_name
+
+ if ($primary==TRUE && $primary_key=='') {
+ if (isset($savem))
+ $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ return $false; //There is no primary key
+ }
+
+ $rs = $this->Execute(sprintf("SELECT ALL_INDEXES.INDEX_NAME, ALL_INDEXES.UNIQUENESS, ALL_IND_COLUMNS.COLUMN_POSITION, ALL_IND_COLUMNS.COLUMN_NAME FROM ALL_INDEXES,ALL_IND_COLUMNS WHERE UPPER(ALL_INDEXES.TABLE_NAME)='%s' AND ALL_IND_COLUMNS.INDEX_NAME=ALL_INDEXES.INDEX_NAME",$table));
+
+
+ if (!is_object($rs)) {
+ if (isset($savem))
+ $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ return $false;
+ }
+
+ $indexes = array ();
+ // parse index data into array
+
+ while ($row = $rs->FetchRow()) {
+ if ($primary && $row[0] != $primary_key) continue;
+ if (!isset($indexes[$row[0]])) {
+ $indexes[$row[0]] = array(
+ 'unique' => ($row[1] == 'UNIQUE'),
+ 'columns' => array()
+ );
+ }
+ $indexes[$row[0]]['columns'][$row[2] - 1] = $row[3];
+ }
+
+ // sort columns by order in the index
+ foreach ( array_keys ($indexes) as $index ) {
+ ksort ($indexes[$index]['columns']);
+ }
+
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ }
+ return $indexes;
+ }
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->autoCommit = false;
+ $this->_commit = OCI_DEFAULT;
+
+ if ($this->_transmode) $this->Execute("SET TRANSACTION ".$this->_transmode);
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+
+ if ($this->transCnt) $this->transCnt -= 1;
+ $ret = OCIcommit($this->_connectionID);
+ $this->_commit = OCI_COMMIT_ON_SUCCESS;
+ $this->autoCommit = true;
+ return $ret;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $ret = OCIrollback($this->_connectionID);
+ $this->_commit = OCI_COMMIT_ON_SUCCESS;
+ $this->autoCommit = true;
+ return $ret;
+ }
+
+
+ function SelectDB($dbName)
+ {
+ return false;
+ }
+
+ function ErrorMsg()
+ {
+ if ($this->_errorMsg !== false) return $this->_errorMsg;
+
+ if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
+ if (empty($arr)) {
+ if (is_resource($this->_connectionID)) $arr = @OCIError($this->_connectionID);
+ else $arr = @OCIError();
+ if ($arr === false) return '';
+ }
+ $this->_errorMsg = $arr['message'];
+ $this->_errorCode = $arr['code'];
+ return $this->_errorMsg;
+ }
+
+ function ErrorNo()
+ {
+ if ($this->_errorCode !== false) return $this->_errorCode;
+
+ if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
+ if (empty($arr)) {
+ $arr = @OCIError($this->_connectionID);
+ if ($arr == false) $arr = @OCIError();
+ if ($arr == false) return '';
+ }
+
+ $this->_errorMsg = $arr['message'];
+ $this->_errorCode = $arr['code'];
+
+ return $arr['code'];
+ }
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysTimeStamp;
+ $s = 'TO_CHAR('.$col.",'";
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= 'YYYY';
+ break;
+ case 'Q':
+ case 'q':
+ $s .= 'Q';
+ break;
+
+ case 'M':
+ $s .= 'Mon';
+ break;
+
+ case 'm':
+ $s .= 'MM';
+ break;
+ case 'D':
+ case 'd':
+ $s .= 'DD';
+ break;
+
+ case 'H':
+ $s.= 'HH24';
+ break;
+
+ case 'h':
+ $s .= 'HH';
+ break;
+
+ case 'i':
+ $s .= 'MI';
+ break;
+
+ case 's':
+ $s .= 'SS';
+ break;
+
+ case 'a':
+ case 'A':
+ $s .= 'AM';
+ break;
+
+ case 'w':
+ $s .= 'D';
+ break;
+
+ case 'l':
+ $s .= 'DAY';
+ break;
+
+ case 'W':
+ $s .= 'WW';
+ break;
+
+ default:
+ // handle escape characters...
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
+ else $s .= '"'.$ch.'"';
+
+ }
+ }
+ return $s. "')";
+ }
+
+
+ /*
+ This algorithm makes use of
+
+ a. FIRST_ROWS hint
+ The FIRST_ROWS hint explicitly chooses the approach to optimize response time,
+ that is, minimum resource usage to return the first row. Results will be returned
+ as soon as they are identified.
+
+ b. Uses rownum tricks to obtain only the required rows from a given offset.
+ As this uses complicated sql statements, we only use this if the $offset >= 100.
+ This idea by Tomas V V Cox.
+
+ This implementation does not appear to work with oracle 8.0.5 or earlier. Comment
+ out this function then, and the slower SelectLimit() in the base class will be used.
+ */
+ function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
+ {
+ // seems that oracle only supports 1 hint comment in 8i
+ if ($this->firstrows) {
+ if (strpos($sql,'/*+') !== false)
+ $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
+ else
+ $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
+ }
+
+ if ($offset < $this->selectOffsetAlg1) {
+ if ($nrows > 0) {
+ if ($offset > 0) $nrows += $offset;
+ //$inputarr['adodb_rownum'] = $nrows;
+ if ($this->databaseType == 'oci8po') {
+ $sql = "select * from (".$sql.") where rownum <= ?";
+ } else {
+ $sql = "select * from (".$sql.") where rownum <= :adodb_offset";
+ }
+ $inputarr['adodb_offset'] = $nrows;
+ $nrows = -1;
+ }
+ // note that $nrows = 0 still has to work ==> no rows returned
+
+ $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+ return $rs;
+
+ } else {
+ // Algorithm by Tomas V V Cox, from PEAR DB oci8.php
+
+ // Let Oracle return the name of the columns
+ $q_fields = "SELECT * FROM (".$sql.") WHERE NULL = NULL";
+
+ $false = false;
+ if (! $stmt_arr = $this->Prepare($q_fields)) {
+ return $false;
+ }
+ $stmt = $stmt_arr[1];
+
+ if (is_array($inputarr)) {
+ foreach($inputarr as $k => $v) {
+ if (is_array($v)) {
+ if (sizeof($v) == 2) // suggested by g.giunta@libero.
+ OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
+ else
+ OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
+ } else {
+ $len = -1;
+ if ($v === ' ') $len = 1;
+ if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again
+ $bindarr[$k] = $v;
+ } else { // dynamic sql, so rebind every time
+ OCIBindByName($stmt,":$k",$inputarr[$k],$len);
+ }
+ }
+ }
+ }
+
+ if (!OCIExecute($stmt, OCI_DEFAULT)) {
+ OCIFreeStatement($stmt);
+ return $false;
+ }
+
+ $ncols = OCINumCols($stmt);
+ for ( $i = 1; $i <= $ncols; $i++ ) {
+ $cols[] = '"'.OCIColumnName($stmt, $i).'"';
+ }
+ $result = false;
+
+ OCIFreeStatement($stmt);
+ $fields = implode(',', $cols);
+ $nrows += $offset;
+ $offset += 1; // in Oracle rownum starts at 1
+
+ if ($this->databaseType == 'oci8po') {
+ $sql = "SELECT $fields FROM".
+ "(SELECT rownum as adodb_rownum, $fields FROM".
+ " ($sql) WHERE rownum <= ?".
+ ") WHERE adodb_rownum >= ?";
+ } else {
+ $sql = "SELECT $fields FROM".
+ "(SELECT rownum as adodb_rownum, $fields FROM".
+ " ($sql) WHERE rownum <= :adodb_nrows".
+ ") WHERE adodb_rownum >= :adodb_offset";
+ }
+ $inputarr['adodb_nrows'] = $nrows;
+ $inputarr['adodb_offset'] = $offset;
+
+ if ($secs2cache>0) $rs =& $this->CacheExecute($secs2cache, $sql,$inputarr);
+ else $rs =& $this->Execute($sql,$inputarr);
+ return $rs;
+ }
+
+ }
+
+ /**
+ * Usage:
+ * Store BLOBs and CLOBs
+ *
+ * Example: to store $var in a blob
+ *
+ * $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())');
+ * $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB');
+ *
+ * $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'.
+ *
+ * to get length of LOB:
+ * select DBMS_LOB.GETLENGTH(ablob) from TABLE
+ *
+ * If you are using CURSOR_SHARING = force, it appears this will case a segfault
+ * under oracle 8.1.7.0. Run:
+ * $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
+ * before UpdateBlob() then...
+ */
+
+ function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+
+ //if (strlen($val) < 4000) return $this->Execute("UPDATE $table SET $column=:blob WHERE $where",array('blob'=>$val)) != false;
+
+ switch(strtoupper($blobtype)) {
+ default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
+ case 'BLOB': $type = OCI_B_BLOB; break;
+ case 'CLOB': $type = OCI_B_CLOB; break;
+ }
+
+ if ($this->databaseType == 'oci8po')
+ $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
+ else
+ $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
+
+ $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
+ $arr['blob'] = array($desc,-1,$type);
+ if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
+ $commit = $this->autoCommit;
+ if ($commit) $this->BeginTrans();
+ $rs = $this->_Execute($sql,$arr);
+ if ($rez = !empty($rs)) $desc->save($val);
+ $desc->free();
+ if ($commit) $this->CommitTrans();
+ if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE');
+
+ if ($rez) $rs->Close();
+ return $rez;
+ }
+
+ /**
+ * Usage: store file pointed to by $var in a blob
+ */
+ function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB')
+ {
+ switch(strtoupper($blobtype)) {
+ default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
+ case 'BLOB': $type = OCI_B_BLOB; break;
+ case 'CLOB': $type = OCI_B_CLOB; break;
+ }
+
+ if ($this->databaseType == 'oci8po')
+ $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
+ else
+ $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
+
+ $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
+ $arr['blob'] = array($desc,-1,$type);
+
+ $this->BeginTrans();
+ $rs = ADODB_oci8::Execute($sql,$arr);
+ if ($rez = !empty($rs)) $desc->savefile($val);
+ $desc->free();
+ $this->CommitTrans();
+
+ if ($rez) $rs->Close();
+ return $rez;
+ }
+
+ /**
+ * Execute SQL
+ *
+ * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
+ * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
+ * @return RecordSet or false
+ */
+ function &Execute($sql,$inputarr=false)
+ {
+ if ($this->fnExecute) {
+ $fn = $this->fnExecute;
+ $ret =& $fn($this,$sql,$inputarr);
+ if (isset($ret)) return $ret;
+ }
+ if ($inputarr) {
+ #if (!is_array($inputarr)) $inputarr = array($inputarr);
+
+ $element0 = reset($inputarr);
+
+ # is_object check because oci8 descriptors can be passed in
+ if (is_array($element0) && !is_object(reset($element0))) {
+ 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;
+ }
+
+ /*
+ Example of usage:
+
+ $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
+ */
+ function Prepare($sql,$cursor=false)
+ {
+ static $BINDNUM = 0;
+
+ $stmt = OCIParse($this->_connectionID,$sql);
+
+ if (!$stmt) {
+ $this->_errorMsg = false;
+ $this->_errorCode = false;
+ $arr = @OCIError($this->_connectionID);
+ if ($arr === false) return false;
+
+ $this->_errorMsg = $arr['message'];
+ $this->_errorCode = $arr['code'];
+ return false;
+ }
+
+ $BINDNUM += 1;
+
+ $sttype = @OCIStatementType($stmt);
+ if ($sttype == 'BEGIN' || $sttype == 'DECLARE') {
+ return array($sql,$stmt,0,$BINDNUM, ($cursor) ? OCINewCursor($this->_connectionID) : false);
+ }
+ return array($sql,$stmt,0,$BINDNUM);
+ }
+
+ /*
+ Call an oracle stored procedure and returns a cursor variable as a recordset.
+ Concept by Robert Tuttle robert@ud.com
+
+ Example:
+ Note: we return a cursor variable in :RS2
+ $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2');
+
+ $rs = $db->ExecuteCursor(
+ "BEGIN :RS2 = adodb.getdata(:VAR1); END;",
+ 'RS2',
+ array('VAR1' => 'Mr Bean'));
+
+ */
+ function &ExecuteCursor($sql,$cursorName='rs',$params=false)
+ {
+ if (is_array($sql)) $stmt = $sql;
+ else $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor
+
+ if (is_array($stmt) && sizeof($stmt) >= 5) {
+ $hasref = true;
+ $ignoreCur = false;
+ $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR);
+ if ($params) {
+ foreach($params as $k => $v) {
+ $this->Parameter($stmt,$params[$k], $k);
+ }
+ }
+ } else
+ $hasref = false;
+
+ $rs =& $this->Execute($stmt);
+ if ($rs) {
+ if ($rs->databaseType == 'array') OCIFreeCursor($stmt[4]);
+ else if ($hasref) $rs->_refcursor = $stmt[4];
+ }
+ return $rs;
+ }
+
+ /*
+ Bind a variable -- very, very fast for executing repeated statements in oracle.
+ Better than using
+ for ($i = 0; $i < $max; $i++) {
+ $p1 = ?; $p2 = ?; $p3 = ?;
+ $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)",
+ array($p1,$p2,$p3));
+ }
+
+ Usage:
+ $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
+ $DB->Bind($stmt, $p1);
+ $DB->Bind($stmt, $p2);
+ $DB->Bind($stmt, $p3);
+ for ($i = 0; $i < $max; $i++) {
+ $p1 = ?; $p2 = ?; $p3 = ?;
+ $DB->Execute($stmt);
+ }
+
+ Some timings:
+ ** Test table has 3 cols, and 1 index. Test to insert 1000 records
+ Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute
+ Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute
+ Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute
+
+ Now if PHP only had batch/bulk updating like Java or PL/SQL...
+
+ Note that the order of parameters differs from OCIBindByName,
+ because we default the names to :0, :1, :2
+ */
+ function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false,$isOutput=false)
+ {
+
+ if (!is_array($stmt)) return false;
+
+ if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) {
+ return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type);
+ }
+
+ if ($name == false) {
+ if ($type !== false) $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size,$type);
+ else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator
+ $stmt[2] += 1;
+ } else if (oci_lob_desc($type)) {
+ if ($this->debug) {
+ ADOConnection::outp("<b>Bind</b>: name = $name");
+ }
+ //we have to create a new Descriptor here
+ $numlob = count($this->_refLOBs);
+ $this->_refLOBs[$numlob]['LOB'] = OCINewDescriptor($this->_connectionID, oci_lob_desc($type));
+ $this->_refLOBs[$numlob]['TYPE'] = $isOutput;
+
+ $tmp = &$this->_refLOBs[$numlob]['LOB'];
+ $rez = OCIBindByName($stmt[1], ":".$name, $tmp, -1, $type);
+ if ($this->debug) {
+ ADOConnection::outp("<b>Bind</b>: descriptor has been allocated, var (".$name.") binded");
+ }
+
+ // if type is input then write data to lob now
+ if ($isOutput == false) {
+ $var = $this->BlobEncode($var);
+ $tmp->WriteTemporary($var);
+ $this->_refLOBs[$numlob]['VAR'] = &$var;
+ if ($this->debug) {
+ ADOConnection::outp("<b>Bind</b>: LOB has been written to temp");
+ }
+ } else {
+ $this->_refLOBs[$numlob]['VAR'] = &$var;
+ }
+ $rez = $tmp;
+ } else {
+ if ($this->debug)
+ ADOConnection::outp("<b>Bind</b>: name = $name");
+
+ if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
+ else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator
+ }
+
+ return $rez;
+ }
+
+ function Param($name,$type=false)
+ {
+ return ':'.$name;
+ }
+
+ /*
+ Usage:
+ $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
+ $db->Parameter($stmt,$id,'myid');
+ $db->Parameter($stmt,$group,'group');
+ $db->Execute($stmt);
+
+ @param $stmt Statement returned by Prepare() or PrepareSP().
+ @param $var PHP variable to bind to
+ @param $name Name of stored procedure variable name to bind to.
+ @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
+ @param [$maxLen] Holds an maximum length of the variable.
+ @param [$type] The data type of $var. Legal values depend on driver.
+
+ See OCIBindByName documentation at php.net.
+ */
+ function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
+ {
+ if ($this->debug) {
+ $prefix = ($isOutput) ? 'Out' : 'In';
+ $ztype = (empty($type)) ? 'false' : $type;
+ ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
+ }
+ return $this->Bind($stmt,$var,$maxLen,$type,$name,$isOutput);
+ }
+
+ /*
+ returns query ID if successful, otherwise false
+ this version supports:
+
+ 1. $db->execute('select * from table');
+
+ 2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
+ $db->execute($prepared_statement, array(1,2,3));
+
+ 3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3));
+
+ 4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
+ $db->bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3);
+ $db->execute($stmt);
+ */
+ function _query($sql,$inputarr)
+ {
+ if (is_array($sql)) { // is prepared sql
+ $stmt = $sql[1];
+
+ // we try to bind to permanent array, so that OCIBindByName is persistent
+ // and carried out once only - note that max array element size is 4000 chars
+ if (is_array($inputarr)) {
+ $bindpos = $sql[3];
+ if (isset($this->_bind[$bindpos])) {
+ // all tied up already
+ $bindarr = &$this->_bind[$bindpos];
+ } else {
+ // one statement to bind them all
+ $bindarr = array();
+ foreach($inputarr as $k => $v) {
+ $bindarr[$k] = $v;
+ OCIBindByName($stmt,":$k",$bindarr[$k],is_string($v) && strlen($v)>4000 ? -1 : 4000);
+ }
+ $this->_bind[$bindpos] = &$bindarr;
+ }
+ }
+ } else {
+ $stmt=OCIParse($this->_connectionID,$sql);
+ }
+
+ $this->_stmt = $stmt;
+ if (!$stmt) return false;
+
+ if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS);
+
+ if (is_array($inputarr)) {
+ foreach($inputarr as $k => $v) {
+ if (is_array($v)) {
+ if (sizeof($v) == 2) // suggested by g.giunta@libero.
+ OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
+ else
+ OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
+
+ if ($this->debug==99) echo "name=:$k",' var='.$inputarr[$k][0],' len='.$v[1],' type='.$v[2],'<br>';
+ } else {
+ $len = -1;
+ if ($v === ' ') $len = 1;
+ if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again
+ $bindarr[$k] = $v;
+ } else { // dynamic sql, so rebind every time
+ OCIBindByName($stmt,":$k",$inputarr[$k],$len);
+ }
+ }
+ }
+ }
+
+ $this->_errorMsg = false;
+ $this->_errorCode = false;
+ if (OCIExecute($stmt,$this->_commit)) {
+//OCIInternalDebug(1);
+ if (count($this -> _refLOBs) > 0) {
+
+ foreach ($this -> _refLOBs as $key => $value) {
+ if ($this -> _refLOBs[$key]['TYPE'] == true) {
+ $tmp = $this -> _refLOBs[$key]['LOB'] -> load();
+ if ($this -> debug) {
+ ADOConnection::outp("<b>OUT LOB</b>: LOB has been loaded. <br>");
+ }
+ //$_GLOBALS[$this -> _refLOBs[$key]['VAR']] = $tmp;
+ $this -> _refLOBs[$key]['VAR'] = $tmp;
+ } else {
+ $this->_refLOBs[$key]['LOB']->save($this->_refLOBs[$key]['VAR']);
+ $this -> _refLOBs[$key]['LOB']->free();
+ unset($this -> _refLOBs[$key]);
+ if ($this->debug) {
+ ADOConnection::outp("<b>IN LOB</b>: LOB has been saved. <br>");
+ }
+ }
+ }
+ }
+
+ switch (@OCIStatementType($stmt)) {
+ case "SELECT":
+ return $stmt;
+
+ case 'DECLARE':
+ case "BEGIN":
+ if (is_array($sql) && !empty($sql[4])) {
+ $cursor = $sql[4];
+ if (is_resource($cursor)) {
+ $ok = OCIExecute($cursor);
+ return $cursor;
+ }
+ return $stmt;
+ } else {
+ if (is_resource($stmt)) {
+ OCIFreeStatement($stmt);
+ return true;
+ }
+ return $stmt;
+ }
+ break;
+ default :
+ // ociclose -- no because it could be used in a LOB?
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ if (!$this->_connectionID) return;
+
+ if (!$this->autoCommit) OCIRollback($this->_connectionID);
+ if (count($this->_refLOBs) > 0) {
+ foreach ($this ->_refLOBs as $key => $value) {
+ $this->_refLOBs[$key]['LOB']->free();
+ unset($this->_refLOBs[$key]);
+ }
+ }
+ OCILogoff($this->_connectionID);
+
+ $this->_stmt = false;
+ $this->_connectionID = false;
+ }
+
+ function MetaPrimaryKeys($table, $owner=false,$internalKey=false)
+ {
+ if ($internalKey) return array('ROWID');
+
+ // tested with oracle 8.1.7
+ $table = strtoupper($table);
+ if ($owner) {
+ $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))";
+ $ptab = 'ALL_';
+ } else {
+ $owner_clause = '';
+ $ptab = 'USER_';
+ }
+ $sql = "
+SELECT /*+ RULE */ distinct b.column_name
+ FROM {$ptab}CONSTRAINTS a
+ , {$ptab}CONS_COLUMNS b
+ WHERE ( UPPER(b.table_name) = ('$table'))
+ AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P')
+ $owner_clause
+ AND (a.constraint_name = b.constraint_name)";
+
+ $rs = $this->Execute($sql);
+ if ($rs && !$rs->EOF) {
+ $arr =& $rs->GetArray();
+ $a = array();
+ foreach($arr as $v) {
+ $a[] = reset($v);
+ }
+ return $a;
+ }
+ else return false;
+ }
+
+ // http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html
+ function MetaForeignKeys($table, $owner=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $table = $this->qstr(strtoupper($table));
+ if (!$owner) {
+ $owner = $this->user;
+ $tabp = 'user_';
+ } else
+ $tabp = 'all_';
+
+ $owner = ' and owner='.$this->qstr(strtoupper($owner));
+
+ $sql =
+"select constraint_name,r_owner,r_constraint_name
+ from {$tabp}constraints
+ where constraint_type = 'R' and table_name = $table $owner";
+
+ $constraints =& $this->GetArray($sql);
+ $arr = false;
+ foreach($constraints as $constr) {
+ $cons = $this->qstr($constr[0]);
+ $rowner = $this->qstr($constr[1]);
+ $rcons = $this->qstr($constr[2]);
+ $cols = $this->GetArray("select column_name from {$tabp}cons_columns where constraint_name=$cons $owner order by position");
+ $tabcol = $this->GetArray("select table_name,column_name from {$tabp}cons_columns where owner=$rowner and constraint_name=$rcons order by position");
+
+ if ($cols && $tabcol)
+ for ($i=0, $max=sizeof($cols); $i < $max; $i++) {
+ $arr[$tabcol[$i][0]] = $cols[$i][0].'='.$tabcol[$i][1];
+ }
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ return $arr;
+ }
+
+
+ function CharMax()
+ {
+ return 4000;
+ }
+
+ function TextMax()
+ {
+ return 4000;
+ }
+
+ /**
+ * Quotes a string.
+ * An example is $db->qstr("Don't bother",magic_quotes_runtime());
+ *
+ * @param s the string to quote
+ * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
+ * This undoes the stupidity of magic quotes for GPC.
+ *
+ * @return quoted string to be sent back to database
+ */
+ function qstr($s,$magic_quotes=false)
+ {
+ //$nofixquotes=false;
+
+ if ($this->noNullStrings && strlen($s)==0)$s = ' ';
+ if (!$magic_quotes) {
+ if ($this->replaceQuote[0] == '\\'){
+ $s = str_replace('\\','\\\\',$s);
+ }
+ return "'".str_replace("'",$this->replaceQuote,$s)."'";
+ }
+
+ // undo magic quotes for "
+ $s = str_replace('\\"','"',$s);
+
+ $s = str_replace('\\\\','\\',$s);
+ return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
+
+ }
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_oci8 extends ADORecordSet {
+
+ var $databaseType = 'oci8';
+ var $bind=false;
+ var $_fieldobjs;
+
+ //var $_arr = false;
+
+ function ADORecordset_oci8($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode)
+ {
+ case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+ case ADODB_FETCH_NUM:
+ default:
+ $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+ }
+
+ $this->adodbFetchMode = $mode;
+ $this->_queryID = $queryID;
+ }
+
+
+ function Init()
+ {
+ if ($this->_inited) return;
+
+ $this->_inited = true;
+ if ($this->_queryID) {
+
+ $this->_currentRow = 0;
+ @$this->_initrs();
+ $this->EOF = !$this->_fetch();
+
+ /*
+ // based on idea by Gaetano Giunta to detect unusual oracle errors
+ // see http://phplens.com/lens/lensforum/msgs.php?id=6771
+ $err = OCIError($this->_queryID);
+ if ($err && $this->connection->debug) ADOConnection::outp($err);
+ */
+
+ if (!is_array($this->fields)) {
+ $this->_numOfRows = 0;
+ $this->fields = array();
+ }
+ } else {
+ $this->fields = array();
+ $this->_numOfRows = 0;
+ $this->_numOfFields = 0;
+ $this->EOF = true;
+ }
+ }
+
+ function _initrs()
+ {
+ $this->_numOfRows = -1;
+ $this->_numOfFields = OCInumcols($this->_queryID);
+ if ($this->_numOfFields>0) {
+ $this->_fieldobjs = array();
+ $max = $this->_numOfFields;
+ for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i);
+ }
+ }
+
+ /* Returns: an object containing field information.
+ Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+ fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+ fetchField() is retrieved. */
+
+ function &_FetchField($fieldOffset = -1)
+ {
+ $fld = new ADOFieldObject;
+ $fieldOffset += 1;
+ $fld->name =OCIcolumnname($this->_queryID, $fieldOffset);
+ $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
+ $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
+ if ($fld->type == 'NUMBER') {
+ $p = OCIColumnPrecision($this->_queryID, $fieldOffset);
+ $sc = OCIColumnScale($this->_queryID, $fieldOffset);
+ if ($p != 0 && $sc == 0) $fld->type = 'INT';
+ //echo " $this->name ($p.$sc) ";
+ }
+ return $fld;
+ }
+
+ /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */
+ function &FetchField($fieldOffset = -1)
+ {
+ return $this->_fieldobjs[$fieldOffset];
+ }
+
+
+ /*
+ // 10% speedup to move MoveNext to child class
+ function _MoveNext()
+ {
+ //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this);
+
+ if ($this->EOF) return false;
+
+ $this->_currentRow++;
+ if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode))
+ return true;
+ $this->EOF = true;
+
+ return false;
+ } */
+
+
+ function MoveNext()
+ {
+ if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
+ $this->_currentRow += 1;
+ return true;
+ }
+ if (!$this->EOF) {
+ $this->_currentRow += 1;
+ $this->EOF = true;
+ }
+ return false;
+ }
+
+ /*
+ # does not work as first record is retrieved in _initrs(), so is not included in GetArray()
+ function &GetArray($nRows = -1)
+ {
+ global $ADODB_OCI8_GETARRAY;
+
+ if (true || !empty($ADODB_OCI8_GETARRAY)) {
+ # does not support $ADODB_ANSI_PADDING_OFF
+
+ //OCI_RETURN_NULLS and OCI_RETURN_LOBS is set by OCIfetchstatement
+ switch($this->adodbFetchMode) {
+ case ADODB_FETCH_NUM:
+
+ $ncols = @OCIfetchstatement($this->_queryID, $results, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW+OCI_NUM);
+ $results = array_merge(array($this->fields),$results);
+ return $results;
+
+ case ADODB_FETCH_ASSOC:
+ if (ADODB_ASSOC_CASE != 2 || $this->databaseType != 'oci8') break;
+
+ $ncols = @OCIfetchstatement($this->_queryID, $assoc, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW);
+ $results =& array_merge(array($this->fields),$assoc);
+ return $results;
+
+ default:
+ break;
+ }
+ }
+
+ $results =& ADORecordSet::GetArray($nRows);
+ return $results;
+
+ } */
+
+ /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
+ function &GetArrayLimit($nrows,$offset=-1)
+ {
+ if ($offset <= 0) {
+ $arr =& $this->GetArray($nrows);
+ return $arr;
+ }
+ $arr = array();
+ for ($i=1; $i < $offset; $i++)
+ if (!@OCIFetch($this->_queryID)) return $arr;
+
+ if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return $arr;;
+ $results = array();
+ $cnt = 0;
+ while (!$this->EOF && $nrows != $cnt) {
+ $results[$cnt++] = $this->fields;
+ $this->MoveNext();
+ }
+
+ return $results;
+ }
+
+
+ /* Use associative array to get fields array */
+ function 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)]];
+ }
+
+
+
+ function _seek($row)
+ {
+ return false;
+ }
+
+ function _fetch()
+ {
+ return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
+ }
+
+ /* close() only needs to be called if you are worried about using too much memory while your script
+ is running. All associated result memory for the specified result identifier will automatically be freed. */
+
+ function _close()
+ {
+ if ($this->connection->_stmt === $this->_queryID) $this->connection->_stmt = false;
+ if (!empty($this->_refcursor)) {
+ OCIFreeCursor($this->_refcursor);
+ $this->_refcursor = false;
+ }
+ @OCIFreeStatement($this->_queryID);
+ $this->_queryID = false;
+
+ }
+
+ function MetaType($t,$len=-1)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ switch (strtoupper($t)) {
+ case 'VARCHAR':
+ case 'VARCHAR2':
+ case 'CHAR':
+ case 'VARBINARY':
+ case 'BINARY':
+ case 'NCHAR':
+ case 'NVARCHAR':
+ case 'NVARCHAR2':
+ if (isset($this) && $len <= $this->blobSize) return 'C';
+
+ case 'NCLOB':
+ case 'LONG':
+ case 'LONG VARCHAR':
+ case 'CLOB':
+ return 'X';
+
+ case 'LONG RAW':
+ case 'LONG VARBINARY':
+ case 'BLOB':
+ return 'B';
+
+ case 'DATE':
+ return ($this->connection->datetime) ? 'T' : 'D';
+
+
+ case 'TIMESTAMP': return 'T';
+
+ case 'INT':
+ case 'SMALLINT':
+ case 'INTEGER':
+ return 'I';
+
+ default: return 'N';
+ }
+ }
+}
+
+class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 {
+ function ADORecordSet_ext_oci8($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode)
+ {
+ case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+ case ADODB_FETCH_NUM:
+ default: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
+ }
+ $this->adodbFetchMode = $mode;
+ $this->_queryID = $queryID;
+ }
+
+ function MoveNext()
+ {
+ return adodb_movenext($this);
+ }
+}
+?>
diff --git a/lib/adodb/drivers/adodb-oci805.inc.php b/lib/adodb/drivers/adodb-oci805.inc.php
new file mode 100644
index 0000000..8da0ba1
--- /dev/null
+++ b/lib/adodb/drivers/adodb-oci805.inc.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * @version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://php.weblogs.com
+ *
+ * Oracle 8.0.5 driver
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');
+
+class ADODB_oci805 extends ADODB_oci8 {
+ var $databaseType = "oci805";
+ var $connectSID = true;
+
+ function ADODB_oci805()
+ {
+ $this->ADODB_oci8();
+ }
+
+ function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
+ {
+ // seems that oracle only supports 1 hint comment in 8i
+ if (strpos($sql,'/*+') !== false)
+ $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
+ else
+ $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
+
+ /*
+ The following is only available from 8.1.5 because order by in inline views not
+ available before then...
+ http://www.jlcomp.demon.co.uk/faq/top_sql.html
+ if ($nrows > 0) {
+ if ($offset > 0) $nrows += $offset;
+ $sql = "select * from ($sql) where rownum <= $nrows";
+ $nrows = -1;
+ }
+ */
+
+ return ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+ }
+}
+
+class ADORecordset_oci805 extends ADORecordset_oci8 {
+ var $databaseType = "oci805";
+ function ADORecordset_oci805($id,$mode=false)
+ {
+ $this->ADORecordset_oci8($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-oci8po.inc.php b/lib/adodb/drivers/adodb-oci8po.inc.php
new file mode 100644
index 0000000..2432f39
--- /dev/null
+++ b/lib/adodb/drivers/adodb-oci8po.inc.php
@@ -0,0 +1,217 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Portable version of oci8 driver, to make it more similar to other database drivers.
+ The main differences are
+
+ 1. that the OCI_ASSOC names are in lowercase instead of uppercase.
+ 2. bind variables are mapped using ? instead of :<bindvar>
+
+ Should some emulation of RecordCount() be implemented?
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');
+
+class ADODB_oci8po extends ADODB_oci8 {
+ var $databaseType = 'oci8po';
+ var $dataProvider = 'oci8';
+ var $metaColumnsSQL = "select lower(cname),coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net
+ var $metaTablesSQL = "select lower(table_name),table_type from cat where table_type in ('TABLE','VIEW')";
+
+ function ADODB_oci8po()
+ {
+ $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;
+ # oci8po does not support adodb extension: adodb_movenext()
+ }
+
+ function Param($name)
+ {
+ return '?';
+ }
+
+ function Prepare($sql,$cursor=false)
+ {
+ $sqlarr = explode('?',$sql);
+ $sql = $sqlarr[0];
+ for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {
+ $sql .= ':'.($i-1) . $sqlarr[$i];
+ }
+ return ADODB_oci8::Prepare($sql,$cursor);
+ }
+
+ // emulate handling of parameters ? ?, replacing with :bind0 :bind1
+ function _query($sql,$inputarr)
+ {
+ if (is_array($inputarr)) {
+ $i = 0;
+ if (is_array($sql)) {
+ foreach($inputarr as $v) {
+ $arr['bind'.$i++] = $v;
+ }
+ } else {
+ $sqlarr = explode('?',$sql);
+ $sql = $sqlarr[0];
+ foreach($inputarr as $k => $v) {
+ $sql .= ":$k" . $sqlarr[++$i];
+ }
+ }
+ }
+ return ADODB_oci8::_query($sql,$inputarr);
+ }
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_oci8po extends ADORecordset_oci8 {
+
+ var $databaseType = 'oci8po';
+
+ function ADORecordset_oci8po($queryID,$mode=false)
+ {
+ $this->ADORecordset_oci8($queryID,$mode);
+ }
+
+ function Fields($colname)
+ {
+ if ($this->fetchMode & OCI_ASSOC) 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)]];
+ }
+
+ // lowercase field names...
+ function &_FetchField($fieldOffset = -1)
+ {
+ $fld = new ADOFieldObject;
+ $fieldOffset += 1;
+ $fld->name = strtolower(OCIcolumnname($this->_queryID, $fieldOffset));
+ $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
+ $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
+ if ($fld->type == 'NUMBER') {
+ //$p = OCIColumnPrecision($this->_queryID, $fieldOffset);
+ $sc = OCIColumnScale($this->_queryID, $fieldOffset);
+ if ($sc == 0) $fld->type = 'INT';
+ }
+ return $fld;
+ }
+ /*
+ function MoveNext()
+ {
+ if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
+ $this->_currentRow += 1;
+ return true;
+ }
+ if (!$this->EOF) {
+ $this->_currentRow += 1;
+ $this->EOF = true;
+ }
+ return false;
+ }*/
+
+ // 10% speedup to move MoveNext to child class
+ function MoveNext()
+ {
+ if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
+ global $ADODB_ANSI_PADDING_OFF;
+ $this->_currentRow++;
+
+ if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();
+ if (!empty($ADODB_ANSI_PADDING_OFF)) {
+ foreach($this->fields as $k => $v) {
+ if (is_string($v)) $this->fields[$k] = rtrim($v);
+ }
+ }
+ return true;
+ }
+ if (!$this->EOF) {
+ $this->EOF = true;
+ $this->_currentRow++;
+ }
+ return false;
+ }
+
+ /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
+ function &GetArrayLimit($nrows,$offset=-1)
+ {
+ if ($offset <= 0) {
+ $arr = $this->GetArray($nrows);
+ return $arr;
+ }
+ for ($i=1; $i < $offset; $i++)
+ if (!@OCIFetch($this->_queryID)) {
+ $arr = array();
+ return $arr;
+ }
+ if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
+ $arr = array();
+ return $arr;
+ }
+ if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();
+ $results = array();
+ $cnt = 0;
+ while (!$this->EOF && $nrows != $cnt) {
+ $results[$cnt++] = $this->fields;
+ $this->MoveNext();
+ }
+
+ return $results;
+ }
+
+ // Create associative array
+ function _updatefields()
+ {
+ if (ADODB_ASSOC_CASE == 2) return; // native
+
+ $arr = array();
+ $lowercase = (ADODB_ASSOC_CASE == 0);
+
+ foreach($this->fields as $k => $v) {
+ if (is_integer($k)) $arr[$k] = $v;
+ else {
+ if ($lowercase)
+ $arr[strtolower($k)] = $v;
+ else
+ $arr[strtoupper($k)] = $v;
+ }
+ }
+ $this->fields = $arr;
+ }
+
+ function _fetch()
+ {
+ $ret = @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
+ if ($ret) {
+ global $ADODB_ANSI_PADDING_OFF;
+
+ if ($this->fetchMode & OCI_ASSOC) $this->_updatefields();
+ if (!empty($ADODB_ANSI_PADDING_OFF)) {
+ foreach($this->fields as $k => $v) {
+ if (is_string($v)) $this->fields[$k] = rtrim($v);
+ }
+ }
+ }
+ return $ret;
+ }
+
+}
+
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-odbc.inc.php b/lib/adodb/drivers/adodb-odbc.inc.php
new file mode 100644
index 0000000..d8b8f18
--- /dev/null
+++ b/lib/adodb/drivers/adodb-odbc.inc.php
@@ -0,0 +1,738 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Requires ODBC. Works on Windows and Unix.
+*/
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+ define("_ADODB_ODBC_LAYER", 2 );
+
+/*--------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------*/
+
+
+class ADODB_odbc extends ADOConnection {
+ var $databaseType = "odbc";
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $dataProvider = "odbc";
+ var $hasAffectedRows = true;
+ var $binmode = ODBC_BINMODE_RETURN;
+ var $useFetchArray = false; // setting this to true will make array elements in FETCH_ASSOC mode case-sensitive
+ // breaking backward-compat
+ //var $longreadlen = 8000; // default number of chars to return for a Blob/Long field
+ var $_bindInputArray = false;
+ var $curmode = SQL_CUR_USE_DRIVER; // See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L
+ var $_genSeqSQL = "create table %s (id integer)";
+ var $_autocommit = true;
+ var $_haserrorfunctions = true;
+ var $_has_stupid_odbc_fetch_api_change = true;
+ var $_lastAffectedRows = 0;
+ var $uCaseTables = true; // for meta* functions, uppercase table names
+
+ function ADODB_odbc()
+ {
+ $this->_haserrorfunctions = ADODB_PHPVER >= 0x4050;
+ $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
+ }
+
+ // returns true or false
+ function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ global $php_errormsg;
+
+ if (!function_exists('odbc_connect')) return null;
+
+ if ($this->debug && $argDatabasename && $this->databaseType != 'vfp') {
+ ADOConnection::outp("For odbc Connect(), $argDatabasename is not used. Place dsn in 1st parameter.");
+ }
+ if (isset($php_errormsg)) $php_errormsg = '';
+ if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
+ else $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,$this->curmode);
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+
+ return $this->_connectionID != false;
+ }
+
+ // returns true or false
+ function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ global $php_errormsg;
+
+ if (!function_exists('odbc_connect')) return null;
+
+ if (isset($php_errormsg)) $php_errormsg = '';
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ if ($this->debug && $argDatabasename) {
+ ADOConnection::outp("For odbc PConnect(), $argDatabasename is not used. Place dsn in 1st parameter.");
+ }
+ // print "dsn=$argDSN u=$argUsername p=$argPassword<br>"; flush();
+ if ($this->curmode === false) $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword);
+ else $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,$this->curmode);
+
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ if ($this->_connectionID && $this->autoRollback) @odbc_rollback($this->_connectionID);
+ if (isset($this->connectStmt)) $this->Execute($this->connectStmt);
+
+ return $this->_connectionID != false;
+ }
+
+
+ function ServerInfo()
+ {
+
+ if (!empty($this->host) && ADODB_PHPVER >= 0x4300) {
+ $dsn = strtoupper($this->host);
+ $first = true;
+ $found = false;
+
+ if (!function_exists('odbc_data_source')) return false;
+
+ while(true) {
+
+ $rez = @odbc_data_source($this->_connectionID,
+ $first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT);
+ $first = false;
+ if (!is_array($rez)) break;
+ if (strtoupper($rez['server']) == $dsn) {
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) return ADOConnection::ServerInfo();
+ if (!isset($rez['version'])) $rez['version'] = '';
+ return $rez;
+ } else {
+ return ADOConnection::ServerInfo();
+ }
+ }
+
+
+ function CreateSequence($seqname='adodbseq',$start=1)
+ {
+ if (empty($this->_genSeqSQL)) return false;
+ $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+ if (!$ok) return false;
+ $start -= 1;
+ return $this->Execute("insert into $seqname values($start)");
+ }
+
+ var $_dropSeqSQL = 'drop table %s';
+ function DropSequence($seqname)
+ {
+ if (empty($this->_dropSeqSQL)) return false;
+ return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+ }
+
+ /*
+ This algorithm is not very efficient, but works even if table locking
+ is not available.
+
+ Will return false if unable to generate an ID after $MAXLOOPS attempts.
+ */
+ function GenID($seq='adodbseq',$start=1)
+ {
+ // if you have to modify the parameter below, your database is overloaded,
+ // or you need to implement generation of id's yourself!
+ $MAXLOOPS = 100;
+ //$this->debug=1;
+ while (--$MAXLOOPS>=0) {
+ $num = $this->GetOne("select id from $seq");
+ if ($num === false) {
+ $this->Execute(sprintf($this->_genSeqSQL ,$seq));
+ $start -= 1;
+ $num = '0';
+ $ok = $this->Execute("insert into $seq values($start)");
+ if (!$ok) return false;
+ }
+ $this->Execute("update $seq set id=id+1 where id=$num");
+
+ if ($this->affected_rows() > 0) {
+ $num += 1;
+ $this->genID = $num;
+ return $num;
+ }
+ }
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
+ }
+ return false;
+ }
+
+
+ function ErrorMsg()
+ {
+ if ($this->_haserrorfunctions) {
+ if ($this->_errorMsg !== false) return $this->_errorMsg;
+ if (empty($this->_connectionID)) return @odbc_errormsg();
+ return @odbc_errormsg($this->_connectionID);
+ } else return ADOConnection::ErrorMsg();
+ }
+
+ function ErrorNo()
+ {
+
+ if ($this->_haserrorfunctions) {
+ if ($this->_errorCode !== false) {
+ // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
+ return (strlen($this->_errorCode)<=2) ? 0 : $this->_errorCode;
+ }
+
+ if (empty($this->_connectionID)) $e = @odbc_error();
+ else $e = @odbc_error($this->_connectionID);
+
+ // bug in 4.0.6, error number can be corrupted string (should be 6 digits)
+ // so we check and patch
+ if (strlen($e)<=2) return 0;
+ return $e;
+ } else return ADOConnection::ErrorNo();
+ }
+
+
+
+ function BeginTrans()
+ {
+ if (!$this->hasTransactions) return false;
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->_autocommit = false;
+ return odbc_autocommit($this->_connectionID,false);
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+ $ret = odbc_commit($this->_connectionID);
+ odbc_autocommit($this->_connectionID,true);
+ return $ret;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+ $ret = odbc_rollback($this->_connectionID);
+ odbc_autocommit($this->_connectionID,true);
+ return $ret;
+ }
+
+ function MetaPrimaryKeys($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ if ($this->uCaseTables) $table = strtoupper($table);
+ $schema = '';
+ $this->_findschema($table,$schema);
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = @odbc_primarykeys($this->_connectionID,'',$schema,$table);
+
+ if (!$qid) {
+ $ADODB_FETCH_MODE = $savem;
+ return false;
+ }
+ $rs = new ADORecordSet_odbc($qid);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$rs) return false;
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+
+ $arr =& $rs->GetArray();
+ $rs->Close();
+ //print_r($arr);
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if ($arr[$i][3]) $arr2[] = $arr[$i][3];
+ }
+ return $arr2;
+ }
+
+
+
+ function &MetaTables($ttype=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = odbc_tables($this->_connectionID);
+
+ $rs = new ADORecordSet_odbc($qid);
+
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) {
+ $false = false;
+ return $false;
+ }
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+
+ $arr =& $rs->GetArray();
+ //print_r($arr);
+
+ $rs->Close();
+ $arr2 = array();
+
+ if ($ttype) {
+ $isview = strncmp($ttype,'V',1) === 0;
+ }
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if (!$arr[$i][2]) continue;
+ $type = $arr[$i][3];
+ if ($ttype) {
+ if ($isview) {
+ if (strncmp($type,'V',1) === 0) $arr2[] = $arr[$i][2];
+ } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $arr[$i][2];
+ } else if (strncmp($type,'SYS',3) !== 0) $arr2[] = $arr[$i][2];
+ }
+ return $arr2;
+ }
+
+/*
+See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcdatetime_data_type_changes.asp
+/ SQL data type codes /
+#define SQL_UNKNOWN_TYPE 0
+#define SQL_CHAR 1
+#define SQL_NUMERIC 2
+#define SQL_DECIMAL 3
+#define SQL_INTEGER 4
+#define SQL_SMALLINT 5
+#define SQL_FLOAT 6
+#define SQL_REAL 7
+#define SQL_DOUBLE 8
+#if (ODBCVER >= 0x0300)
+#define SQL_DATETIME 9
+#endif
+#define SQL_VARCHAR 12
+
+
+/ One-parameter shortcuts for date/time data types /
+#if (ODBCVER >= 0x0300)
+#define SQL_TYPE_DATE 91
+#define SQL_TYPE_TIME 92
+#define SQL_TYPE_TIMESTAMP 93
+
+#define SQL_UNICODE (-95)
+#define SQL_UNICODE_VARCHAR (-96)
+#define SQL_UNICODE_LONGVARCHAR (-97)
+*/
+ function ODBCTypes($t)
+ {
+ switch ((integer)$t) {
+ case 1:
+ case 12:
+ case 0:
+ case -95:
+ case -96:
+ return 'C';
+ case -97:
+ case -1: //text
+ return 'X';
+ case -4: //image
+ return 'B';
+
+ case 9:
+ case 91:
+ return 'D';
+
+ case 10:
+ case 11:
+ case 92:
+ case 93:
+ return 'T';
+
+ case 4:
+ case 5:
+ case -6:
+ return 'I';
+
+ case -11: // uniqidentifier
+ return 'R';
+ case -7: //bit
+ return 'L';
+
+ default:
+ return 'N';
+ }
+ }
+
+ function &MetaColumns($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $false = false;
+ if ($this->uCaseTables) $table = strtoupper($table);
+ $schema = '';
+ $this->_findschema($table,$schema);
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ /*if (false) { // after testing, confirmed that the following does not work becoz of a bug
+ $qid2 = odbc_tables($this->_connectionID);
+ $rs = new ADORecordSet_odbc($qid2);
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) return false;
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+ $rs->_fetch();
+
+ while (!$rs->EOF) {
+ if ($table == strtoupper($rs->fields[2])) {
+ $q = $rs->fields[0];
+ $o = $rs->fields[1];
+ break;
+ }
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $qid = odbc_columns($this->_connectionID,$q,$o,strtoupper($table),'%');
+ } */
+
+ switch ($this->databaseType) {
+ case 'access':
+ case 'vfp':
+ $qid = odbc_columns($this->_connectionID);#,'%','',strtoupper($table),'%');
+ break;
+
+
+ case 'db2':
+ $colname = "%";
+ $qid = odbc_columns($this->_connectionID, "", $schema, $table, $colname);
+ break;
+
+ default:
+ $qid = @odbc_columns($this->_connectionID,'%','%',strtoupper($table),'%');
+ if (empty($qid)) $qid = odbc_columns($this->_connectionID);
+ break;
+ }
+ if (empty($qid)) return $false;
+
+ $rs =& new ADORecordSet_odbc($qid);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$rs) return $false;
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+ $rs->_fetch();
+
+ $retarr = array();
+
+ /*
+ $rs->fields indices
+ 0 TABLE_QUALIFIER
+ 1 TABLE_SCHEM
+ 2 TABLE_NAME
+ 3 COLUMN_NAME
+ 4 DATA_TYPE
+ 5 TYPE_NAME
+ 6 PRECISION
+ 7 LENGTH
+ 8 SCALE
+ 9 RADIX
+ 10 NULLABLE
+ 11 REMARKS
+ */
+ while (!$rs->EOF) {
+ // adodb_pr($rs->fields);
+ if (strtoupper(trim($rs->fields[2])) == $table && (!$schema || strtoupper($rs->fields[1]) == $schema)) {
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[3];
+ $fld->type = $this->ODBCTypes($rs->fields[4]);
+
+ // ref: http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnaraccgen/html/msdn_odk.asp
+ // access uses precision to store length for char/varchar
+ if ($fld->type == 'C' or $fld->type == 'X') {
+ if ($this->databaseType == 'access')
+ $fld->max_length = $rs->fields[6];
+ else if ($rs->fields[4] <= -95) // UNICODE
+ $fld->max_length = $rs->fields[7]/2;
+ else
+ $fld->max_length = $rs->fields[7];
+ } else
+ $fld->max_length = $rs->fields[7];
+ $fld->not_null = !empty($rs->fields[10]);
+ $fld->scale = $rs->fields[8];
+ $retarr[strtoupper($fld->name)] = $fld;
+ } else if (sizeof($retarr)>0)
+ break;
+ $rs->MoveNext();
+ }
+ $rs->Close(); //-- crashes 4.03pl1 -- why?
+
+ if (empty($retarr)) $retarr = false;
+ return $retarr;
+ }
+
+ function Prepare($sql)
+ {
+ if (! $this->_bindInputArray) return $sql; // no binding
+ $stmt = odbc_prepare($this->_connectionID,$sql);
+ if (!$stmt) {
+ // we don't know whether odbc driver is parsing prepared stmts, so just return sql
+ return $sql;
+ }
+ return array($sql,$stmt,false);
+ }
+
+ /* returns queryID or false */
+ function _query($sql,$inputarr=false)
+ {
+ GLOBAL $php_errormsg;
+ if (isset($php_errormsg)) $php_errormsg = '';
+ $this->_error = '';
+
+ if ($inputarr) {
+ if (is_array($sql)) {
+ $stmtid = $sql[1];
+ } else {
+ $stmtid = odbc_prepare($this->_connectionID,$sql);
+
+ if ($stmtid == false) {
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ return false;
+ }
+ }
+
+ if (! odbc_execute($stmtid,$inputarr)) {
+ //@odbc_free_result($stmtid);
+ if ($this->_haserrorfunctions) {
+ $this->_errorMsg = odbc_errormsg();
+ $this->_errorCode = odbc_error();
+ }
+ return false;
+ }
+
+ } else if (is_array($sql)) {
+ $stmtid = $sql[1];
+ if (!odbc_execute($stmtid)) {
+ //@odbc_free_result($stmtid);
+ if ($this->_haserrorfunctions) {
+ $this->_errorMsg = odbc_errormsg();
+ $this->_errorCode = odbc_error();
+ }
+ return false;
+ }
+ } else
+ $stmtid = odbc_exec($this->_connectionID,$sql);
+
+ $this->_lastAffectedRows = 0;
+ if ($stmtid) {
+ if (@odbc_num_fields($stmtid) == 0) {
+ $this->_lastAffectedRows = odbc_num_rows($stmtid);
+ $stmtid = true;
+ } else {
+ $this->_lastAffectedRows = 0;
+ odbc_binmode($stmtid,$this->binmode);
+ odbc_longreadlen($stmtid,$this->maxblobsize);
+ }
+
+ if ($this->_haserrorfunctions) {
+ $this->_errorMsg = '';
+ $this->_errorCode = 0;
+ } else
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ } else {
+ if ($this->_haserrorfunctions) {
+ $this->_errorMsg = odbc_errormsg();
+ $this->_errorCode = odbc_error();
+ } else
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : '';
+ }
+ return $stmtid;
+ }
+
+ /*
+ Insert a null into the blob field of the table first.
+ Then use UpdateBlob to store the blob.
+
+ Usage:
+
+ $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+ */
+ function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+ return $this->Execute("UPDATE $table SET $column=? WHERE $where",array($val)) != false;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ $ret = @odbc_close($this->_connectionID);
+ $this->_connectionID = false;
+ return $ret;
+ }
+
+ function _affectedrows()
+ {
+ return $this->_lastAffectedRows;
+ }
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_odbc extends ADORecordSet {
+
+ var $bind = false;
+ var $databaseType = "odbc";
+ var $dataProvider = "odbc";
+ var $useFetchArray;
+ var $_has_stupid_odbc_fetch_api_change;
+
+ function ADORecordSet_odbc($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+
+ $this->_queryID = $id;
+
+ // the following is required for mysql odbc driver in 4.3.1 -- why?
+ $this->EOF = false;
+ $this->_currentRow = -1;
+ //$this->ADORecordSet($id);
+ }
+
+
+ // returns the field object
+ function &FetchField($fieldOffset = -1)
+ {
+
+ $off=$fieldOffset+1; // offsets begin at 1
+
+ $o= new ADOFieldObject();
+ $o->name = @odbc_field_name($this->_queryID,$off);
+ $o->type = @odbc_field_type($this->_queryID,$off);
+ $o->max_length = @odbc_field_len($this->_queryID,$off);
+ if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
+ else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
+ return $o;
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) 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)]];
+ }
+
+
+ function _initrs()
+ {
+ global $ADODB_COUNTRECS;
+ $this->_numOfRows = ($ADODB_COUNTRECS) ? @odbc_num_rows($this->_queryID) : -1;
+ $this->_numOfFields = @odbc_num_fields($this->_queryID);
+ // some silly drivers such as db2 as/400 and intersystems cache return _numOfRows = 0
+ if ($this->_numOfRows == 0) $this->_numOfRows = -1;
+ //$this->useFetchArray = $this->connection->useFetchArray;
+ $this->_has_stupid_odbc_fetch_api_change = ADODB_PHPVER >= 0x4200;
+ }
+
+ function _seek($row)
+ {
+ return false;
+ }
+
+ // speed up SelectLimit() by switching to ADODB_FETCH_NUM as ADODB_FETCH_ASSOC is emulated
+ function &GetArrayLimit($nrows,$offset=-1)
+ {
+ if ($offset <= 0) {
+ $rs =& $this->GetArray($nrows);
+ return $rs;
+ }
+ $savem = $this->fetchMode;
+ $this->fetchMode = ADODB_FETCH_NUM;
+ $this->Move($offset);
+ $this->fetchMode = $savem;
+
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+
+ $results = array();
+ $cnt = 0;
+ while (!$this->EOF && $nrows != $cnt) {
+ $results[$cnt++] = $this->fields;
+ $this->MoveNext();
+ }
+
+ return $results;
+ }
+
+
+ function MoveNext()
+ {
+ if ($this->_numOfRows != 0 && !$this->EOF) {
+ $this->_currentRow++;
+
+ if ($this->_has_stupid_odbc_fetch_api_change)
+ $rez = @odbc_fetch_into($this->_queryID,$this->fields);
+ else {
+ $row = 0;
+ $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
+ }
+ if ($rez) {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+ }
+ $this->fields = false;
+ $this->EOF = true;
+ return false;
+ }
+
+ function _fetch()
+ {
+
+ if ($this->_has_stupid_odbc_fetch_api_change)
+ $rez = @odbc_fetch_into($this->_queryID,$this->fields);
+ else {
+ $row = 0;
+ $rez = @odbc_fetch_into($this->_queryID,$row,$this->fields);
+ }
+ if ($rez) {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) {
+ $this->fields =& $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ }
+ return true;
+ }
+ $this->fields = false;
+ return false;
+ }
+
+ function _close()
+ {
+ return @odbc_free_result($this->_queryID);
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-odbc_db2.inc.php b/lib/adodb/drivers/adodb-odbc_db2.inc.php
new file mode 100644
index 0000000..3ae91d7
--- /dev/null
+++ b/lib/adodb/drivers/adodb-odbc_db2.inc.php
@@ -0,0 +1,368 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ DB2 data driver. Requires ODBC.
+
+From phpdb list:
+
+Hi Andrew,
+
+thanks a lot for your help. Today we discovered what
+our real problem was:
+
+After "playing" a little bit with the php-scripts that try
+to connect to the IBM DB2, we set the optional parameter
+Cursortype when calling odbc_pconnect(....).
+
+And the exciting thing: When we set the cursor type
+to SQL_CUR_USE_ODBC Cursor Type, then
+the whole query speed up from 1 till 10 seconds
+to 0.2 till 0.3 seconds for 100 records. Amazing!!!
+
+Therfore, PHP is just almost fast as calling the DB2
+from Servlets using JDBC (don't take too much care
+about the speed at whole: the database was on a
+completely other location, so the whole connection
+was made over a slow network connection).
+
+I hope this helps when other encounter the same
+problem when trying to connect to DB2 from
+PHP.
+
+Kind regards,
+Christian Szardenings
+
+2 Oct 2001
+Mark Newnham has discovered that the SQL_CUR_USE_ODBC is not supported by
+IBM's DB2 ODBC driver, so this must be a 3rd party ODBC driver.
+
+From the IBM CLI Reference:
+
+SQL_ATTR_ODBC_CURSORS (DB2 CLI v5)
+This connection attribute is defined by ODBC, but is not supported by DB2
+CLI. Any attempt to set or get this attribute will result in an SQLSTATE of
+HYC00 (Driver not capable).
+
+A 32-bit option specifying how the Driver Manager uses the ODBC cursor
+library.
+
+So I guess this means the message [above] was related to using a 3rd party
+odbc driver.
+
+Setting SQL_CUR_USE_ODBC
+========================
+To set SQL_CUR_USE_ODBC for drivers that require it, do this:
+
+$db = NewADOConnection('odbc_db2');
+$db->curMode = SQL_CUR_USE_ODBC;
+$db->Connect($dsn, $userid, $pwd);
+
+
+
+USING CLI INTERFACE
+===================
+
+I have had reports that the $host and $database params have to be reversed in
+Connect() when using the CLI interface. From Halmai Csongor csongor.halmai#nexum.hu:
+
+> The symptom is that if I change the database engine from postgres or any other to DB2 then the following
+> connection command becomes wrong despite being described this version to be correct in the docs.
+>
+> $connection_object->Connect( $DATABASE_HOST, $DATABASE_AUTH_USER_NAME, $DATABASE_AUTH_PASSWORD, $DATABASE_NAME )
+>
+> In case of DB2 I had to swap the first and last arguments in order to connect properly.
+
+
+System Error 5
+==============
+IF you get a System Error 5 when trying to Connect/Load, it could be a permission problem. Give the user connecting
+to DB2 full rights to the DB2 SQLLIB directory, and place the user in the DBUSERS group.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+if (!defined('ADODB_ODBC_DB2')){
+define('ADODB_ODBC_DB2',1);
+
+class ADODB_ODBC_DB2 extends ADODB_odbc {
+ var $databaseType = "db2";
+ var $concat_operator = '||';
+ var $sysTime = 'CURRENT TIME';
+ var $sysDate = 'CURRENT DATE';
+ var $sysTimeStamp = 'CURRENT TIMESTAMP';
+ // The complete string representation of a timestamp has the form
+ // yyyy-mm-dd-hh.mm.ss.nnnnnn.
+ var $fmtTimeStamp = "'Y-m-d-H.i.s'";
+ var $ansiOuter = true;
+ var $identitySQL = 'values IDENTITY_VAL_LOCAL()';
+ var $_bindInputArray = true;
+ var $hasInsertID = true;
+ var $rsPrefix = 'ADORecordset_odbc_';
+
+ function ADODB_DB2()
+ {
+ if (strncmp(PHP_OS,'WIN',3) === 0) $this->curmode = SQL_CUR_USE_ODBC;
+ $this->ADODB_odbc();
+ }
+
+ function IfNull( $field, $ifNull )
+ {
+ return " COALESCE($field, $ifNull) "; // if DB2 UDB
+ }
+
+ function ServerInfo()
+ {
+ //odbc_setoption($this->_connectionID,1,101 /*SQL_ATTR_ACCESS_MODE*/, 1 /*SQL_MODE_READ_ONLY*/);
+ $vers = $this->GetOne('select versionnumber from sysibm.sysversions');
+ //odbc_setoption($this->_connectionID,1,101, 0 /*SQL_MODE_READ_WRITE*/);
+ return array('description'=>'DB2 ODBC driver', 'version'=>$vers);
+ }
+
+ function _insertid()
+ {
+ return $this->GetOne($this->identitySQL);
+ }
+
+ function RowLock($tables,$where,$flds='1 as ignore')
+ {
+ if ($this->_autocommit) $this->BeginTrans();
+ return $this->GetOne("select $flds from $tables where $where for update");
+ }
+
+ function &MetaTables($ttype=false,$showSchema=false, $qtable="%", $qschema="%")
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $qid = odbc_tables($this->_connectionID, "", $qschema, $qtable, "");
+
+ $rs = new ADORecordSet_odbc($qid);
+
+ $ADODB_FETCH_MODE = $savem;
+ if (!$rs) {
+ $false = false;
+ return $false;
+ }
+ $rs->_has_stupid_odbc_fetch_api_change = $this->_has_stupid_odbc_fetch_api_change;
+
+ $arr =& $rs->GetArray();
+ //print_r($arr);
+
+ $rs->Close();
+ $arr2 = array();
+
+ if ($ttype) {
+ $isview = strncmp($ttype,'V',1) === 0;
+ }
+ for ($i=0; $i < sizeof($arr); $i++) {
+
+ if (!$arr[$i][2]) continue;
+ if (strncmp($arr[$i][1],'SYS',3) === 0) continue;
+
+ $type = $arr[$i][3];
+
+ if ($showSchema) $arr[$i][2] = $arr[$i][1].'.'.$arr[$i][2];
+
+ if ($ttype) {
+ if ($isview) {
+ if (strncmp($type,'V',1) === 0) $arr2[] = $arr[$i][2];
+ } else if (strncmp($type,'T',1) === 0) $arr2[] = $arr[$i][2];
+ } else if (strncmp($type,'S',1) !== 0) $arr2[] = $arr[$i][2];
+ }
+ return $arr2;
+ }
+
+ function &MetaIndexes ($table, $primary = FALSE, $owner=false)
+ {
+ // save old fetch mode
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+ $false = false;
+ // get index details
+ $table = strtoupper($table);
+ $SQL="SELECT NAME, UNIQUERULE, COLNAMES FROM SYSIBM.SYSINDEXES WHERE TBNAME='$table'";
+ if ($primary)
+ $SQL.= " AND UNIQUERULE='P'";
+ $rs = $this->Execute($SQL);
+ if (!is_object($rs)) {
+ if (isset($savem))
+ $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ return $false;
+ }
+ $indexes = array ();
+ // parse index data into array
+ while ($row = $rs->FetchRow()) {
+ $indexes[$row[0]] = array(
+ 'unique' => ($row[1] == 'U' || $row[1] == 'P'),
+ 'columns' => array()
+ );
+ $cols = ltrim($row[2],'+');
+ $indexes[$row[0]]['columns'] = explode('+', $cols);
+ }
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ }
+ return $indexes;
+ }
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ // use right() and replace() ?
+ if (!$col) $col = $this->sysDate;
+ $s = '';
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ if ($s) $s .= '||';
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= "char(year($col))";
+ break;
+ case 'M':
+ $s .= "substr(monthname($col),1,3)";
+ break;
+ case 'm':
+ $s .= "right(digits(month($col)),2)";
+ break;
+ case 'D':
+ case 'd':
+ $s .= "right(digits(day($col)),2)";
+ break;
+ case 'H':
+ case 'h':
+ if ($col != $this->sysDate) $s .= "right(digits(hour($col)),2)";
+ else $s .= "''";
+ break;
+ case 'i':
+ case 'I':
+ if ($col != $this->sysDate)
+ $s .= "right(digits(minute($col)),2)";
+ else $s .= "''";
+ break;
+ case 'S':
+ case 's':
+ if ($col != $this->sysDate)
+ $s .= "right(digits(second($col)),2)";
+ else $s .= "''";
+ break;
+ default:
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ $s .= $this->qstr($ch);
+ }
+ }
+ return $s;
+ }
+
+
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputArr=false)
+ {
+ $nrows = (integer) $nrows;
+ if ($offset <= 0) {
+ // could also use " OPTIMIZE FOR $nrows ROWS "
+ if ($nrows >= 0) $sql .= " FETCH FIRST $nrows ROWS ONLY ";
+ $rs =& $this->Execute($sql,$inputArr);
+ } else {
+ if ($offset > 0 && $nrows < 0);
+ else {
+ $nrows += $offset;
+ $sql .= " FETCH FIRST $nrows ROWS ONLY ";
+ }
+ $rs =& ADOConnection::SelectLimit($sql,-1,$offset,$inputArr);
+ }
+
+ return $rs;
+ }
+
+};
+
+
+class ADORecordSet_odbc_db2 extends ADORecordSet_odbc {
+
+ var $databaseType = "db2";
+
+ function ADORecordSet_db2($id,$mode=false)
+ {
+ $this->ADORecordSet_odbc($id,$mode);
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+ switch (strtoupper($t)) {
+ case 'VARCHAR':
+ case 'CHAR':
+ case 'CHARACTER':
+ case 'C':
+ if ($len <= $this->blobSize) return 'C';
+
+ case 'LONGCHAR':
+ case 'TEXT':
+ case 'CLOB':
+ case 'DBCLOB': // double-byte
+ case 'X':
+ return 'X';
+
+ case 'BLOB':
+ case 'GRAPHIC':
+ case 'VARGRAPHIC':
+ return 'B';
+
+ case 'DATE':
+ case 'D':
+ return 'D';
+
+ case 'TIME':
+ case 'TIMESTAMP':
+ case 'T':
+ return 'T';
+
+ //case 'BOOLEAN':
+ //case 'BIT':
+ // return 'L';
+
+ //case 'COUNTER':
+ // return 'R';
+
+ case 'INT':
+ case 'INTEGER':
+ case 'BIGINT':
+ case 'SMALLINT':
+ case 'I':
+ return 'I';
+
+ default: return 'N';
+ }
+ }
+}
+
+} //define
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-odbc_mssql.inc.php b/lib/adodb/drivers/adodb-odbc_mssql.inc.php
new file mode 100644
index 0000000..2181739
--- /dev/null
+++ b/lib/adodb/drivers/adodb-odbc_mssql.inc.php
@@ -0,0 +1,306 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ MSSQL support via ODBC. Requires ODBC. Works on Windows and Unix.
+ For Unix configuration, see http://phpbuilder.com/columns/alberto20000919.php3
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+
+
+class ADODB_odbc_mssql extends ADODB_odbc {
+ var $databaseType = 'odbc_mssql';
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $_bindInputArray = true;
+ var $metaTablesSQL="select name,case when type='U' then 'T' else 'V' end from sysobjects where (type='U' or type='V') and (name not in ('sysallocations','syscolumns','syscomments','sysdepends','sysfilegroups','sysfiles','sysfiles1','sysforeignkeys','sysfulltextcatalogs','sysindexes','sysindexkeys','sysmembers','sysobjects','syspermissions','sysprotects','sysreferences','systypes','sysusers','sysalternates','sysconstraints','syssegments','REFERENTIAL_CONSTRAINTS','CHECK_CONSTRAINTS','CONSTRAINT_TABLE_USAGE','CONSTRAINT_COLUMN_USAGE','VIEWS','VIEW_TABLE_USAGE','VIEW_COLUMN_USAGE','SCHEMATA','TABLES','TABLE_CONSTRAINTS','TABLE_PRIVILEGES','COLUMNS','COLUMN_DOMAIN_USAGE','COLUMN_PRIVILEGES','DOMAINS','DOMAIN_CONSTRAINTS','KEY_COLUMN_USAGE'))";
+ var $metaColumnsSQL = "select c.name,t.name,c.length from syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id where o.name='%s'";
+ var $hasTop = 'top'; // support mssql/interbase SELECT TOP 10 * FROM TABLE
+ var $sysDate = 'GetDate()';
+ var $sysTimeStamp = 'GetDate()';
+ var $leftOuter = '*=';
+ var $rightOuter = '=*';
+ var $substr = 'substring';
+ var $length = 'len';
+ var $ansiOuter = true; // for mssql7 or later
+ var $identitySQL = 'select @@IDENTITY'; // 'select SCOPE_IDENTITY'; # for mssql 2000
+ var $hasInsertID = true;
+ var $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL OFF'; # When SET CONCAT_NULL_YIELDS_NULL is ON,
+ # concatenating a null value with a string yields a NULL result
+
+ function ADODB_odbc_mssql()
+ {
+ $this->ADODB_odbc();
+ //$this->curmode = SQL_CUR_USE_ODBC;
+ }
+
+ // crashes php...
+ function ServerInfo()
+ {
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $row = $this->GetRow("execute sp_server_info 2");
+ $ADODB_FETCH_MODE = $save;
+ if (!is_array($row)) return false;
+ $arr['description'] = $row[2];
+ $arr['version'] = ADOConnection::_findvers($arr['description']);
+ return $arr;
+ }
+
+ function IfNull( $field, $ifNull )
+ {
+ return " ISNULL($field, $ifNull) "; // if MS SQL Server
+ }
+
+ function _insertid()
+ {
+ // SCOPE_IDENTITY()
+ // Returns the last IDENTITY value inserted into an IDENTITY column in
+ // the same scope. A scope is a module -- a stored procedure, trigger,
+ // function, or batch. Thus, two statements are in the same scope if
+ // they are in the same stored procedure, function, or batch.
+ return $this->GetOne($this->identitySQL);
+ }
+
+
+ function MetaForeignKeys($table, $owner=false, $upper=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $table = $this->qstr(strtoupper($table));
+
+ $sql =
+"select object_name(constid) as constraint_name,
+ col_name(fkeyid, fkey) as column_name,
+ object_name(rkeyid) as referenced_table_name,
+ col_name(rkeyid, rkey) as referenced_column_name
+from sysforeignkeys
+where upper(object_name(fkeyid)) = $table
+order by constraint_name, referenced_table_name, keyno";
+
+ $constraints =& $this->GetArray($sql);
+
+ $ADODB_FETCH_MODE = $save;
+
+ $arr = false;
+ foreach($constraints as $constr) {
+ //print_r($constr);
+ $arr[$constr[0]][$constr[2]][] = $constr[1].'='.$constr[3];
+ }
+ if (!$arr) return false;
+
+ $arr2 = false;
+
+ foreach($arr as $k => $v) {
+ foreach($v as $a => $b) {
+ if ($upper) $a = strtoupper($a);
+ $arr2[$a] = $b;
+ }
+ }
+ return $arr2;
+ }
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ if ($mask) {$this->debug=1;
+ $save = $this->metaTablesSQL;
+ $mask = $this->qstr($mask);
+ $this->metaTablesSQL .= " AND name like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ if ($mask) {
+ $this->metaTablesSQL = $save;
+ }
+ return $ret;
+ }
+
+ function &MetaColumns($table)
+ {
+ $arr = ADOConnection::MetaColumns($table);
+ return $arr;
+ }
+
+
+ function &MetaIndexes($table,$primary=false)
+ {
+ $table = $this->qstr($table);
+
+ $sql = "SELECT i.name AS ind_name, C.name AS col_name, USER_NAME(O.uid) AS Owner, c.colid, k.Keyno,
+ CASE WHEN I.indid BETWEEN 1 AND 254 AND (I.status & 2048 = 2048 OR I.Status = 16402 AND O.XType = 'V') THEN 1 ELSE 0 END AS IsPK,
+ CASE WHEN I.status & 2 = 2 THEN 1 ELSE 0 END AS IsUnique
+ FROM dbo.sysobjects o INNER JOIN dbo.sysindexes I ON o.id = i.id
+ INNER JOIN dbo.sysindexkeys K ON I.id = K.id AND I.Indid = K.Indid
+ INNER JOIN dbo.syscolumns c ON K.id = C.id AND K.colid = C.Colid
+ WHERE LEFT(i.name, 8) <> '_WA_Sys_' AND o.status >= 0 AND O.Name LIKE $table
+ ORDER BY O.name, I.Name, K.keyno";
+
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+
+ $rs = $this->Execute($sql);
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ if (!is_object($rs)) {
+ return FALSE;
+ }
+
+ $indexes = array();
+ while ($row = $rs->FetchRow()) {
+ if (!$primary && $row[5]) continue;
+
+ $indexes[$row[0]]['unique'] = $row[6];
+ $indexes[$row[0]]['columns'][] = $row[1];
+ }
+ return $indexes;
+ }
+
+ function _query($sql,$inputarr)
+ {
+ if (is_string($sql)) $sql = str_replace('||','+',$sql);
+ return ADODB_odbc::_query($sql,$inputarr);
+ }
+
+ function SetTransactionMode( $transaction_mode )
+ {
+ $this->_transmode = $transaction_mode;
+ if (empty($transaction_mode)) {
+ $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+ return;
+ }
+ if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+ $this->Execute("SET TRANSACTION ".$transaction_mode);
+ }
+
+ // "Stein-Aksel Basma" <basma@accelero.no>
+ // tested with MSSQL 2000
+ function &MetaPrimaryKeys($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $schema = '';
+ $this->_findschema($table,$schema);
+ //if (!$schema) $schema = $this->database;
+ if ($schema) $schema = "and k.table_catalog like '$schema%'";
+
+ $sql = "select distinct k.column_name,ordinal_position from information_schema.key_column_usage k,
+ information_schema.table_constraints tc
+ where tc.constraint_name = k.constraint_name and tc.constraint_type =
+ 'PRIMARY KEY' and k.table_name = '$table' $schema order by ordinal_position ";
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $a = $this->GetCol($sql);
+ $ADODB_FETCH_MODE = $savem;
+
+ if ($a && sizeof($a)>0) return $a;
+ $false = false;
+ return $false;
+ }
+
+ function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
+ {
+ if ($nrows > 0 && $offset <= 0) {
+ $sql = preg_replace(
+ '/(^\s*select\s+(distinctrow|distinct)?)/i','\\1 '.$this->hasTop." $nrows ",$sql);
+ $rs =& $this->Execute($sql,$inputarr);
+ } else
+ $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+
+ return $rs;
+ }
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysTimeStamp;
+ $s = '';
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ if ($s) $s .= '+';
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= "datename(yyyy,$col)";
+ break;
+ case 'M':
+ $s .= "convert(char(3),$col,0)";
+ break;
+ case 'm':
+ $s .= "replace(str(month($col),2),' ','0')";
+ break;
+ case 'Q':
+ case 'q':
+ $s .= "datename(quarter,$col)";
+ break;
+ case 'D':
+ case 'd':
+ $s .= "replace(str(day($col),2),' ','0')";
+ break;
+ case 'h':
+ $s .= "substring(convert(char(14),$col,0),13,2)";
+ break;
+
+ case 'H':
+ $s .= "replace(str(datepart(hh,$col),2),' ','0')";
+ break;
+
+ case 'i':
+ $s .= "replace(str(datepart(mi,$col),2),' ','0')";
+ break;
+ case 's':
+ $s .= "replace(str(datepart(ss,$col),2),' ','0')";
+ break;
+ case 'a':
+ case 'A':
+ $s .= "substring(convert(char(19),$col,0),18,2)";
+ break;
+
+ default:
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ $s .= $this->qstr($ch);
+ break;
+ }
+ }
+ return $s;
+ }
+
+}
+
+class ADORecordSet_odbc_mssql extends ADORecordSet_odbc {
+
+ var $databaseType = 'odbc_mssql';
+
+ function ADORecordSet_odbc_mssql($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbc($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-odbc_oracle.inc.php b/lib/adodb/drivers/adodb-odbc_oracle.inc.php
new file mode 100644
index 0000000..cb29f0b
--- /dev/null
+++ b/lib/adodb/drivers/adodb-odbc_oracle.inc.php
@@ -0,0 +1,115 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Oracle support via ODBC. Requires ODBC. Works on Windows.
+*/
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+
+
+class ADODB_odbc_oracle extends ADODB_odbc {
+ var $databaseType = 'odbc_oracle';
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $concat_operator='||';
+ var $fmtDate = "'Y-m-d 00:00:00'";
+ var $fmtTimeStamp = "'Y-m-d h:i:sA'";
+ var $metaTablesSQL = 'select table_name from cat';
+ var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno";
+ var $sysDate = "TRUNC(SYSDATE)";
+ var $sysTimeStamp = 'SYSDATE';
+
+ //var $_bindInputArray = false;
+
+ function ADODB_odbc_oracle()
+ {
+ $this->ADODB_odbc();
+ }
+
+ function &MetaTables()
+ {
+ $false = false;
+ $rs = $this->Execute($this->metaTablesSQL);
+ if ($rs === false) return $false;
+ $arr = $rs->GetArray();
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ $arr2[] = $arr[$i][0];
+ }
+ $rs->Close();
+ return $arr2;
+ }
+
+ function &MetaColumns($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
+ if ($rs === false) {
+ $false = false;
+ return $false;
+ }
+ $retarr = array();
+ while (!$rs->EOF) { //print_r($rs->fields);
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+ $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;
+ }
+
+ // returns true or false
+ function _connect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ global $php_errormsg;
+
+ $php_errormsg = '';
+ $this->_connectionID = odbc_connect($argDSN,$argUsername,$argPassword,SQL_CUR_USE_ODBC );
+ $this->_errorMsg = $php_errormsg;
+
+ $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
+ //if ($this->_connectionID) odbc_autocommit($this->_connectionID,true);
+ return $this->_connectionID != false;
+ }
+ // returns true or false
+ function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ global $php_errormsg;
+ $php_errormsg = '';
+ $this->_connectionID = odbc_pconnect($argDSN,$argUsername,$argPassword,SQL_CUR_USE_ODBC );
+ $this->_errorMsg = $php_errormsg;
+
+ $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
+ //if ($this->_connectionID) odbc_autocommit($this->_connectionID,true);
+ return $this->_connectionID != false;
+ }
+}
+
+class ADORecordSet_odbc_oracle extends ADORecordSet_odbc {
+
+ var $databaseType = 'odbc_oracle';
+
+ function ADORecordSet_odbc_oracle($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbc($id,$mode);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-odbtp.inc.php b/lib/adodb/drivers/adodb-odbtp.inc.php
new file mode 100644
index 0000000..6f52ae7
--- /dev/null
+++ b/lib/adodb/drivers/adodb-odbtp.inc.php
@@ -0,0 +1,743 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+ Latest version is available at http://adodb.sourceforge.net
+*/
+// Code contributed by "stefan bogdan" <sbogdan#rsb.ro>
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+define("_ADODB_ODBTP_LAYER", 2 );
+
+class ADODB_odbtp extends ADOConnection{
+ var $databaseType = "odbtp";
+ var $dataProvider = "odbtp";
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $odbc_driver = 0;
+ var $hasAffectedRows = true;
+ var $hasInsertID = false;
+ var $hasGenID = true;
+ var $hasMoveFirst = true;
+
+ var $_genSeqSQL = "create table %s (seq_name char(30) not null unique , seq_value integer not null)";
+ var $_dropSeqSQL = "delete from adodb_seq where seq_name = '%s'";
+ var $_bindInputArray = false;
+ var $_useUnicodeSQL = false;
+ var $_canPrepareSP = false;
+ var $_dontPoolDBC = true;
+
+ function ADODB_odbtp()
+ {
+ }
+
+ function ServerInfo()
+ {
+ return array('description' => @odbtp_get_attr( ODB_ATTR_DBMSNAME, $this->_connectionID),
+ 'version' => @odbtp_get_attr( ODB_ATTR_DBMSVER, $this->_connectionID));
+ }
+
+ function ErrorMsg()
+ {
+ if (empty($this->_connectionID)) return @odbtp_last_error();
+ return @odbtp_last_error($this->_connectionID);
+ }
+
+ function ErrorNo()
+ {
+ if (empty($this->_connectionID)) return @odbtp_last_error_state();
+ return @odbtp_last_error_state($this->_connectionID);
+ }
+
+ function _insertid()
+ {
+ // SCOPE_IDENTITY()
+ // Returns the last IDENTITY value inserted into an IDENTITY column in
+ // the same scope. A scope is a module -- a stored procedure, trigger,
+ // function, or batch. Thus, two statements are in the same scope if
+ // they are in the same stored procedure, function, or batch.
+ return $this->GetOne($this->identitySQL);
+ }
+
+ function _affectedrows()
+ {
+ if ($this->_queryID) {
+ return @odbtp_affected_rows ($this->_queryID);
+ } else
+ return 0;
+ }
+
+ function CreateSequence($seqname='adodbseq',$start=1)
+ {
+ //verify existence
+ $num = $this->GetOne("select seq_value from adodb_seq");
+ $seqtab='adodb_seq';
+ if( $this->odbc_driver == ODB_DRIVER_FOXPRO ) {
+ $path = @odbtp_get_attr( ODB_ATTR_DATABASENAME, $this->_connectionID );
+ //if using vfp dbc file
+ if( !strcasecmp(strrchr($path, '.'), '.dbc') )
+ $path = substr($path,0,strrpos($path,'\/'));
+ $seqtab = $path . '/' . $seqtab;
+ }
+ if($num == false) {
+ if (empty($this->_genSeqSQL)) return false;
+ $ok = $this->Execute(sprintf($this->_genSeqSQL ,$seqtab));
+ }
+ $num = $this->GetOne("select seq_value from adodb_seq where seq_name='$seqname'");
+ if ($num) {
+ return false;
+ }
+ $start -= 1;
+ return $this->Execute("insert into adodb_seq values('$seqname',$start)");
+ }
+
+ function DropSequence($seqname)
+ {
+ if (empty($this->_dropSeqSQL)) return false;
+ return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+ }
+
+ function GenID($seq='adodbseq',$start=1)
+ {
+ $seqtab='adodb_seq';
+ if( $this->odbc_driver == ODB_DRIVER_FOXPRO) {
+ $path = @odbtp_get_attr( ODB_ATTR_DATABASENAME, $this->_connectionID );
+ //if using vfp dbc file
+ if( !strcasecmp(strrchr($path, '.'), '.dbc') )
+ $path = substr($path,0,strrpos($path,'\/'));
+ $seqtab = $path . '/' . $seqtab;
+ }
+ $MAXLOOPS = 100;
+ while (--$MAXLOOPS>=0) {
+ $num = $this->GetOne("select seq_value from adodb_seq where seq_name='$seq'");
+ if ($num === false) {
+ //verify if abodb_seq table exist
+ $ok = $this->GetOne("select seq_value from adodb_seq ");
+ if(!$ok) {
+ //creating the sequence table adodb_seq
+ $this->Execute(sprintf($this->_genSeqSQL ,$seqtab));
+ }
+ $start -= 1;
+ $num = '0';
+ $ok = $this->Execute("insert into adodb_seq values('$seq',$start)");
+ if (!$ok) return false;
+ }
+ $ok = $this->Execute("update adodb_seq set seq_value=seq_value+1 where seq_name='$seq'");
+ if($ok) {
+ $num += 1;
+ $this->genID = $num;
+ return $num;
+ }
+ }
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
+ }
+ return false;
+ }
+
+ //example for $UserOrDSN
+ //for visual fox : DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBF;SOURCEDB=c:\YourDbfFileDir;EXCLUSIVE=NO;
+ //for visual fox dbc: DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBC;SOURCEDB=c:\YourDbcFileDir\mydb.dbc;EXCLUSIVE=NO;
+ //for access : DRIVER={Microsoft Access Driver (*.mdb)};DBQ=c:\path_to_access_db\base_test.mdb;UID=root;PWD=;
+ //for mssql : DRIVER={SQL Server};SERVER=myserver;UID=myuid;PWD=mypwd;DATABASE=OdbtpTest;
+ //if uid & pwd can be separate
+ function _connect($HostOrInterface, $UserOrDSN='', $argPassword='', $argDatabase='')
+ {
+ $this->_connectionID = odbtp_connect($HostOrInterface,$UserOrDSN,$argPassword,$argDatabase);
+ if ($this->_connectionID === false) {
+ $this->_errorMsg = $this->ErrorMsg() ;
+ return false;
+ }
+
+ odbtp_convert_datetime($this->_connectionID,true);
+
+ if ($this->_dontPoolDBC) {
+ if (function_exists('odbtp_dont_pool_dbc'))
+ @odbtp_dont_pool_dbc($this->_connectionID);
+ }
+ else {
+ $this->_dontPoolDBC = true;
+ }
+ $this->odbc_driver = @odbtp_get_attr(ODB_ATTR_DRIVER, $this->_connectionID);
+ $dbms = strtolower(@odbtp_get_attr(ODB_ATTR_DBMSNAME, $this->_connectionID));
+ $this->odbc_name = $dbms;
+
+ // Account for inconsistent DBMS names
+ if( $this->odbc_driver == ODB_DRIVER_ORACLE )
+ $dbms = 'oracle';
+ else if( $this->odbc_driver == ODB_DRIVER_SYBASE )
+ $dbms = 'sybase';
+
+ // Set DBMS specific attributes
+ switch( $dbms ) {
+ case 'microsoft sql server':
+ $this->databaseType = 'odbtp_mssql';
+ $this->fmtDate = "'Y-m-d'";
+ $this->fmtTimeStamp = "'Y-m-d h:i:sA'";
+ $this->sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
+ $this->sysTimeStamp = 'GetDate()';
+ $this->ansiOuter = true;
+ $this->leftOuter = '*=';
+ $this->rightOuter = '=*';
+ $this->hasTop = 'top';
+ $this->hasInsertID = true;
+ $this->hasTransactions = true;
+ $this->_bindInputArray = true;
+ $this->_canSelectDb = true;
+ $this->substr = "substring";
+ $this->length = 'len';
+ $this->identitySQL = 'select @@IDENTITY';
+ $this->metaDatabasesSQL = "select name from master..sysdatabases where name <> 'master'";
+ $this->_canPrepareSP = true;
+ break;
+ case 'access':
+ $this->databaseType = 'odbtp_access';
+ $this->fmtDate = "#Y-m-d#";
+ $this->fmtTimeStamp = "#Y-m-d h:i:sA#";
+ $this->sysDate = "FORMAT(NOW,'yyyy-mm-dd')";
+ $this->sysTimeStamp = 'NOW';
+ $this->hasTop = 'top';
+ $this->hasTransactions = false;
+ $this->_canPrepareSP = true; // For MS Access only.
+ break;
+ case 'visual foxpro':
+ $this->databaseType = 'odbtp_vfp';
+ $this->fmtDate = "{^Y-m-d}";
+ $this->fmtTimeStamp = "{^Y-m-d, h:i:sA}";
+ $this->sysDate = 'date()';
+ $this->sysTimeStamp = 'datetime()';
+ $this->ansiOuter = true;
+ $this->hasTop = 'top';
+ $this->hasTransactions = false;
+ $this->replaceQuote = "'+chr(39)+'";
+ $this->true = '.T.';
+ $this->false = '.F.';
+
+ break;
+ case 'oracle':
+ $this->databaseType = 'odbtp_oci8';
+ $this->fmtDate = "'Y-m-d 00:00:00'";
+ $this->fmtTimeStamp = "'Y-m-d h:i:sA'";
+ $this->sysDate = 'TRUNC(SYSDATE)';
+ $this->sysTimeStamp = 'SYSDATE';
+ $this->hasTransactions = true;
+ $this->_bindInputArray = true;
+ $this->concat_operator = '||';
+ break;
+ case 'sybase':
+ $this->databaseType = 'odbtp_sybase';
+ $this->fmtDate = "'Y-m-d'";
+ $this->fmtTimeStamp = "'Y-m-d H:i:s'";
+ $this->sysDate = 'GetDate()';
+ $this->sysTimeStamp = 'GetDate()';
+ $this->leftOuter = '*=';
+ $this->rightOuter = '=*';
+ $this->hasInsertID = true;
+ $this->hasTransactions = true;
+ $this->identitySQL = 'select @@IDENTITY';
+ break;
+ default:
+ $this->databaseType = 'odbtp';
+ if( @odbtp_get_attr(ODB_ATTR_TXNCAPABLE, $this->_connectionID) )
+ $this->hasTransactions = true;
+ else
+ $this->hasTransactions = false;
+ }
+ @odbtp_set_attr(ODB_ATTR_FULLCOLINFO, TRUE, $this->_connectionID );
+
+ if ($this->_useUnicodeSQL )
+ @odbtp_set_attr(ODB_ATTR_UNICODESQL, TRUE, $this->_connectionID);
+
+ return true;
+ }
+
+ function _pconnect($HostOrInterface, $UserOrDSN='', $argPassword='', $argDatabase='')
+ {
+ $this->_dontPoolDBC = false;
+ return $this->_connect($HostOrInterface, $UserOrDSN, $argPassword, $argDatabase);
+ }
+
+ function SelectDB($dbName)
+ {
+ if (!@odbtp_select_db($dbName, $this->_connectionID)) {
+ return false;
+ }
+ $this->database = $dbName;
+ $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
+ return true;
+ }
+
+ function &MetaTables($ttype='',$showSchema=false,$mask=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false) $savefm = $this->SetFetchMode(false);
+
+ $arr =& $this->GetArray("||SQLTables||||$ttype");
+
+ if (isset($savefm)) $this->SetFetchMode($savefm);
+ $ADODB_FETCH_MODE = $savem;
+
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if ($arr[$i][3] == 'SYSTEM TABLE' ) continue;
+ if ($arr[$i][2])
+ $arr2[] = $showSchema && $arr[$i][1]? $arr[$i][1].'.'.$arr[$i][2] : $arr[$i][2];
+ }
+ return $arr2;
+ }
+
+ function &MetaColumns($table,$upper=true)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $schema = false;
+ $this->_findschema($table,$schema);
+ if ($upper) $table = strtoupper($table);
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false) $savefm = $this->SetFetchMode(false);
+
+ $rs = $this->Execute( "||SQLColumns||$schema|$table" );
+
+ if (isset($savefm)) $this->SetFetchMode($savefm);
+ $ADODB_FETCH_MODE = $savem;
+
+ if (!$rs || $rs->EOF) {
+ $false = false;
+ return $false;
+ }
+ $retarr = array();
+ while (!$rs->EOF) {
+ //print_r($rs->fields);
+ if (strtoupper($rs->fields[2]) == $table) {
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[3];
+ $fld->type = $rs->fields[5];
+ $fld->max_length = $rs->fields[6];
+ $fld->not_null = !empty($rs->fields[9]);
+ $fld->scale = $rs->fields[7];
+ if (isset($rs->fields[12])) // vfp does not have field 12
+ if (!is_null($rs->fields[12])) {
+ $fld->has_default = true;
+ $fld->default_value = $rs->fields[12];
+ }
+ $retarr[strtoupper($fld->name)] = $fld;
+ } else if (!empty($retarr))
+ break;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ return $retarr;
+ }
+
+ function &MetaPrimaryKeys($table, $owner='')
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $arr =& $this->GetArray("||SQLPrimaryKeys||$owner|$table");
+ $ADODB_FETCH_MODE = $savem;
+
+ //print_r($arr);
+ $arr2 = array();
+ for ($i=0; $i < sizeof($arr); $i++) {
+ if ($arr[$i][3]) $arr2[] = $arr[$i][3];
+ }
+ return $arr2;
+ }
+
+ function &MetaForeignKeys($table, $owner='', $upper=false)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $savem = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $constraints =& $this->GetArray("||SQLForeignKeys|||||$owner|$table");
+ $ADODB_FETCH_MODE = $savem;
+
+ $arr = false;
+ foreach($constraints as $constr) {
+ //print_r($constr);
+ $arr[$constr[11]][$constr[2]][] = $constr[7].'='.$constr[3];
+ }
+ if (!$arr) {
+ $false = false;
+ return $false;
+ }
+
+ $arr2 = array();
+
+ foreach($arr as $k => $v) {
+ foreach($v as $a => $b) {
+ if ($upper) $a = strtoupper($a);
+ $arr2[$a] = $b;
+ }
+ }
+ return $arr2;
+ }
+
+ function BeginTrans()
+ {
+ if (!$this->hasTransactions) return false;
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->autoCommit = false;
+ if (defined('ODB_TXN_DEFAULT'))
+ $txn = ODB_TXN_DEFAULT;
+ else
+ $txn = ODB_TXN_READUNCOMMITTED;
+ $rs = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS,$txn,$this->_connectionID);
+ if(!$rs) return false;
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->autoCommit = true;
+ if( ($ret = @odbtp_commit($this->_connectionID)) )
+ $ret = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE, $this->_connectionID);//set transaction off
+ return $ret;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->autoCommit = true;
+ if( ($ret = @odbtp_rollback($this->_connectionID)) )
+ $ret = @odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE, $this->_connectionID);//set transaction off
+ return $ret;
+ }
+
+ function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
+ {
+ // TOP requires ORDER BY for Visual FoxPro
+ if( $this->odbc_driver == ODB_DRIVER_FOXPRO ) {
+ if (!preg_match('/ORDER[ \t\r\n]+BY/is',$sql)) $sql .= ' ORDER BY 1';
+ }
+ $ret =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+ return $ret;
+ }
+
+ function Prepare($sql)
+ {
+ if (! $this->_bindInputArray) return $sql; // no binding
+ $stmt = @odbtp_prepare($sql,$this->_connectionID);
+ if (!$stmt) {
+ // print "Prepare Error for ($sql) ".$this->ErrorMsg()."<br>";
+ return $sql;
+ }
+ return array($sql,$stmt,false);
+ }
+
+ function PrepareSP($sql)
+ {
+ if (!$this->_canPrepareSP) return $sql; // Can't prepare procedures
+
+ $stmt = @odbtp_prepare_proc($sql,$this->_connectionID);
+ if (!$stmt) return false;
+ return array($sql,$stmt);
+ }
+
+ /*
+ Usage:
+ $stmt = $db->PrepareSP('SP_RUNSOMETHING'); -- takes 2 params, @myid and @group
+
+ # note that the parameter does not have @ in front!
+ $db->Parameter($stmt,$id,'myid');
+ $db->Parameter($stmt,$group,'group',false,64);
+ $db->Parameter($stmt,$group,'photo',false,100000,ODB_BINARY);
+ $db->Execute($stmt);
+
+ @param $stmt Statement returned by Prepare() or PrepareSP().
+ @param $var PHP variable to bind to. Can set to null (for isNull support).
+ @param $name Name of stored procedure variable name to bind to.
+ @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in odbtp.
+ @param [$maxLen] Holds an maximum length of the variable.
+ @param [$type] The data type of $var. Legal values depend on driver.
+
+ See odbtp_attach_param documentation at http://odbtp.sourceforge.net.
+ */
+ function Parameter(&$stmt, &$var, $name, $isOutput=false, $maxLen=0, $type=0)
+ {
+ if ( $this->odbc_driver == ODB_DRIVER_JET ) {
+ $name = '['.$name.']';
+ if( !$type && $this->_useUnicodeSQL
+ && @odbtp_param_bindtype($stmt[1], $name) == ODB_CHAR )
+ {
+ $type = ODB_WCHAR;
+ }
+ }
+ else {
+ $name = '@'.$name;
+ }
+ return @odbtp_attach_param($stmt[1], $name, $var, $type, $maxLen);
+ }
+
+ /*
+ Insert a null into the blob field of the table first.
+ Then use UpdateBlob to store the blob.
+
+ Usage:
+
+ $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+ */
+
+ function UpdateBlob($table,$column,$val,$where,$blobtype='image')
+ {
+ $sql = "UPDATE $table SET $column = ? WHERE $where";
+ if( !($stmt = @odbtp_prepare($sql, $this->_connectionID)) )
+ return false;
+ if( !@odbtp_input( $stmt, 1, ODB_BINARY, 1000000, $blobtype ) )
+ return false;
+ if( !@odbtp_set( $stmt, 1, $val ) )
+ return false;
+ return @odbtp_execute( $stmt ) != false;
+ }
+
+ function IfNull( $field, $ifNull )
+ {
+ switch( $this->odbc_driver ) {
+ case ODB_DRIVER_MSSQL:
+ return " ISNULL($field, $ifNull) ";
+ case ODB_DRIVER_JET:
+ return " IIF(IsNull($field), $ifNull, $field) ";
+ }
+ return " CASE WHEN $field is null THEN $ifNull ELSE $field END ";
+ }
+
+ function _query($sql,$inputarr=false)
+ {
+ global $php_errormsg;
+
+ if ($inputarr) {
+ if (is_array($sql)) {
+ $stmtid = $sql[1];
+ } else {
+ $stmtid = @odbtp_prepare($sql,$this->_connectionID);
+ if ($stmtid == false) {
+ $this->_errorMsg = $php_errormsg;
+ return false;
+ }
+ }
+ $num_params = @odbtp_num_params( $stmtid );
+ for( $param = 1; $param <= $num_params; $param++ ) {
+ @odbtp_input( $stmtid, $param );
+ @odbtp_set( $stmtid, $param, $inputarr[$param-1] );
+ }
+ if (!@odbtp_execute($stmtid) ) {
+ return false;
+ }
+ } else if (is_array($sql)) {
+ $stmtid = $sql[1];
+ if (!@odbtp_execute($stmtid)) {
+ return false;
+ }
+ } else {
+ $stmtid = odbtp_query($sql,$this->_connectionID);
+ }
+ $this->_lastAffectedRows = 0;
+ if ($stmtid) {
+ $this->_lastAffectedRows = @odbtp_affected_rows($stmtid);
+ }
+ return $stmtid;
+ }
+
+ function _close()
+ {
+ $ret = @odbtp_close($this->_connectionID);
+ $this->_connectionID = false;
+ return $ret;
+ }
+}
+
+class ADORecordSet_odbtp extends ADORecordSet {
+
+ var $databaseType = 'odbtp';
+ var $canSeek = true;
+
+ function ADORecordSet_odbtp($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+ $this->ADORecordSet($queryID);
+ }
+
+ function _initrs()
+ {
+ $this->_numOfFields = @odbtp_num_fields($this->_queryID);
+ if (!($this->_numOfRows = @odbtp_num_rows($this->_queryID)))
+ $this->_numOfRows = -1;
+
+ if (!$this->connection->_useUnicodeSQL) return;
+
+ if ($this->connection->odbc_driver == ODB_DRIVER_JET) {
+ if (!@odbtp_get_attr(ODB_ATTR_MAPCHARTOWCHAR,
+ $this->connection->_connectionID))
+ {
+ for ($f = 0; $f < $this->_numOfFields; $f++) {
+ if (@odbtp_field_bindtype($this->_queryID, $f) == ODB_CHAR)
+ @odbtp_bind_field($this->_queryID, $f, ODB_WCHAR);
+ }
+ }
+ }
+ }
+
+ function &FetchField($fieldOffset = 0)
+ {
+ $off=$fieldOffset; // offsets begin at 0
+ $o= new ADOFieldObject();
+ $o->name = @odbtp_field_name($this->_queryID,$off);
+ $o->type = @odbtp_field_type($this->_queryID,$off);
+ $o->max_length = @odbtp_field_length($this->_queryID,$off);
+ if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
+ else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
+ return $o;
+ }
+
+ function _seek($row)
+ {
+ return @odbtp_data_seek($this->_queryID, $row);
+ }
+
+ function fields($colname)
+ {
+ if ($this->fetchMode & ADODB_FETCH_ASSOC) return $this->fields[$colname];
+
+ if (!$this->bind) {
+ $this->bind = array();
+ for ($i=0; $i < $this->_numOfFields; $i++) {
+ $name = @odbtp_field_name( $this->_queryID, $i );
+ $this->bind[strtoupper($name)] = $i;
+ }
+ }
+ return $this->fields[$this->bind[strtoupper($colname)]];
+ }
+
+ function _fetch_odbtp($type=0)
+ {
+ switch ($this->fetchMode) {
+ case ADODB_FETCH_NUM:
+ $this->fields = @odbtp_fetch_row($this->_queryID, $type);
+ break;
+ case ADODB_FETCH_ASSOC:
+ $this->fields = @odbtp_fetch_assoc($this->_queryID, $type);
+ break;
+ default:
+ $this->fields = @odbtp_fetch_array($this->_queryID, $type);
+ }
+ if ($this->databaseType = 'odbtp_vfp') {
+ if ($this->fields)
+ foreach($this->fields as $k => $v) {
+ if (strncmp($v,'1899-12-30',10) == 0) $this->fields[$k] = '';
+ }
+ }
+ return is_array($this->fields);
+ }
+
+ function _fetch()
+ {
+ return $this->_fetch_odbtp();
+ }
+
+ function MoveFirst()
+ {
+ if (!$this->_fetch_odbtp(ODB_FETCH_FIRST)) return false;
+ $this->EOF = false;
+ $this->_currentRow = 0;
+ return true;
+ }
+
+ function MoveLast()
+ {
+ if (!$this->_fetch_odbtp(ODB_FETCH_LAST)) return false;
+ $this->EOF = false;
+ $this->_currentRow = $this->_numOfRows - 1;
+ return true;
+ }
+
+ function NextRecordSet()
+ {
+ if (!@odbtp_next_result($this->_queryID)) return false;
+ $this->_inited = false;
+ $this->bind = false;
+ $this->_currentRow = -1;
+ $this->Init();
+ return true;
+ }
+
+ function _close()
+ {
+ return @odbtp_free_query($this->_queryID);
+ }
+}
+
+class ADORecordSet_odbtp_mssql extends ADORecordSet_odbtp {
+
+ var $databaseType = 'odbtp_mssql';
+
+ function ADORecordSet_odbtp_mssql($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbtp($id,$mode);
+ }
+}
+
+class ADORecordSet_odbtp_access extends ADORecordSet_odbtp {
+
+ var $databaseType = 'odbtp_access';
+
+ function ADORecordSet_odbtp_access($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbtp($id,$mode);
+ }
+}
+
+class ADORecordSet_odbtp_vfp extends ADORecordSet_odbtp {
+
+ var $databaseType = 'odbtp_vfp';
+
+ function ADORecordSet_odbtp_vfp($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbtp($id,$mode);
+ }
+}
+
+class ADORecordSet_odbtp_oci8 extends ADORecordSet_odbtp {
+
+ var $databaseType = 'odbtp_oci8';
+
+ function ADORecordSet_odbtp_oci8($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbtp($id,$mode);
+ }
+}
+
+class ADORecordSet_odbtp_sybase extends ADORecordSet_odbtp {
+
+ var $databaseType = 'odbtp_sybase';
+
+ function ADORecordSet_odbtp_sybase($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbtp($id,$mode);
+ }
+}
+?>
diff --git a/lib/adodb/drivers/adodb-odbtp_unicode.inc.php b/lib/adodb/drivers/adodb-odbtp_unicode.inc.php
new file mode 100644
index 0000000..ff79373
--- /dev/null
+++ b/lib/adodb/drivers/adodb-odbtp_unicode.inc.php
@@ -0,0 +1,39 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+ Latest version is available at http://adodb.sourceforge.net
+*/
+
+// Code contributed by "Robert Twitty" <rtwitty#neutron.ushmm.org>
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+/*
+ Because the ODBTP server sends and reads UNICODE text data using UTF-8
+ encoding, the following HTML meta tag must be included within the HTML
+ head section of every HTML form and script page:
+
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+ Also, all SQL query strings must be submitted as UTF-8 encoded text.
+*/
+
+if (!defined('_ADODB_ODBTP_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbtp.inc.php");
+}
+
+class ADODB_odbtp_unicode extends ADODB_odbtp {
+ var $databaseType = 'odbtp';
+ var $_useUnicodeSQL = true;
+
+ function ADODB_odbtp_unicode()
+ {
+ $this->ADODB_odbtp();
+ }
+}
+?>
diff --git a/lib/adodb/drivers/adodb-oracle.inc.php b/lib/adodb/drivers/adodb-oracle.inc.php
new file mode 100644
index 0000000..3c6dbd3
--- /dev/null
+++ b/lib/adodb/drivers/adodb-oracle.inc.php
@@ -0,0 +1,338 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Oracle data driver. Requires Oracle client. Works on Windows and Unix and Oracle 7.
+
+ If you are using Oracle 8 or later, use the oci8 driver which is much better and more reliable.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB_oracle extends ADOConnection {
+ var $databaseType = "oracle";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $concat_operator='||';
+ var $_curs;
+ var $_initdate = true; // init date to YYYY-MM-DD
+ var $metaTablesSQL = 'select table_name from cat';
+ var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno";
+ var $sysDate = "TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM-DD'),'YYYY-MM-DD')";
+ var $sysTimeStamp = 'SYSDATE';
+ var $connectSID = true;
+
+ function ADODB_oracle()
+ {
+ }
+
+ // format and return date string in database date format
+ function DBDate($d)
+ {
+ if (is_string($d)) $d = ADORecordSet::UnixDate($d);
+ return 'TO_DATE('.adodb_date($this->fmtDate,$d).",'YYYY-MM-DD')";
+ }
+
+ // format and return date string in database timestamp format
+ function DBTimeStamp($ts)
+ {
+
+ if (is_string($ts)) $d = ADORecordSet::UnixTimeStamp($ts);
+ return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";
+ }
+
+
+ function BindDate($d)
+ {
+ $d = ADOConnection::DBDate($d);
+ if (strncmp($d,"'",1)) return $d;
+
+ return substr($d,1,strlen($d)-2);
+ }
+
+ function BindTimeStamp($d)
+ {
+ $d = ADOConnection::DBTimeStamp($d);
+ if (strncmp($d,"'",1)) return $d;
+
+ return substr($d,1,strlen($d)-2);
+ }
+
+
+
+ function BeginTrans()
+ {
+ $this->autoCommit = false;
+ ora_commitoff($this->_connectionID);
+ return true;
+ }
+
+
+ function CommitTrans($ok=true)
+ {
+ if (!$ok) return $this->RollbackTrans();
+ $ret = ora_commit($this->_connectionID);
+ ora_commiton($this->_connectionID);
+ return $ret;
+ }
+
+
+ function RollbackTrans()
+ {
+ $ret = ora_rollback($this->_connectionID);
+ ora_commiton($this->_connectionID);
+ return $ret;
+ }
+
+
+ /* there seems to be a bug in the oracle extension -- always returns ORA-00000 - no error */
+ function ErrorMsg()
+ {
+ if ($this->_errorMsg !== false) return $this->_errorMsg;
+
+ if (is_resource($this->_curs)) $this->_errorMsg = @ora_error($this->_curs);
+ if (empty($this->_errorMsg)) $this->_errorMsg = @ora_error($this->_connectionID);
+ return $this->_errorMsg;
+ }
+
+
+ function ErrorNo()
+ {
+ if ($this->_errorCode !== false) return $this->_errorCode;
+
+ if (is_resource($this->_curs)) $this->_errorCode = @ora_errorcode($this->_curs);
+ if (empty($this->_errorCode)) $this->_errorCode = @ora_errorcode($this->_connectionID);
+ return $this->_errorCode;
+ }
+
+
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename, $mode=0)
+ {
+ if (!function_exists('ora_plogon')) return null;
+
+ // <G. Giunta 2003/03/03/> Reset error messages before connecting
+ $this->_errorMsg = false;
+ $this->_errorCode = false;
+
+ // G. Giunta 2003/08/13 - This looks danegrously suspicious: why should we want to set
+ // the oracle home to the host name of remote DB?
+// if ($argHostname) putenv("ORACLE_HOME=$argHostname");
+
+ if($argHostname) { // code copied from version submitted for oci8 by Jorma Tuomainen <jorma.tuomainen@ppoy.fi>
+ if (empty($argDatabasename)) $argDatabasename = $argHostname;
+ else {
+ if(strpos($argHostname,":")) {
+ $argHostinfo=explode(":",$argHostname);
+ $argHostname=$argHostinfo[0];
+ $argHostport=$argHostinfo[1];
+ } else {
+ $argHostport="1521";
+ }
+
+
+ if ($this->connectSID) {
+ $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
+ .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";
+ } else
+ $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
+ .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";
+ }
+
+ }
+
+ if ($argDatabasename) $argUsername .= "@$argDatabasename";
+
+ //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";
+ if ($mode = 1)
+ $this->_connectionID = ora_plogon($argUsername,$argPassword);
+ else
+ $this->_connectionID = ora_logon($argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($this->autoCommit) ora_commiton($this->_connectionID);
+ if ($this->_initdate) {
+ $rs = $this->_query("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD'");
+ if ($rs) ora_close($rs);
+ }
+
+ return true;
+ }
+
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, 1);
+ }
+
+
+ // returns query ID if successful, otherwise false
+ function _query($sql,$inputarr=false)
+ {
+ // <G. Giunta 2003/03/03/> Reset error messages before executing
+ $this->_errorMsg = false;
+ $this->_errorCode = false;
+
+ $curs = ora_open($this->_connectionID);
+
+ if ($curs === false) return false;
+ $this->_curs = $curs;
+ if (!ora_parse($curs,$sql)) return false;
+ if (ora_exec($curs)) return $curs;
+ // <G. Giunta 2004/03/03> before we close the cursor, we have to store the error message
+ // that we can obtain ONLY from the cursor (and not from the connection)
+ $this->_errorCode = @ora_errorcode($curs);
+ $this->_errorMsg = @ora_error($curs);
+ // </G. Giunta 2004/03/03>
+ @ora_close($curs);
+ return false;
+ }
+
+
+ // returns true or false
+ function _close()
+ {
+ return @ora_logoff($this->_connectionID);
+ }
+
+
+
+}
+
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_oracle extends ADORecordSet {
+
+ var $databaseType = "oracle";
+ var $bind = false;
+
+ function ADORecordset_oracle($queryID,$mode=false)
+ {
+
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->fetchMode = $mode;
+
+ $this->_queryID = $queryID;
+
+ $this->_inited = true;
+ $this->fields = array();
+ if ($queryID) {
+ $this->_currentRow = 0;
+ $this->EOF = !$this->_fetch();
+ @$this->_initrs();
+ } else {
+ $this->_numOfRows = 0;
+ $this->_numOfFields = 0;
+ $this->EOF = true;
+ }
+
+ return $this->_queryID;
+ }
+
+
+
+ /* Returns: an object containing field information.
+ Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+ fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+ fetchField() is retrieved. */
+
+ function &FetchField($fieldOffset = -1)
+ {
+ $fld = new ADOFieldObject;
+ $fld->name = ora_columnname($this->_queryID, $fieldOffset);
+ $fld->type = ora_columntype($this->_queryID, $fieldOffset);
+ $fld->max_length = ora_columnsize($this->_queryID, $fieldOffset);
+ return $fld;
+ }
+
+ /* Use associative array to get fields array */
+ function 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)]];
+ }
+
+ function _initrs()
+ {
+ $this->_numOfRows = -1;
+ $this->_numOfFields = @ora_numcols($this->_queryID);
+ }
+
+
+ function _seek($row)
+ {
+ return false;
+ }
+
+ function _fetch($ignore_fields=false) {
+// should remove call by reference, but ora_fetch_into requires it in 4.0.3pl1
+ if ($this->fetchMode & ADODB_FETCH_ASSOC)
+ return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS|ORA_FETCHINTO_ASSOC);
+ else
+ return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS);
+ }
+
+ /* close() only needs to be called if you are worried about using too much memory while your script
+ is running. All associated result memory for the specified result identifier will automatically be freed. */
+
+ function _close()
+{
+ return @ora_close($this->_queryID);
+ }
+
+ function MetaType($t,$len=-1)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+
+ switch (strtoupper($t)) {
+ case 'VARCHAR':
+ case 'VARCHAR2':
+ case 'CHAR':
+ case 'VARBINARY':
+ case 'BINARY':
+ if ($len <= $this->blobSize) return 'C';
+ case 'LONG':
+ case 'LONG VARCHAR':
+ case 'CLOB':
+ return 'X';
+ case 'LONG RAW':
+ case 'LONG VARBINARY':
+ case 'BLOB':
+ return 'B';
+
+ case 'DATE': return 'D';
+
+ //case 'T': return 'T';
+
+ case 'BIT': return 'L';
+ case 'INT':
+ case 'SMALLINT':
+ case 'INTEGER': return 'I';
+ default: return 'N';
+ }
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-pdo.inc.php b/lib/adodb/drivers/adodb-pdo.inc.php
new file mode 100644
index 0000000..e3f77f1
--- /dev/null
+++ b/lib/adodb/drivers/adodb-pdo.inc.php
@@ -0,0 +1,569 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Requires ODBC. Works on Windows and Unix.
+
+ Problems:
+ Where is float/decimal type in pdo_param_type
+ LOB handling for CLOB/BLOB differs significantly
+*/
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+
+/*
+enum pdo_param_type {
+PDO::PARAM_NULL, 0
+
+/* int as in long (the php native int type).
+ * If you mark a column as an int, PDO expects get_col to return
+ * a pointer to a long
+PDO::PARAM_INT, 1
+
+/* get_col ptr should point to start of the string buffer
+PDO::PARAM_STR, 2
+
+/* get_col: when len is 0 ptr should point to a php_stream *,
+ * otherwise it should behave like a string. Indicate a NULL field
+ * value by setting the ptr to NULL
+PDO::PARAM_LOB, 3
+
+/* get_col: will expect the ptr to point to a new PDOStatement object handle,
+ * but this isn't wired up yet
+PDO::PARAM_STMT, 4 /* hierarchical result set
+
+/* get_col ptr should point to a zend_bool
+PDO::PARAM_BOOL, 5
+
+
+/* magic flag to denote a parameter as being input/output
+PDO::PARAM_INPUT_OUTPUT = 0x80000000
+};
+*/
+
+function adodb_pdo_type($t)
+{
+ switch($t) {
+ case 2: return 'VARCHAR';
+ case 3: return 'BLOB';
+ default: return 'NUMERIC';
+ }
+}
+
+/*--------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------------*/
+
+////////////////////////////////////////////////
+
+
+
+class ADODB_pdo_base extends ADODB_pdo {
+
+ var $sysDate = "'?'";
+ var $sysTimeStamp = "'?'";
+
+
+ function _init($parentDriver)
+ {
+ $parentDriver->_bindInputArray = true;
+ #$parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true);
+ }
+
+ function ServerInfo()
+ {
+ return ADOConnection::ServerInfo();
+ }
+
+ function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ {
+ $ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+ return $ret;
+ }
+
+ function MetaTables()
+ {
+ return false;
+ }
+
+ function MetaColumns()
+ {
+ return false;
+ }
+}
+
+
+class ADODB_pdo extends ADOConnection {
+ var $databaseType = "pdo";
+ var $dataProvider = "pdo";
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d, h:i:sA'";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $hasAffectedRows = true;
+ var $_bindInputArray = true;
+ var $_genSeqSQL = "create table %s (id integer)";
+ var $_autocommit = true;
+ var $_haserrorfunctions = true;
+ var $_lastAffectedRows = 0;
+
+ var $_errormsg = false;
+ var $_errorno = false;
+
+ var $dsnType = '';
+ var $stmt = false;
+
+ function ADODB_pdo()
+ {
+ }
+
+ function _UpdatePDO()
+ {
+ $d = &$this->_driver;
+ $this->fmtDate = $d->fmtDate;
+ $this->fmtTimeStamp = $d->fmtTimeStamp;
+ $this->replaceQuote = $d->replaceQuote;
+ $this->sysDate = $d->sysDate;
+ $this->sysTimeStamp = $d->sysTimeStamp;
+ $this->random = $d->random;
+ $this->concat_operator = $d->concat_operator;
+ $this->nameQuote = $d->nameQuote;
+
+ $this->hasGenID = $d->hasGenID;
+ $this->_genIDSQL = $d->_genIDSQL;
+ $this->_genSeqSQL = $d->_genSeqSQL;
+ $this->_dropSeqSQL = $d->_dropSeqSQL;
+
+ $d->_init($this);
+ }
+
+ function Time()
+ {
+ if (!empty($this->_driver->_hasdual)) $sql = "select $this->sysTimeStamp from dual";
+ else $sql = "select $this->sysTimeStamp";
+
+ $rs =& $this->_Execute($sql);
+ if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
+
+ return false;
+ }
+
+ // returns true or false
+ function _connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persist=false)
+ {
+ $at = strpos($argDSN,':');
+ $this->dsnType = substr($argDSN,0,$at);
+
+ if ($argDatabasename) {
+ $argDSN .= ';dbname='.$argDatabasename;
+ }
+ try {
+ $this->_connectionID = new PDO($argDSN, $argUsername, $argPassword);
+ } catch (Exception $e) {
+ $this->_connectionID = false;
+ $this->_errorno = -1;
+ //var_dump($e);
+ $this->_errormsg = 'Connection attempt failed: '.$e->getMessage();
+ return false;
+ }
+
+ if ($this->_connectionID) {
+ switch(ADODB_ASSOC_CASE){
+ case 0: $m = PDO::CASE_LOWER; break;
+ case 1: $m = PDO::CASE_UPPER; break;
+ default:
+ case 2: $m = PDO::CASE_NATURAL; break;
+ }
+
+ //$this->_connectionID->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_SILENT );
+ $this->_connectionID->setAttribute(PDO::ATTR_CASE,$m);
+
+ $class = 'ADODB_pdo_'.$this->dsnType;
+ //$this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true);
+ switch($this->dsnType) {
+ case 'oci':
+ case 'mysql':
+ case 'pgsql':
+ case 'mssql':
+ include_once(ADODB_DIR.'/drivers/adodb-pdo_'.$this->dsnType.'.inc.php');
+ break;
+ }
+ if (class_exists($class))
+ $this->_driver = new $class();
+ else
+ $this->_driver = new ADODB_pdo_base();
+
+ $this->_driver->_connectionID = $this->_connectionID;
+ $this->_UpdatePDO();
+ return true;
+ }
+ $this->_driver = new ADODB_pdo_base();
+ return false;
+ }
+
+ // returns true or false
+ function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename)
+ {
+ return $this->_connect($argDSN, $argUsername, $argPassword, $argDatabasename, true);
+ }
+
+ /*------------------------------------------------------------------------------*/
+
+
+ function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ {
+ $save = $this->_driver->fetchMode;
+ $this->_driver->fetchMode = $this->fetchMode;
+ $this->_driver->debug = $this->debug;
+ $ret = $this->_driver->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+ $this->_driver->fetchMode = $save;
+ return $ret;
+ }
+
+
+ function ServerInfo()
+ {
+ return $this->_driver->ServerInfo();
+ }
+
+ function MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ return $this->_driver->MetaTables($ttype,$showSchema,$mask);
+ }
+
+ function MetaColumns($table,$normalize=true)
+ {
+ return $this->_driver->MetaColumns($table,$normalize);
+ }
+
+ function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false)
+ {
+ $obj = $stmt[1];
+ if ($type) $obj->bindParam($name,$var,$type,$maxLen);
+ else $obj->bindParam($name, $var);
+ }
+
+
+ function ErrorMsg()
+ {
+ if ($this->_errormsg !== false) return $this->_errormsg;
+ if (!empty($this->_stmt)) $arr = $this->_stmt->errorInfo();
+ else if (!empty($this->_connectionID)) $arr = $this->_connectionID->errorInfo();
+ else return 'No Connection Established';
+
+
+ if ($arr) {
+ if (sizeof($arr)<2) return '';
+ if ((integer)$arr[1]) return $arr[2];
+ else return '';
+ } else return '-1';
+ }
+
+
+ function ErrorNo()
+ {
+ if ($this->_errorno !== false) return $this->_errorno;
+ if (!empty($this->_stmt)) $err = $this->_stmt->errorCode();
+ else if (!empty($this->_connectionID)) {
+ $arr = $this->_connectionID->errorInfo();
+ if (isset($arr[0])) $err = $arr[0];
+ else $err = -1;
+ } else
+ return 0;
+
+ if ($err == '00000') return 0; // allows empty check
+ return $err;
+ }
+
+ function BeginTrans()
+ {
+ if (!$this->hasTransactions) return false;
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ $this->_autocommit = false;
+ $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,false);
+ return $this->_connectionID->beginTransaction();
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if (!$this->hasTransactions) return false;
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+
+ $ret = $this->_connectionID->commit();
+ $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true);
+ return $ret;
+ }
+
+ function RollbackTrans()
+ {
+ if (!$this->hasTransactions) return false;
+ if ($this->transOff) return true;
+ if ($this->transCnt) $this->transCnt -= 1;
+ $this->_autocommit = true;
+
+ $ret = $this->_connectionID->rollback();
+ $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true);
+ return $ret;
+ }
+
+ function Prepare($sql)
+ {
+ $this->_stmt = $this->_connectionID->prepare($sql);
+ if ($this->_stmt) return array($sql,$this->_stmt);
+
+ return false;
+ }
+
+ function PrepareStmt($sql)
+ {
+ $stmt = $this->_connectionID->prepare($sql);
+ if (!$stmt) return false;
+ $obj = new ADOPDOStatement($stmt,$this);
+ return $obj;
+ }
+
+
+ /* returns queryID or false */
+ function _query($sql,$inputarr=false)
+ {
+ if (is_array($sql)) {
+ $stmt = $sql[1];
+ } else {
+ $stmt = $this->_connectionID->prepare($sql);
+ }
+ #adodb_backtrace();
+ #var_dump($this->_bindInputArray);
+ if ($stmt) {
+ $this->_driver->debug = $this->debug;
+ if ($inputarr) $ok = $stmt->execute($inputarr);
+ else $ok = $stmt->execute();
+ }
+
+
+ $this->_errormsg = false;
+ $this->_errorno = false;
+
+ if ($ok) {
+ $this->_stmt = $stmt;
+ return $stmt;
+ }
+
+ if ($stmt) {
+
+ $arr = $stmt->errorinfo();
+ if ((integer)$arr[1]) {
+ $this->_errormsg = $arr[2];
+ $this->_errorno = $arr[1];
+ }
+
+ } else {
+ $this->_errormsg = false;
+ $this->_errorno = false;
+ }
+ return false;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ $this->_stmt = false;
+ return true;
+ }
+
+ function _affectedrows()
+ {
+ return ($this->_stmt) ? $this->_stmt->rowCount() : 0;
+ }
+
+ function _insertid()
+ {
+ return ($this->_connectionID) ? $this->_connectionID->lastInsertId() : 0;
+ }
+}
+
+class ADOPDOStatement {
+
+ var $databaseType = "pdo";
+ var $dataProvider = "pdo";
+ var $_stmt;
+ var $_connectionID;
+
+ function ADOPDOStatement($stmt,$connection)
+ {
+ $this->_stmt = $stmt;
+ $this->_connectionID = $connection;
+ }
+
+ function Execute($inputArr=false)
+ {
+ $savestmt = $this->_connectionID->_stmt;
+ $rs = $this->_connectionID->Execute(array(false,$this->_stmt),$inputArr);
+ $this->_connectionID->_stmt = $savestmt;
+ return $rs;
+ }
+
+ function InParameter(&$var,$name,$maxLen=4000,$type=false)
+ {
+
+ if ($type) $this->_stmt->bindParam($name,$var,$type,$maxLen);
+ else $this->_stmt->bindParam($name, $var);
+ }
+
+ function Affected_Rows()
+ {
+ return ($this->_stmt) ? $this->_stmt->rowCount() : 0;
+ }
+
+ function ErrorMsg()
+ {
+ if ($this->_stmt) $arr = $this->_stmt->errorInfo();
+ else $arr = $this->_connectionID->errorInfo();
+
+ if (is_array($arr)) {
+ if ((integer) $arr[0] && isset($arr[2])) return $arr[2];
+ else return '';
+ } else return '-1';
+ }
+
+ function NumCols()
+ {
+ return ($this->_stmt) ? $this->_stmt->columnCount() : 0;
+ }
+
+ function ErrorNo()
+ {
+ if ($this->_stmt) return $this->_stmt->errorCode();
+ else return $this->_connectionID->errorInfo();
+ }
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_pdo extends ADORecordSet {
+
+ var $bind = false;
+ var $databaseType = "pdo";
+ var $dataProvider = "pdo";
+
+ function ADORecordSet_pdo($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ $this->adodbFetchMode = $mode;
+ switch($mode) {
+ case ADODB_FETCH_NUM: $mode = PDO::FETCH_NUM; break;
+ case ADODB_FETCH_ASSOC: $mode = PDO::FETCH_ASSOC; break;
+
+ case ADODB_FETCH_BOTH:
+ default: $mode = PDO::FETCH_BOTH; break;
+ }
+ $this->fetchMode = $mode;
+
+ $this->_queryID = $id;
+ $this->ADORecordSet($id);
+ }
+
+
+ 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->_currentRow == -1) {
+ $this->_currentRow = 0;
+ if ($this->EOF = ($this->_fetch() === false)) {
+ $this->_numOfRows = 0; // _numOfRows could be -1
+ }
+ } else {
+ $this->EOF = true;
+ }
+ }
+
+ function _initrs()
+ {
+ global $ADODB_COUNTRECS;
+
+ $this->_numOfRows = ($ADODB_COUNTRECS) ? @$this->_queryID->rowCount() : -1;
+ if (!$this->_numOfRows) $this->_numOfRows = -1;
+ $this->_numOfFields = $this->_queryID->columnCount();
+ }
+
+ // returns the field object
+ function &FetchField($fieldOffset = -1)
+ {
+ $off=$fieldOffset+1; // offsets begin at 1
+
+ $o= new ADOFieldObject();
+ $arr = @$this->_queryID->getColumnMeta($fieldOffset);
+ if (!$arr) {
+ $o->name = 'bad getColumnMeta()';
+ $o->max_length = -1;
+ $o->type = 'VARCHAR';
+ $o->precision = 0;
+ # $false = false;
+ return $o;
+ }
+ //adodb_pr($arr);
+ $o->name = $arr['name'];
+ if (isset($arr['native_type']) && $arr['native_type'] <> "null") $o->type = $arr['native_type'];
+ else $o->type = adodb_pdo_type($arr['pdo_type']);
+ $o->max_length = $arr['len'];
+ $o->precision = $arr['precision'];
+
+ if (ADODB_ASSOC_CASE == 0) $o->name = strtolower($o->name);
+ else if (ADODB_ASSOC_CASE == 1) $o->name = strtoupper($o->name);
+ return $o;
+ }
+
+ function _seek($row)
+ {
+ return false;
+ }
+
+ function _fetch()
+ {
+ if (!$this->_queryID) return false;
+
+ $this->fields = $this->_queryID->fetch($this->fetchMode);
+ return !empty($this->fields);
+ }
+
+ function _close()
+ {
+ $this->_queryID = false;
+ }
+
+ function Fields($colname)
+ {
+ if ($this->adodbFetchMode != ADODB_FETCH_NUM) 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)]];
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-pdo_mssql.inc.php b/lib/adodb/drivers/adodb-pdo_mssql.inc.php
new file mode 100644
index 0000000..9470dd8
--- /dev/null
+++ b/lib/adodb/drivers/adodb-pdo_mssql.inc.php
@@ -0,0 +1,61 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+*/
+
+class ADODB_pdo_mssql extends ADODB_pdo {
+
+ var $hasTop = 'top';
+ var $sysDate = 'convert(datetime,convert(char,GetDate(),102),102)';
+ var $sysTimeStamp = 'GetDate()';
+
+
+ function _init($parentDriver)
+ {
+
+ $parentDriver->hasTransactions = false; ## <<< BUG IN PDO mssql driver
+ $parentDriver->_bindInputArray = false;
+ $parentDriver->hasInsertID = true;
+ }
+
+ function ServerInfo()
+ {
+ return ADOConnection::ServerInfo();
+ }
+
+ function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ {
+ $ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+ return $ret;
+ }
+
+ function SetTransactionMode( $transaction_mode )
+ {
+ $this->_transmode = $transaction_mode;
+ if (empty($transaction_mode)) {
+ $this->Execute('SET TRANSACTION ISOLATION LEVEL READ COMMITTED');
+ return;
+ }
+ if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+ $this->Execute("SET TRANSACTION ".$transaction_mode);
+ }
+
+ function MetaTables()
+ {
+ return false;
+ }
+
+ function MetaColumns()
+ {
+ return false;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-pdo_mysql.inc.php b/lib/adodb/drivers/adodb-pdo_mysql.inc.php
new file mode 100644
index 0000000..b80241d
--- /dev/null
+++ b/lib/adodb/drivers/adodb-pdo_mysql.inc.php
@@ -0,0 +1,168 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+*/
+
+class ADODB_pdo_mysql extends ADODB_pdo {
+ var $metaTablesSQL = "SHOW TABLES";
+ var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
+ var $sysDate = 'CURDATE()';
+ var $sysTimeStamp = 'NOW()';
+ var $nameQuote = '`';
+
+ function _init($parentDriver)
+ {
+
+ $parentDriver->hasTransactions = false;
+ $parentDriver->_bindInputArray = false;
+ $parentDriver->hasInsertID = true;
+ $parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true);
+ }
+
+ // dayFraction is a day in floating point
+ function OffsetDate($dayFraction,$date=false)
+ {
+ if (!$date) $date = $this->sysDate;
+
+ $fraction = $dayFraction * 24 * 3600;
+ return $date . ' + INTERVAL ' . $fraction.' SECOND';
+
+// return "from_unixtime(unix_timestamp($date)+$fraction)";
+ }
+
+ function ServerInfo()
+ {
+ $arr['description'] = ADOConnection::GetOne("select version()");
+ $arr['version'] = ADOConnection::_findvers($arr['description']);
+ return $arr;
+ }
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ $save = $this->metaTablesSQL;
+ if ($showSchema && is_string($showSchema)) {
+ $this->metaTablesSQL .= " from $showSchema";
+ }
+
+ if ($mask) {
+ $mask = $this->qstr($mask);
+ $this->metaTablesSQL .= " like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ $this->metaTablesSQL = $save;
+ return $ret;
+ }
+
+ function SetTransactionMode( $transaction_mode )
+ {
+ $this->_transmode = $transaction_mode;
+ if (empty($transaction_mode)) {
+ $this->Execute('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
+ return;
+ }
+ if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode;
+ $this->Execute("SET SESSION TRANSACTION ".$transaction_mode);
+ }
+
+ function &MetaColumns($table)
+ {
+ $this->_findschema($table,$schema);
+ if ($schema) {
+ $dbName = $this->database;
+ $this->SelectDB($schema);
+ }
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+
+ if ($schema) {
+ $this->SelectDB($dbName);
+ }
+
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ if (!is_object($rs)) {
+ $false = false;
+ return $false;
+ }
+
+ $retarr = array();
+ while (!$rs->EOF){
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $type = $rs->fields[1];
+
+ // split type into type(length):
+ $fld->scale = null;
+ if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
+ $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
+ } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
+ } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
+ $fld->type = $query_array[1];
+ $arr = explode(",",$query_array[2]);
+ $fld->enums = $arr;
+ $zlen = max(array_map("strlen",$arr)) - 2; // PHP >= 4.0.6
+ $fld->max_length = ($zlen > 0) ? $zlen : 1;
+ } else {
+ $fld->type = $type;
+ $fld->max_length = -1;
+ }
+ $fld->not_null = ($rs->fields[2] != 'YES');
+ $fld->primary_key = ($rs->fields[3] == 'PRI');
+ $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
+ $fld->binary = (strpos($type,'blob') !== false);
+ $fld->unsigned = (strpos($type,'unsigned') !== false);
+
+ if (!$fld->binary) {
+ $d = $rs->fields[4];
+ if ($d != '' && $d != 'NULL') {
+ $fld->has_default = true;
+ $fld->default_value = $d;
+ } else {
+ $fld->has_default = false;
+ }
+ }
+
+ if ($save == ADODB_FETCH_NUM) {
+ $retarr[] = $fld;
+ } else {
+ $retarr[strtoupper($fld->name)] = $fld;
+ }
+ $rs->MoveNext();
+ }
+
+ $rs->Close();
+ return $retarr;
+ }
+
+
+ // parameters use PostgreSQL convention, not MySQL
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs=0)
+ {
+ $offsetStr =($offset>=0) ? "$offset," : '';
+ // jason judge, see http://phplens.com/lens/lensforum/msgs.php?id=9220
+ if ($nrows < 0) $nrows = '18446744073709551615';
+
+ if ($secs)
+ $rs =& $this->CacheExecute($secs,$sql." LIMIT $offsetStr$nrows",$inputarr);
+ else
+ $rs =& $this->Execute($sql." LIMIT $offsetStr$nrows",$inputarr);
+ return $rs;
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-pdo_oci.inc.php b/lib/adodb/drivers/adodb-pdo_oci.inc.php
new file mode 100644
index 0000000..9d40f14
--- /dev/null
+++ b/lib/adodb/drivers/adodb-pdo_oci.inc.php
@@ -0,0 +1,93 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+*/
+
+class ADODB_pdo_oci extends ADODB_pdo_base {
+
+ var $concat_operator='||';
+ var $sysDate = "TRUNC(SYSDATE)";
+ var $sysTimeStamp = 'SYSDATE';
+ var $NLS_DATE_FORMAT = 'YYYY-MM-DD'; // To include time, use 'RRRR-MM-DD HH24:MI:SS'
+ var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)";
+ var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW')";
+ var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno";
+
+ var $_initdate = true;
+ var $_hasdual = true;
+
+ function _init($parentDriver)
+ {
+ $parentDriver->_bindInputArray = true;
+ $parentDriver->_nestedSQL = true;
+ if ($this->_initdate) {
+ $parentDriver->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
+ }
+ }
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ if ($mask) {
+ $save = $this->metaTablesSQL;
+ $mask = $this->qstr(strtoupper($mask));
+ $this->metaTablesSQL .= " AND table_name like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ if ($mask) {
+ $this->metaTablesSQL = $save;
+ }
+ return $ret;
+ }
+
+ function &MetaColumns($table)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $false = false;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
+
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ if (!$rs) {
+ return $false;
+ }
+ $retarr = array();
+ while (!$rs->EOF) { //print_r($rs->fields);
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+ $fld->max_length = $rs->fields[2];
+ $fld->scale = $rs->fields[3];
+ if ($rs->fields[1] == 'NUMBER' && $rs->fields[3] == 0) {
+ $fld->type ='INT';
+ $fld->max_length = $rs->fields[4];
+ }
+ $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
+ $fld->binary = (strpos($fld->type,'BLOB') !== false);
+ $fld->default_value = $rs->fields[6];
+
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
+ else $retarr[strtoupper($fld->name)] = $fld;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ if (empty($retarr))
+ return $false;
+ else
+ return $retarr;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-pdo_pgsql.inc.php b/lib/adodb/drivers/adodb-pdo_pgsql.inc.php
new file mode 100644
index 0000000..e802d79
--- /dev/null
+++ b/lib/adodb/drivers/adodb-pdo_pgsql.inc.php
@@ -0,0 +1,230 @@
+<?php
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+*/
+
+class ADODB_pdo_pgsql extends ADODB_pdo {
+ var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
+ var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
+ and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages',
+ 'sql_packages', 'sql_sizing', 'sql_sizing_profiles')
+ union
+ select viewname,'V' from pg_views where viewname not like 'pg\_%'";
+ //"select tablename from pg_tables where tablename not like 'pg_%' order by 1";
+ var $isoDates = true; // accepts dates in ISO format
+ var $sysDate = "CURRENT_DATE";
+ var $sysTimeStamp = "CURRENT_TIMESTAMP";
+ var $blobEncodeType = 'C';
+ var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum
+ FROM pg_class c, pg_attribute a,pg_type t
+ WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%'
+AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
+
+ // used when schema defined
+ var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum
+FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n
+WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s'))
+ and c.relnamespace=n.oid and n.nspname='%s'
+ and a.attname not like '....%%' AND a.attnum > 0
+ AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
+
+ // get primary key etc -- from Freek Dijkstra
+ var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key
+ FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'";
+
+ var $hasAffectedRows = true;
+ var $hasLimit = false; // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10
+ // below suggested by Freek Dijkstra
+ var $true = 't'; // string that represents TRUE for a database
+ var $false = 'f'; // string that represents FALSE for a database
+ var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database
+ var $fmtTimeStamp = "'Y-m-d G:i:s'"; // used by DBTimeStamp as the default timestamp fmt.
+ var $hasMoveFirst = true;
+ var $hasGenID = true;
+ var $_genIDSQL = "SELECT NEXTVAL('%s')";
+ var $_genSeqSQL = "CREATE SEQUENCE %s START %s";
+ var $_dropSeqSQL = "DROP SEQUENCE %s";
+ var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum";
+ var $random = 'random()'; /// random function
+ var $concat_operator='||';
+
+ function _init($parentDriver)
+ {
+
+ $parentDriver->hasTransactions = false; ## <<< BUG IN PDO pgsql driver
+ $parentDriver->hasInsertID = true;
+ $parentDriver->_nestedSQL = true;
+ }
+
+ function ServerInfo()
+ {
+ $arr['description'] = ADOConnection::GetOne("select version()");
+ $arr['version'] = ADOConnection::_findvers($arr['description']);
+ return $arr;
+ }
+
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ {
+ $offsetStr = ($offset >= 0) ? " OFFSET $offset" : '';
+ $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : '';
+ if ($secs2cache)
+ $rs =& $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr);
+ else
+ $rs =& $this->Execute($sql."$limitStr$offsetStr",$inputarr);
+
+ return $rs;
+ }
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ $info = $this->ServerInfo();
+ if ($info['version'] >= 7.3) {
+ $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
+ and schemaname not in ( 'pg_catalog','information_schema')
+ union
+ select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') ";
+ }
+ if ($mask) {
+ $save = $this->metaTablesSQL;
+ $mask = $this->qstr(strtolower($mask));
+ if ($info['version']>=7.3)
+ $this->metaTablesSQL = "
+select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema')
+ union
+select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') ";
+ else
+ $this->metaTablesSQL = "
+select tablename,'T' from pg_tables where tablename like $mask
+ union
+select viewname,'V' from pg_views where viewname like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ if ($mask) {
+ $this->metaTablesSQL = $save;
+ }
+ return $ret;
+ }
+
+ function &MetaColumns($table,$normalize=true)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $schema = false;
+ $this->_findschema($table,$schema);
+
+ if ($normalize) $table = strtolower($table);
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+
+ if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema));
+ else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table));
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if ($rs === false) {
+ $false = false;
+ return $false;
+ }
+ if (!empty($this->metaKeySQL)) {
+ // If we want the primary keys, we have to issue a separate query
+ // Of course, a modified version of the metaColumnsSQL query using a
+ // LEFT JOIN would have been much more elegant, but postgres does
+ // not support OUTER JOINS. So here is the clumsy way.
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+
+ $rskey = $this->Execute(sprintf($this->metaKeySQL,($table)));
+ // fetch all result in once for performance.
+ $keys =& $rskey->GetArray();
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ $rskey->Close();
+ unset($rskey);
+ }
+
+ $rsdefa = array();
+ if (!empty($this->metaDefaultsSQL)) {
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $sql = sprintf($this->metaDefaultsSQL, ($table));
+ $rsdef = $this->Execute($sql);
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if ($rsdef) {
+ while (!$rsdef->EOF) {
+ $num = $rsdef->fields['num'];
+ $s = $rsdef->fields['def'];
+ if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */
+ $s = substr($s, 1);
+ $s = substr($s, 0, strlen($s) - 1);
+ }
+
+ $rsdefa[$num] = $s;
+ $rsdef->MoveNext();
+ }
+ } else {
+ ADOConnection::outp( "==> SQL => " . $sql);
+ }
+ unset($rsdef);
+ }
+
+ $retarr = array();
+ while (!$rs->EOF) {
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+ $fld->max_length = $rs->fields[2];
+ if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;
+ if ($fld->max_length <= 0) $fld->max_length = -1;
+ if ($fld->type == 'numeric') {
+ $fld->scale = $fld->max_length & 0xFFFF;
+ $fld->max_length >>= 16;
+ }
+ // dannym
+ // 5 hasdefault; 6 num-of-column
+ $fld->has_default = ($rs->fields[5] == 't');
+ if ($fld->has_default) {
+ $fld->default_value = $rsdefa[$rs->fields[6]];
+ }
+
+ //Freek
+ if ($rs->fields[4] == $this->true) {
+ $fld->not_null = true;
+ }
+
+ // Freek
+ if (is_array($keys)) {
+ foreach($keys as $key) {
+ if ($fld->name == $key['column_name'] AND $key['primary_key'] == $this->true)
+ $fld->primary_key = true;
+ if ($fld->name == $key['column_name'] AND $key['unique_key'] == $this->true)
+ $fld->unique = true; // What name is more compatible?
+ }
+ }
+
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
+ else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld;
+
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ if (empty($retarr)) {
+ $false = false;
+ return $false;
+ } else return $retarr;
+
+ }
+
+}
+
+?>
diff --git a/lib/adodb/drivers/adodb-postgres.inc.php b/lib/adodb/drivers/adodb-postgres.inc.php
new file mode 100644
index 0000000..5e8ce48
--- /dev/null
+++ b/lib/adodb/drivers/adodb-postgres.inc.php
@@ -0,0 +1,14 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4.
+
+ NOTE: Since 3.31, this file is no longer used, and the "postgres" driver is
+ remapped to "postgres7". Maintaining multiple postgres drivers is no easy
+ job, so hopefully this will ensure greater consistency and fewer bugs.
+*/
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-postgres64.inc.php b/lib/adodb/drivers/adodb-postgres64.inc.php
new file mode 100644
index 0000000..69d44fc
--- /dev/null
+++ b/lib/adodb/drivers/adodb-postgres64.inc.php
@@ -0,0 +1,1064 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 8.
+
+ Original version derived from Alberto Cerezal (acerezalp@dbnet.es) - DBNet Informatica & Comunicaciones.
+ 08 Nov 2000 jlim - Minor corrections, removing mysql stuff
+ 09 Nov 2000 jlim - added insertid support suggested by "Christopher Kings-Lynne" <chriskl@familyhealth.com.au>
+ jlim - changed concat operator to || and data types to MetaType to match documented pgsql types
+ see http://www.postgresql.org/devel-corner/docs/postgres/datatype.htm
+ 22 Nov 2000 jlim - added changes to FetchField() and MetaTables() contributed by "raser" <raser@mail.zen.com.tw>
+ 27 Nov 2000 jlim - added changes to _connect/_pconnect from ideas by "Lennie" <leen@wirehub.nl>
+ 15 Dec 2000 jlim - added changes suggested by Additional code changes by "Eric G. Werk" egw@netguide.dk.
+ 31 Jan 2002 jlim - finally installed postgresql. testing
+ 01 Mar 2001 jlim - Freek Dijkstra changes, also support for text type
+
+ See http://www.varlena.com/varlena/GeneralBits/47.php
+
+ -- What indexes are on my table?
+ select * from pg_indexes where tablename = 'tablename';
+
+ -- What triggers are on my table?
+ select c.relname as "Table", t.tgname as "Trigger Name",
+ t.tgconstrname as "Constraint Name", t.tgenabled as "Enabled",
+ t.tgisconstraint as "Is Constraint", cc.relname as "Referenced Table",
+ p.proname as "Function Name"
+ from pg_trigger t, pg_class c, pg_class cc, pg_proc p
+ where t.tgfoid = p.oid and t.tgrelid = c.oid
+ and t.tgconstrrelid = cc.oid
+ and c.relname = 'tablename';
+
+ -- What constraints are on my table?
+ select r.relname as "Table", c.conname as "Constraint Name",
+ contype as "Constraint Type", conkey as "Key Columns",
+ confkey as "Foreign Columns", consrc as "Source"
+ from pg_class r, pg_constraint c
+ where r.oid = c.conrelid
+ and relname = 'tablename';
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+function adodb_addslashes($s)
+{
+ $len = strlen($s);
+ if ($len == 0) return "''";
+ if (strncmp($s,"'",1) === 0 && substr($s,$len-1) == "'") return $s; // already quoted
+
+ return "'".addslashes($s)."'";
+}
+
+class ADODB_postgres64 extends ADOConnection{
+ var $databaseType = 'postgres64';
+ var $dataProvider = 'postgres';
+ var $hasInsertID = true;
+ var $_resultid = false;
+ var $concat_operator='||';
+ var $metaDatabasesSQL = "select datname from pg_database where datname not in ('template0','template1') order by 1";
+ var $metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
+ and tablename not in ('sql_features', 'sql_implementation_info', 'sql_languages',
+ 'sql_packages', 'sql_sizing', 'sql_sizing_profiles')
+ union
+ select viewname,'V' from pg_views where viewname not like 'pg\_%'";
+ //"select tablename from pg_tables where tablename not like 'pg_%' order by 1";
+ var $isoDates = true; // accepts dates in ISO format
+ var $sysDate = "CURRENT_DATE";
+ var $sysTimeStamp = "CURRENT_TIMESTAMP";
+ var $blobEncodeType = 'C';
+ var $metaColumnsSQL = "SELECT a.attname,t.typname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,a.attnum
+ FROM pg_class c, pg_attribute a,pg_type t
+ WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s')) and a.attname not like '....%%'
+AND a.attnum > 0 AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
+
+ // used when schema defined
+ var $metaColumnsSQL1 = "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum
+FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n
+WHERE relkind in ('r','v') AND (c.relname='%s' or c.relname = lower('%s'))
+ and c.relnamespace=n.oid and n.nspname='%s'
+ and a.attname not like '....%%' AND a.attnum > 0
+ AND a.atttypid = t.oid AND a.attrelid = c.oid ORDER BY a.attnum";
+
+ // get primary key etc -- from Freek Dijkstra
+ var $metaKeySQL = "SELECT ic.relname AS index_name, a.attname AS column_name,i.indisunique AS unique_key, i.indisprimary AS primary_key
+ FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a WHERE bc.oid = i.indrelid AND ic.oid = i.indexrelid AND (i.indkey[0] = a.attnum OR i.indkey[1] = a.attnum OR i.indkey[2] = a.attnum OR i.indkey[3] = a.attnum OR i.indkey[4] = a.attnum OR i.indkey[5] = a.attnum OR i.indkey[6] = a.attnum OR i.indkey[7] = a.attnum) AND a.attrelid = bc.oid AND bc.relname = '%s'";
+
+ var $hasAffectedRows = true;
+ var $hasLimit = false; // set to true for pgsql 7 only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10
+ // below suggested by Freek Dijkstra
+ var $true = 'TRUE'; // string that represents TRUE for a database
+ var $false = 'FALSE'; // string that represents FALSE for a database
+ var $fmtDate = "'Y-m-d'"; // used by DBDate() as the default date format used by the database
+ var $fmtTimeStamp = "'Y-m-d H:i:s'"; // used by DBTimeStamp as the default timestamp fmt.
+ var $hasMoveFirst = true;
+ var $hasGenID = true;
+ var $_genIDSQL = "SELECT NEXTVAL('%s')";
+ var $_genSeqSQL = "CREATE SEQUENCE %s START %s";
+ var $_dropSeqSQL = "DROP SEQUENCE %s";
+ var $metaDefaultsSQL = "SELECT d.adnum as num, d.adsrc as def from pg_attrdef d, pg_class c where d.adrelid=c.oid and c.relname='%s' order by d.adnum";
+ var $random = 'random()'; /// random function
+ var $autoRollback = true; // apparently pgsql does not autorollback properly before php 4.3.4
+ // http://bugs.php.net/bug.php?id=25404
+
+ var $_bindInputArray = false; // requires postgresql 7.3+ and ability to modify database
+ var $disableBlobs = false; // set to true to disable blob checking, resulting in 2-5% improvement in performance.
+
+ // The last (fmtTimeStamp is not entirely correct:
+ // PostgreSQL also has support for time zones,
+ // and writes these time in this format: "2001-03-01 18:59:26+02".
+ // There is no code for the "+02" time zone information, so I just left that out.
+ // I'm not familiar enough with both ADODB as well as Postgres
+ // to know what the concequences are. The other values are correct (wheren't in 0.94)
+ // -- Freek Dijkstra
+
+ function ADODB_postgres64()
+ {
+ // changes the metaColumnsSQL, adds columns: attnum[6]
+ }
+
+ function ServerInfo()
+ {
+ if (isset($this->version)) return $this->version;
+
+ $arr['description'] = $this->GetOne("select version()");
+ $arr['version'] = ADOConnection::_findvers($arr['description']);
+ $this->version = $arr;
+ return $arr;
+ }
+
+ function IfNull( $field, $ifNull )
+ {
+ return " coalesce($field, $ifNull) ";
+ }
+
+ // get the last id - never tested
+ function pg_insert_id($tablename,$fieldname)
+ {
+ $result=pg_exec($this->_connectionID, "SELECT last_value FROM ${tablename}_${fieldname}_seq");
+ if ($result) {
+ $arr = @pg_fetch_row($result,0);
+ pg_freeresult($result);
+ if (isset($arr[0])) return $arr[0];
+ }
+ return false;
+ }
+
+/* Warning from http://www.php.net/manual/function.pg-getlastoid.php:
+Using a OID as a unique identifier is not generally wise.
+Unless you are very careful, you might end up with a tuple having
+a different OID if a database must be reloaded. */
+ function _insertid($table,$column)
+ {
+ if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
+ $oid = pg_getlastoid($this->_resultid);
+ // to really return the id, we need the table and column-name, else we can only return the oid != id
+ return empty($table) || empty($column) ? $oid : $this->GetOne("SELECT $column FROM $table WHERE oid=".(int)$oid);
+ }
+
+// I get this error with PHP before 4.0.6 - jlim
+// Warning: This compilation does not support pg_cmdtuples() in adodb-postgres.inc.php on line 44
+ function _affectedrows()
+ {
+ if (!is_resource($this->_resultid) || get_resource_type($this->_resultid) !== 'pgsql result') return false;
+ return pg_cmdtuples($this->_resultid);
+ }
+
+
+ // returns true/false
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+ return @pg_Exec($this->_connectionID, "begin ".$this->_transmode);
+ }
+
+ function RowLock($tables,$where,$flds='1 as ignore')
+ {
+ if (!$this->transCnt) $this->BeginTrans();
+ return $this->GetOne("select $flds from $tables where $where for update");
+ }
+
+ // returns true/false.
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+
+ $this->transCnt -= 1;
+ return @pg_Exec($this->_connectionID, "commit");
+ }
+
+ // returns true/false
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt -= 1;
+ return @pg_Exec($this->_connectionID, "rollback");
+ }
+
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ $info = $this->ServerInfo();
+ if ($info['version'] >= 7.3) {
+ $this->metaTablesSQL = "select tablename,'T' from pg_tables where tablename not like 'pg\_%'
+ and schemaname not in ( 'pg_catalog','information_schema')
+ union
+ select viewname,'V' from pg_views where viewname not like 'pg\_%' and schemaname not in ( 'pg_catalog','information_schema') ";
+ }
+ if ($mask) {
+ $save = $this->metaTablesSQL;
+ $mask = $this->qstr(strtolower($mask));
+ if ($info['version']>=7.3)
+ $this->metaTablesSQL = "
+select tablename,'T' from pg_tables where tablename like $mask and schemaname not in ( 'pg_catalog','information_schema')
+ union
+select viewname,'V' from pg_views where viewname like $mask and schemaname not in ( 'pg_catalog','information_schema') ";
+ else
+ $this->metaTablesSQL = "
+select tablename,'T' from pg_tables where tablename like $mask
+ union
+select viewname,'V' from pg_views where viewname like $mask";
+ }
+ $ret =& ADOConnection::MetaTables($ttype,$showSchema);
+
+ if ($mask) {
+ $this->metaTablesSQL = $save;
+ }
+ return $ret;
+ }
+
+
+ // if magic quotes disabled, use pg_escape_string()
+ function qstr($s,$magic_quotes=false)
+ {
+ if (!$magic_quotes) {
+ if (ADODB_PHPVER >= 0x5200) {
+ return "'".pg_escape_string($this->_connectionID,$s)."'";
+ }
+ if (ADODB_PHPVER >= 0x4200) {
+ return "'".pg_escape_string($s)."'";
+ }
+ if ($this->replaceQuote[0] == '\\'){
+ $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\\000"),$s);
+ }
+ return "'".str_replace("'",$this->replaceQuote,$s)."'";
+ }
+
+ // undo magic quotes for "
+ $s = str_replace('\\"','"',$s);
+ return "'$s'";
+ }
+
+
+
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysTimeStamp;
+ $s = 'TO_CHAR('.$col.",'";
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= 'YYYY';
+ break;
+ case 'Q':
+ case 'q':
+ $s .= 'Q';
+ break;
+
+ case 'M':
+ $s .= 'Mon';
+ break;
+
+ case 'm':
+ $s .= 'MM';
+ break;
+ case 'D':
+ case 'd':
+ $s .= 'DD';
+ break;
+
+ case 'H':
+ $s.= 'HH24';
+ break;
+
+ case 'h':
+ $s .= 'HH';
+ break;
+
+ case 'i':
+ $s .= 'MI';
+ break;
+
+ case 's':
+ $s .= 'SS';
+ break;
+
+ case 'a':
+ case 'A':
+ $s .= 'AM';
+ break;
+
+ case 'w':
+ $s .= 'D';
+ break;
+
+ case 'l':
+ $s .= 'DAY';
+ break;
+
+ case 'W':
+ $s .= 'WW';
+ break;
+
+ default:
+ // handle escape characters...
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
+ else $s .= '"'.$ch.'"';
+
+ }
+ }
+ return $s. "')";
+ }
+
+
+
+ /*
+ * Load a Large Object from a file
+ * - the procedure stores the object id in the table and imports the object using
+ * postgres proprietary blob handling routines
+ *
+ * contributed by Mattia Rossi mattia@technologist.com
+ * modified for safe mode by juraj chlebec
+ */
+ function UpdateBlobFile($table,$column,$path,$where,$blobtype='BLOB')
+ {
+ pg_exec ($this->_connectionID, "begin");
+
+ $fd = fopen($path,'r');
+ $contents = fread($fd,filesize($path));
+ fclose($fd);
+
+ $oid = pg_lo_create($this->_connectionID);
+ $handle = pg_lo_open($this->_connectionID, $oid, 'w');
+ pg_lo_write($handle, $contents);
+ pg_lo_close($handle);
+
+ // $oid = pg_lo_import ($path);
+ pg_exec($this->_connectionID, "commit");
+ $rs = ADOConnection::UpdateBlob($table,$column,$oid,$where,$blobtype);
+ $rez = !empty($rs);
+ return $rez;
+ }
+
+ /*
+ * Deletes/Unlinks a Blob from the database, otherwise it
+ * will be left behind
+ *
+ * Returns TRUE on success or FALSE on failure.
+ *
+ * contributed by Todd Rogers todd#windfox.net
+ */
+ function BlobDelete( $blob )
+ {
+ pg_exec ($this->_connectionID, "begin");
+ $result = @pg_lo_unlink($blob);
+ pg_exec ($this->_connectionID, "commit");
+ return( $result );
+ }
+
+ /*
+ Hueristic - not guaranteed to work.
+ */
+ function GuessOID($oid)
+ {
+ if (strlen($oid)>16) return false;
+ return is_numeric($oid);
+ }
+
+ /*
+ * If an OID is detected, then we use pg_lo_* to open the oid file and read the
+ * real blob from the db using the oid supplied as a parameter. If you are storing
+ * blobs using bytea, we autodetect and process it so this function is not needed.
+ *
+ * contributed by Mattia Rossi mattia@technologist.com
+ *
+ * see http://www.postgresql.org/idocs/index.php?largeobjects.html
+ *
+ * Since adodb 4.54, this returns the blob, instead of sending it to stdout. Also
+ * added maxsize parameter, which defaults to $db->maxblobsize if not defined.
+ */
+ function BlobDecode($blob,$maxsize=false,$hastrans=true)
+ {
+ if (!$this->GuessOID($blob)) return $blob;
+
+ if ($hastrans) @pg_exec($this->_connectionID,"begin");
+ $fd = @pg_lo_open($this->_connectionID,$blob,"r");
+ if ($fd === false) {
+ if ($hastrans) @pg_exec($this->_connectionID,"commit");
+ return $blob;
+ }
+ if (!$maxsize) $maxsize = $this->maxblobsize;
+ $realblob = @pg_loread($fd,$maxsize);
+ @pg_loclose($fd);
+ if ($hastrans) @pg_exec($this->_connectionID,"commit");
+ return $realblob;
+ }
+
+ /*
+ See http://www.postgresql.org/idocs/index.php?datatype-binary.html
+
+ NOTE: SQL string literals (input strings) must be preceded with two backslashes
+ due to the fact that they must pass through two parsers in the PostgreSQL
+ backend.
+ */
+ function BlobEncode($blob)
+ {
+ if (ADODB_PHPVER >= 0x5200) return pg_escape_bytea($this->_connectionID, $blob);
+ if (ADODB_PHPVER >= 0x4200) return pg_escape_bytea($blob);
+
+ /*92=backslash, 0=null, 39=single-quote*/
+ $badch = array(chr(92),chr(0),chr(39)); # \ null '
+ $fixch = array('\\\\134','\\\\000','\\\\047');
+ return adodb_str_replace($badch,$fixch,$blob);
+
+ // note that there is a pg_escape_bytea function only for php 4.2.0 or later
+ }
+
+ // assumes bytea for blob, and varchar for clob
+ function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
+ {
+
+ if ($blobtype == 'CLOB') {
+ return $this->Execute("UPDATE $table SET $column=" . $this->qstr($val) . " WHERE $where");
+ }
+ // do not use bind params which uses qstr(), as blobencode() already quotes data
+ return $this->Execute("UPDATE $table SET $column='".$this->BlobEncode($val)."'::bytea WHERE $where");
+ }
+
+ function OffsetDate($dayFraction,$date=false)
+ {
+ if (!$date) $date = $this->sysDate;
+ else if (strncmp($date,"'",1) == 0) {
+ $len = strlen($date);
+ if (10 <= $len && $len <= 12) $date = 'date '.$date;
+ else $date = 'timestamp '.$date;
+ }
+ return "($date+interval'$dayFraction days')";
+ }
+
+
+ // for schema support, pass in the $table param "$schema.$tabname".
+ // converts field names to lowercase, $upper is ignored
+ // see http://phplens.com/lens/lensforum/msgs.php?id=14018 for more info
+ function &MetaColumns($table,$normalize=true)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $schema = false;
+ $false = false;
+ $this->_findschema($table,$schema);
+
+ if ($normalize) $table = strtolower($table);
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+
+ if ($schema) $rs =& $this->Execute(sprintf($this->metaColumnsSQL1,$table,$table,$schema));
+ else $rs =& $this->Execute(sprintf($this->metaColumnsSQL,$table,$table));
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if ($rs === false) {
+ return $false;
+ }
+ if (!empty($this->metaKeySQL)) {
+ // If we want the primary keys, we have to issue a separate query
+ // Of course, a modified version of the metaColumnsSQL query using a
+ // LEFT JOIN would have been much more elegant, but postgres does
+ // not support OUTER JOINS. So here is the clumsy way.
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+
+ $rskey = $this->Execute(sprintf($this->metaKeySQL,($table)));
+ // fetch all result in once for performance.
+ $keys =& $rskey->GetArray();
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ $rskey->Close();
+ unset($rskey);
+ }
+
+ $rsdefa = array();
+ if (!empty($this->metaDefaultsSQL)) {
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $sql = sprintf($this->metaDefaultsSQL, ($table));
+ $rsdef = $this->Execute($sql);
+ if (isset($savem)) $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if ($rsdef) {
+ while (!$rsdef->EOF) {
+ $num = $rsdef->fields['num'];
+ $s = $rsdef->fields['def'];
+ if (strpos($s,'::')===false && substr($s, 0, 1) == "'") { /* quoted strings hack... for now... fixme */
+ $s = substr($s, 1);
+ $s = substr($s, 0, strlen($s) - 1);
+ }
+
+ $rsdefa[$num] = $s;
+ $rsdef->MoveNext();
+ }
+ } else {
+ ADOConnection::outp( "==> SQL => " . $sql);
+ }
+ unset($rsdef);
+ }
+
+ $retarr = array();
+ while (!$rs->EOF) {
+ $fld = new ADOFieldObject();
+ $fld->name = $rs->fields[0];
+ $fld->type = $rs->fields[1];
+ $fld->max_length = $rs->fields[2];
+ $fld->attnum = $rs->fields[6];
+
+ if ($fld->max_length <= 0) $fld->max_length = $rs->fields[3]-4;
+ if ($fld->max_length <= 0) $fld->max_length = -1;
+ if ($fld->type == 'numeric') {
+ $fld->scale = $fld->max_length & 0xFFFF;
+ $fld->max_length >>= 16;
+ }
+ // dannym
+ // 5 hasdefault; 6 num-of-column
+ $fld->has_default = ($rs->fields[5] == 't');
+ if ($fld->has_default) {
+ $fld->default_value = $rsdefa[$rs->fields[6]];
+ }
+
+ //Freek
+ $fld->not_null = $rs->fields[4] == 't';
+
+
+ // Freek
+ if (is_array($keys)) {
+ foreach($keys as $key) {
+ if ($fld->name == $key['column_name'] AND $key['primary_key'] == 't')
+ $fld->primary_key = true;
+ if ($fld->name == $key['column_name'] AND $key['unique_key'] == 't')
+ $fld->unique = true; // What name is more compatible?
+ }
+ }
+
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
+ else $retarr[($normalize) ? strtoupper($fld->name) : $fld->name] = $fld;
+
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ if (empty($retarr))
+ return $false;
+ else
+ return $retarr;
+
+ }
+
+ function &MetaIndexes ($table, $primary = FALSE)
+ {
+ global $ADODB_FETCH_MODE;
+
+ $schema = false;
+ $this->_findschema($table,$schema);
+
+ if ($schema) { // requires pgsql 7.3+ - pg_namespace used.
+ $sql = '
+SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"
+FROM pg_catalog.pg_class c
+JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid
+JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
+ ,pg_namespace n
+WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\')) and c.relnamespace=c2.relnamespace and c.relnamespace=n.oid and n.nspname=\'%s\'';
+ } else {
+ $sql = '
+SELECT c.relname as "Name", i.indisunique as "Unique", i.indkey as "Columns"
+FROM pg_catalog.pg_class c
+JOIN pg_catalog.pg_index i ON i.indexrelid=c.oid
+JOIN pg_catalog.pg_class c2 ON c2.oid=i.indrelid
+WHERE (c2.relname=\'%s\' or c2.relname=lower(\'%s\'))';
+ }
+
+ if ($primary == FALSE) {
+ $sql .= ' AND i.indisprimary=false;';
+ }
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+
+ $rs = $this->Execute(sprintf($sql,$table,$table,$schema));
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ if (!is_object($rs)) {
+ $false = false;
+ return $false;
+ }
+
+ $col_names = $this->MetaColumnNames($table,true,true);
+ //3rd param is use attnum,
+ // see http://sourceforge.net/tracker/index.php?func=detail&aid=1451245&group_id=42718&atid=433976
+ $indexes = array();
+ while ($row = $rs->FetchRow()) {
+ $columns = array();
+ foreach (explode(' ', $row[2]) as $col) {
+ $columns[] = $col_names[$col];
+ }
+
+ $indexes[$row[0]] = array(
+ 'unique' => ($row[1] == 't'),
+ 'columns' => $columns
+ );
+ }
+ return $indexes;
+ }
+
+ // returns true or false
+ //
+ // examples:
+ // $db->Connect("host=host1 user=user1 password=secret port=4341");
+ // $db->Connect('host1','user1','secret');
+ function _connect($str,$user='',$pwd='',$db='',$ctype=0)
+ {
+
+ if (!function_exists('pg_connect')) return null;
+
+ $this->_errorMsg = false;
+
+ if ($user || $pwd || $db) {
+ $user = adodb_addslashes($user);
+ $pwd = adodb_addslashes($pwd);
+ if (strlen($db) == 0) $db = 'template1';
+ $db = adodb_addslashes($db);
+ if ($str) {
+ $host = split(":", $str);
+ if ($host[0]) $str = "host=".adodb_addslashes($host[0]);
+ else $str = '';
+ if (isset($host[1])) $str .= " port=$host[1]";
+ else if (!empty($this->port)) $str .= " port=".$this->port;
+ }
+ if ($user) $str .= " user=".$user;
+ if ($pwd) $str .= " password=".$pwd;
+ if ($db) $str .= " dbname=".$db;
+ }
+
+ //if ($user) $linea = "user=$user host=$linea password=$pwd dbname=$db port=5432";
+
+ if ($ctype === 1) { // persistent
+ $this->_connectionID = pg_pconnect($str);
+ } else {
+ if ($ctype === -1) { // nconnect, we trick pgsql ext by changing the connection str
+ static $ncnt;
+
+ if (empty($ncnt)) $ncnt = 1;
+ else $ncnt += 1;
+
+ $str .= str_repeat(' ',$ncnt);
+ }
+ $this->_connectionID = pg_connect($str);
+ }
+ if ($this->_connectionID === false) return false;
+ $this->Execute("set datestyle='ISO'");
+
+ $info = $this->ServerInfo();
+ $this->pgVersion = (float) substr($info['version'],0,3);
+ if ($this->pgVersion >= 7.1) { // good till version 999
+ $this->_nestedSQL = true;
+ }
+ return true;
+ }
+
+ function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName)
+ {
+ return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabaseName,-1);
+ }
+
+ // returns true or false
+ //
+ // examples:
+ // $db->PConnect("host=host1 user=user1 password=secret port=4341");
+ // $db->PConnect('host1','user1','secret');
+ function _pconnect($str,$user='',$pwd='',$db='')
+ {
+ return $this->_connect($str,$user,$pwd,$db,1);
+ }
+
+
+ // returns queryID or false
+ function _query($sql,$inputarr)
+ {
+ $this->_errorMsg = false;
+ if ($inputarr) {
+ /*
+ It appears that PREPARE/EXECUTE is slower for many queries.
+
+ For query executed 1000 times:
+ "select id,firstname,lastname from adoxyz
+ where firstname not like ? and lastname not like ? and id = ?"
+
+ with plan = 1.51861286163 secs
+ no plan = 1.26903700829 secs
+
+
+
+ */
+ $plan = 'P'.md5($sql);
+
+ $execp = '';
+ foreach($inputarr as $v) {
+ if ($execp) $execp .= ',';
+ if (is_string($v)) {
+ if (strncmp($v,"'",1) !== 0) $execp .= $this->qstr($v);
+ } else {
+ $execp .= $v;
+ }
+ }
+
+ if ($execp) $exsql = "EXECUTE $plan ($execp)";
+ else $exsql = "EXECUTE $plan";
+
+
+ $rez = @pg_exec($this->_connectionID,$exsql);
+ if (!$rez) {
+ # Perhaps plan does not exist? Prepare/compile plan.
+ $params = '';
+ foreach($inputarr as $v) {
+ if ($params) $params .= ',';
+ if (is_string($v)) {
+ $params .= 'VARCHAR';
+ } else if (is_integer($v)) {
+ $params .= 'INTEGER';
+ } else {
+ $params .= "REAL";
+ }
+ }
+ $sqlarr = explode('?',$sql);
+ //print_r($sqlarr);
+ $sql = '';
+ $i = 1;
+ foreach($sqlarr as $v) {
+ $sql .= $v.' $'.$i;
+ $i++;
+ }
+ $s = "PREPARE $plan ($params) AS ".substr($sql,0,strlen($sql)-2);
+ //adodb_pr($s);
+ $rez = pg_exec($this->_connectionID,$s);
+ //echo $this->ErrorMsg();
+ }
+ if ($rez)
+ $rez = pg_exec($this->_connectionID,$exsql);
+ } else {
+ //adodb_backtrace();
+ $rez = pg_exec($this->_connectionID,$sql);
+ }
+ // check if no data returned, then no need to create real recordset
+ if ($rez && pg_numfields($rez) <= 0) {
+ if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {
+ pg_freeresult($this->_resultid);
+ }
+ $this->_resultid = $rez;
+ return true;
+ }
+
+ return $rez;
+ }
+
+ function _errconnect()
+ {
+ if (defined('DB_ERROR_CONNECT_FAILED')) return DB_ERROR_CONNECT_FAILED;
+ else return 'Database connection failed';
+ }
+
+ /* Returns: the last error message from previous database operation */
+ function ErrorMsg()
+ {
+ if ($this->_errorMsg !== false) return $this->_errorMsg;
+ if (ADODB_PHPVER >= 0x4300) {
+ if (!empty($this->_resultid)) {
+ $this->_errorMsg = @pg_result_error($this->_resultid);
+ if ($this->_errorMsg) return $this->_errorMsg;
+ }
+
+ if (!empty($this->_connectionID)) {
+ $this->_errorMsg = @pg_last_error($this->_connectionID);
+ } else $this->_errorMsg = $this->_errconnect();
+ } else {
+ if (empty($this->_connectionID)) $this->_errconnect();
+ else $this->_errorMsg = @pg_errormessage($this->_connectionID);
+ }
+ return $this->_errorMsg;
+ }
+
+ function ErrorNo()
+ {
+ $e = $this->ErrorMsg();
+ if (strlen($e)) {
+ return ADOConnection::MetaError($e);
+ }
+ return 0;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ if ($this->transCnt) $this->RollbackTrans();
+ if ($this->_resultid) {
+ @pg_freeresult($this->_resultid);
+ $this->_resultid = false;
+ }
+ @pg_close($this->_connectionID);
+ $this->_connectionID = false;
+ return true;
+ }
+
+
+ /*
+ * Maximum size of C field
+ */
+ function CharMax()
+ {
+ return 1000000000; // should be 1 Gb?
+ }
+
+ /*
+ * Maximum size of X field
+ */
+ function TextMax()
+ {
+ return 1000000000; // should be 1 Gb?
+ }
+
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_postgres64 extends ADORecordSet{
+ var $_blobArr;
+ var $databaseType = "postgres64";
+ var $canSeek = true;
+ function ADORecordSet_postgres64($queryID,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch ($mode)
+ {
+ case ADODB_FETCH_NUM: $this->fetchMode = PGSQL_NUM; break;
+ case ADODB_FETCH_ASSOC:$this->fetchMode = PGSQL_ASSOC; break;
+
+ case ADODB_FETCH_DEFAULT:
+ case ADODB_FETCH_BOTH:
+ default: $this->fetchMode = PGSQL_BOTH; break;
+ }
+ $this->adodbFetchMode = $mode;
+ $this->ADORecordSet($queryID);
+ }
+
+ function &GetRowAssoc($upper=true)
+ {
+ if ($this->fetchMode == PGSQL_ASSOC && !$upper) return $this->fields;
+ $row =& ADORecordSet::GetRowAssoc($upper);
+ return $row;
+ }
+
+ function _initrs()
+ {
+ global $ADODB_COUNTRECS;
+ $qid = $this->_queryID;
+ $this->_numOfRows = ($ADODB_COUNTRECS)? @pg_numrows($qid):-1;
+ $this->_numOfFields = @pg_numfields($qid);
+
+ // cache types for blob decode check
+ // apparently pg_fieldtype actually performs an sql query on the database to get the type.
+ if (empty($this->connection->noBlobs))
+ for ($i=0, $max = $this->_numOfFields; $i < $max; $i++) {
+ if (pg_fieldtype($qid,$i) == 'bytea') {
+ $this->_blobArr[$i] = pg_fieldname($qid,$i);
+ }
+ }
+ }
+
+ /* Use associative array to get fields array */
+ function Fields($colname)
+ {
+ if ($this->fetchMode != PGSQL_NUM) 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)]];
+ }
+
+ function &FetchField($off = 0)
+ {
+ // offsets begin at 0
+
+ $o= new ADOFieldObject();
+ $o->name = @pg_fieldname($this->_queryID,$off);
+ $o->type = @pg_fieldtype($this->_queryID,$off);
+ $o->max_length = @pg_fieldsize($this->_queryID,$off);
+ return $o;
+ }
+
+ function _seek($row)
+ {
+ return @pg_fetch_row($this->_queryID,$row);
+ }
+
+ function _decode($blob)
+ {
+ eval('$realblob="'.adodb_str_replace(array('"','$'),array('\"','\$'),$blob).'";');
+ return $realblob;
+ }
+
+ function _fixblobs()
+ {
+ if ($this->fetchMode == PGSQL_NUM || $this->fetchMode == PGSQL_BOTH) {
+ foreach($this->_blobArr as $k => $v) {
+ $this->fields[$k] = ADORecordSet_postgres64::_decode($this->fields[$k]);
+ }
+ }
+ if ($this->fetchMode == PGSQL_ASSOC || $this->fetchMode == PGSQL_BOTH) {
+ foreach($this->_blobArr as $k => $v) {
+ $this->fields[$v] = ADORecordSet_postgres64::_decode($this->fields[$v]);
+ }
+ }
+ }
+
+ // 10% speedup to move MoveNext to child class
+ function MoveNext()
+ {
+ if (!$this->EOF) {
+ $this->_currentRow++;
+ if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+ if (is_array($this->fields) && $this->fields) {
+ if (isset($this->_blobArr)) $this->_fixblobs();
+ return true;
+ }
+ }
+ $this->fields = false;
+ $this->EOF = true;
+ }
+ return false;
+ }
+
+ function _fetch()
+ {
+
+ if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
+ return false;
+
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+
+ if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
+
+ return (is_array($this->fields));
+ }
+
+ function _close()
+ {
+ return @pg_freeresult($this->_queryID);
+ }
+
+ function MetaType($t,$len=-1,$fieldobj=false)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ switch (strtoupper($t)) {
+ case 'MONEY': // stupid, postgres expects money to be a string
+ case 'INTERVAL':
+ case 'CHAR':
+ case 'CHARACTER':
+ case 'VARCHAR':
+ case 'NAME':
+ case 'BPCHAR':
+ case '_VARCHAR':
+ case 'INET':
+ case 'MACADDR':
+ if ($len <= $this->blobSize) return 'C';
+
+ case 'TEXT':
+ return 'X';
+
+ case 'IMAGE': // user defined type
+ case 'BLOB': // user defined type
+ case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
+ case 'VARBIT':
+ case 'BYTEA':
+ return 'B';
+
+ case 'BOOL':
+ case 'BOOLEAN':
+ return 'L';
+
+ case 'DATE':
+ return 'D';
+
+
+ case 'TIMESTAMP WITHOUT TIME ZONE':
+ case 'TIME':
+ case 'DATETIME':
+ case 'TIMESTAMP':
+ case 'TIMESTAMPTZ':
+ return 'T';
+
+ case 'SMALLINT':
+ case 'BIGINT':
+ case 'INTEGER':
+ case 'INT8':
+ case 'INT4':
+ case 'INT2':
+ if (isset($fieldobj) &&
+ empty($fieldobj->primary_key) && empty($fieldobj->unique)) return 'I';
+
+ case 'OID':
+ case 'SERIAL':
+ return 'R';
+
+ default:
+ return 'N';
+ }
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-postgres7.inc.php b/lib/adodb/drivers/adodb-postgres7.inc.php
new file mode 100644
index 0000000..5c3d7bb
--- /dev/null
+++ b/lib/adodb/drivers/adodb-postgres7.inc.php
@@ -0,0 +1,264 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4.
+
+ Postgres7 support.
+ 28 Feb 2001: Currently indicate that we support LIMIT
+ 01 Dec 2001: dannym added support for default values
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR."/drivers/adodb-postgres64.inc.php");
+
+class ADODB_postgres7 extends ADODB_postgres64 {
+ var $databaseType = 'postgres7';
+ var $hasLimit = true; // set to true for pgsql 6.5+ only. support pgsql/mysql SELECT * FROM TABLE LIMIT 10
+ var $ansiOuter = true;
+ var $charSet = true; //set to true for Postgres 7 and above - PG client supports encodings
+
+ function ADODB_postgres7()
+ {
+ $this->ADODB_postgres64();
+ if (ADODB_ASSOC_CASE !== 2) {
+ $this->rsPrefix .= 'assoc_';
+ }
+ $this->_bindInputArray = PHP_VERSION >= 5.1;
+ }
+
+
+ // the following should be compat with postgresql 7.2,
+ // which makes obsolete the LIMIT limit,offset syntax
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ {
+ $offsetStr = ($offset >= 0) ? " OFFSET ".((integer)$offset) : '';
+ $limitStr = ($nrows >= 0) ? " LIMIT ".((integer)$nrows) : '';
+ if ($secs2cache)
+ $rs =& $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr);
+ else
+ $rs =& $this->Execute($sql."$limitStr$offsetStr",$inputarr);
+
+ return $rs;
+ }
+ /*
+ function Prepare($sql)
+ {
+ $info = $this->ServerInfo();
+ if ($info['version']>=7.3) {
+ return array($sql,false);
+ }
+ return $sql;
+ }
+ */
+
+
+ // from Edward Jaramilla, improved version - works on pg 7.4
+ function MetaForeignKeys($table, $owner=false, $upper=false)
+ {
+ $sql = 'SELECT t.tgargs as args
+ FROM
+ pg_trigger t,pg_class c,pg_proc p
+ WHERE
+ t.tgenabled AND
+ t.tgrelid = c.oid AND
+ t.tgfoid = p.oid AND
+ p.proname = \'RI_FKey_check_ins\' AND
+ c.relname = \''.strtolower($table).'\'
+ ORDER BY
+ t.tgrelid';
+
+ $rs =& $this->Execute($sql);
+
+ if (!$rs || $rs->EOF) return false;
+
+ $arr =& $rs->GetArray();
+ $a = array();
+ foreach($arr as $v) {
+ $data = explode(chr(0), $v['args']);
+ $size = count($data)-1; //-1 because the last node is empty
+ for($i = 4; $i < $size; $i++) {
+ if ($upper)
+ $a[strtoupper($data[2])][] = strtoupper($data[$i].'='.$data[++$i]);
+ else
+ $a[$data[2]][] = $data[$i].'='.$data[++$i];
+ }
+ }
+ return $a;
+ }
+
+ function _query($sql,$inputarr)
+ {
+ if (! $this->_bindInputArray) {
+ // We don't have native support for parameterized queries, so let's emulate it at the parent
+ return ADODB_postgres64::_query($sql, $inputarr);
+ }
+ $this->_errorMsg = false;
+ // -- added Cristiano da Cunha Duarte
+ if ($inputarr) {
+ $sqlarr = explode('?',trim($sql));
+ $sql = '';
+ $i = 1;
+ $last = sizeof($sqlarr)-1;
+ foreach($sqlarr as $v) {
+ if ($last < $i) $sql .= $v;
+ else $sql .= $v.' $'.$i;
+ $i++;
+ }
+
+ $rez = pg_query_params($this->_connectionID,$sql, $inputarr);
+ } else {
+ $rez = pg_query($this->_connectionID,$sql);
+ }
+ // check if no data returned, then no need to create real recordset
+ if ($rez && pg_numfields($rez) <= 0) {
+ if (is_resource($this->_resultid) && get_resource_type($this->_resultid) === 'pgsql result') {
+ pg_freeresult($this->_resultid);
+ }
+ $this->_resultid = $rez;
+ return true;
+ }
+ return $rez;
+ }
+
+ // this is a set of functions for managing client encoding - very important if the encodings
+ // of your database and your output target (i.e. HTML) don't match
+ //for instance, you may have UNICODE database and server it on-site as WIN1251 etc.
+ // GetCharSet - get the name of the character set the client is using now
+ // the functions should work with Postgres 7.0 and above, the set of charsets supported
+ // depends on compile flags of postgres distribution - if no charsets were compiled into the server
+ // it will return 'SQL_ANSI' always
+ function GetCharSet()
+ {
+ //we will use ADO's builtin property charSet
+ $this->charSet = @pg_client_encoding($this->_connectionID);
+ if (!$this->charSet) {
+ return false;
+ } else {
+ return $this->charSet;
+ }
+ }
+
+ // SetCharSet - switch the client encoding
+ function SetCharSet($charset_name)
+ {
+ $this->GetCharSet();
+ if ($this->charSet !== $charset_name) {
+ $if = pg_set_client_encoding($this->_connectionID, $charset_name);
+ if ($if == "0" & $this->GetCharSet() == $charset_name) {
+ return true;
+ } else return false;
+ } else return true;
+ }
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordSet_postgres7 extends ADORecordSet_postgres64{
+
+ var $databaseType = "postgres7";
+
+
+ function ADORecordSet_postgres7($queryID,$mode=false)
+ {
+ $this->ADORecordSet_postgres64($queryID,$mode);
+ }
+
+ // 10% speedup to move MoveNext to child class
+ function MoveNext()
+ {
+ if (!$this->EOF) {
+ $this->_currentRow++;
+ if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+
+ if (is_array($this->fields)) {
+ if ($this->fields && isset($this->_blobArr)) $this->_fixblobs();
+ return true;
+ }
+ }
+ $this->fields = false;
+ $this->EOF = true;
+ }
+ return false;
+ }
+
+}
+
+class ADORecordSet_assoc_postgres7 extends ADORecordSet_postgres64{
+
+ var $databaseType = "postgres7";
+
+
+ function ADORecordSet_assoc_postgres7($queryID,$mode=false)
+ {
+ $this->ADORecordSet_postgres64($queryID,$mode);
+ }
+
+ function _fetch()
+ {
+ if ($this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0)
+ return false;
+
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+
+ if ($this->fields) {
+ if (isset($this->_blobArr)) $this->_fixblobs();
+ $this->_updatefields();
+ }
+
+ return (is_array($this->fields));
+ }
+
+ // Create associative array
+ function _updatefields()
+ {
+ if (ADODB_ASSOC_CASE == 2) return; // native
+
+ $arr = array();
+ $lowercase = (ADODB_ASSOC_CASE == 0);
+
+ foreach($this->fields as $k => $v) {
+ if (is_integer($k)) $arr[$k] = $v;
+ else {
+ if ($lowercase)
+ $arr[strtolower($k)] = $v;
+ else
+ $arr[strtoupper($k)] = $v;
+ }
+ }
+ $this->fields = $arr;
+ }
+
+ function MoveNext()
+ {
+ if (!$this->EOF) {
+ $this->_currentRow++;
+ if ($this->_numOfRows < 0 || $this->_numOfRows > $this->_currentRow) {
+ $this->fields = @pg_fetch_array($this->_queryID,$this->_currentRow,$this->fetchMode);
+
+ if (is_array($this->fields)) {
+ if ($this->fields) {
+ if (isset($this->_blobArr)) $this->_fixblobs();
+
+ $this->_updatefields();
+ }
+ return true;
+ }
+ }
+
+
+ $this->fields = false;
+ $this->EOF = true;
+ }
+ return false;
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-postgres8.inc.php b/lib/adodb/drivers/adodb-postgres8.inc.php
new file mode 100644
index 0000000..f3712a3
--- /dev/null
+++ b/lib/adodb/drivers/adodb-postgres8.inc.php
@@ -0,0 +1,12 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4.
+
+ NOTE: The "postgres8" driver is remapped to "postgres7".
+*/
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-proxy.inc.php b/lib/adodb/drivers/adodb-proxy.inc.php
new file mode 100644
index 0000000..022a64e
--- /dev/null
+++ b/lib/adodb/drivers/adodb-proxy.inc.php
@@ -0,0 +1,33 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4.
+
+ Synonym for csv driver.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (! defined("_ADODB_PROXY_LAYER")) {
+ define("_ADODB_PROXY_LAYER", 1 );
+ include(ADODB_DIR."/drivers/adodb-csv.inc.php");
+
+ class ADODB_proxy extends ADODB_csv {
+ var $databaseType = 'proxy';
+ var $databaseProvider = 'csv';
+ }
+ class ADORecordset_proxy extends ADORecordset_csv {
+ var $databaseType = "proxy";
+
+ function ADORecordset_proxy($id,$mode=false)
+ {
+ $this->ADORecordset($id,$mode);
+ }
+ };
+} // define
+
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-sapdb.inc.php b/lib/adodb/drivers/adodb-sapdb.inc.php
new file mode 100644
index 0000000..493893e
--- /dev/null
+++ b/lib/adodb/drivers/adodb-sapdb.inc.php
@@ -0,0 +1,184 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ SAPDB data driver. Requires ODBC.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+if (!defined('ADODB_SAPDB')){
+define('ADODB_SAPDB',1);
+
+class ADODB_SAPDB extends ADODB_odbc {
+ var $databaseType = "sapdb";
+ var $concat_operator = '||';
+ var $sysDate = 'DATE';
+ var $sysTimeStamp = 'TIMESTAMP';
+ var $fmtDate = "'Y-m-d'"; /// used by DBDate() as the default date format used by the database
+ var $fmtTimeStamp = "'Y-m-d H:i:s'"; /// used by DBTimeStamp as the default timestamp fmt.
+ var $hasInsertId = true;
+ var $_bindInputArray = true;
+
+ function ADODB_SAPDB()
+ {
+ //if (strncmp(PHP_OS,'WIN',3) === 0) $this->curmode = SQL_CUR_USE_ODBC;
+ $this->ADODB_odbc();
+ }
+
+ function ServerInfo()
+ {
+ $info = ADODB_odbc::ServerInfo();
+ if (!$info['version'] && preg_match('/([0-9.]+)/',$info['description'],$matches)) {
+ $info['version'] = $matches[1];
+ }
+ return $info;
+ }
+
+ function MetaPrimaryKeys($table)
+ {
+ $table = $this->Quote(strtoupper($table));
+
+ return $this->GetCol("SELECT columnname FROM COLUMNS WHERE tablename=$table AND mode='KEY' ORDER BY pos");
+ }
+
+ function &MetaIndexes ($table, $primary = FALSE)
+ {
+ $table = $this->Quote(strtoupper($table));
+
+ $sql = "SELECT INDEXNAME,TYPE,COLUMNNAME FROM INDEXCOLUMNS ".
+ " WHERE TABLENAME=$table".
+ " ORDER BY INDEXNAME,COLUMNNO";
+
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+
+ $rs = $this->Execute($sql);
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ if (!is_object($rs)) {
+ return FALSE;
+ }
+
+ $indexes = array();
+ while ($row = $rs->FetchRow()) {
+ $indexes[$row[0]]['unique'] = $row[1] == 'UNIQUE';
+ $indexes[$row[0]]['columns'][] = $row[2];
+ }
+ if ($primary) {
+ $indexes['SYSPRIMARYKEYINDEX'] = array(
+ 'unique' => True, // by definition
+ 'columns' => $this->GetCol("SELECT columnname FROM COLUMNS WHERE tablename=$table AND mode='KEY' ORDER BY pos"),
+ );
+ }
+ return $indexes;
+ }
+
+ function &MetaColumns ($table)
+ {
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+ $table = $this->Quote(strtoupper($table));
+
+ $retarr = array();
+ foreach($this->GetAll("SELECT COLUMNNAME,DATATYPE,LEN,DEC,NULLABLE,MODE,\"DEFAULT\",CASE WHEN \"DEFAULT\" IS NULL THEN 0 ELSE 1 END AS HAS_DEFAULT FROM COLUMNS WHERE tablename=$table ORDER BY pos") as $column)
+ {
+ $fld = new ADOFieldObject();
+ $fld->name = $column[0];
+ $fld->type = $column[1];
+ $fld->max_length = $fld->type == 'LONG' ? 2147483647 : $column[2];
+ $fld->scale = $column[3];
+ $fld->not_null = $column[4] == 'NO';
+ $fld->primary_key = $column[5] == 'KEY';
+ if ($fld->has_default = $column[7]) {
+ if ($fld->primary_key && $column[6] == 'DEFAULT SERIAL (1)') {
+ $fld->auto_increment = true;
+ $fld->has_default = false;
+ } else {
+ $fld->default_value = $column[6];
+ switch($fld->type) {
+ case 'VARCHAR':
+ case 'CHARACTER':
+ case 'LONG':
+ $fld->default_value = $column[6];
+ break;
+ default:
+ $fld->default_value = trim($column[6]);
+ break;
+ }
+ }
+ }
+ $retarr[$fld->name] = $fld;
+ }
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ return $retarr;
+ }
+
+ function MetaColumnNames($table)
+ {
+ $table = $this->Quote(strtoupper($table));
+
+ return $this->GetCol("SELECT columnname FROM COLUMNS WHERE tablename=$table ORDER BY pos");
+ }
+
+ // unlike it seems, this depends on the db-session and works in a multiuser environment
+ function _insertid($table,$column)
+ {
+ return empty($table) ? False : $this->GetOne("SELECT $table.CURRVAL FROM DUAL");
+ }
+
+ /*
+ SelectLimit implementation problems:
+
+ The following will return random 10 rows as order by performed after "WHERE rowno<10"
+ which is not ideal...
+
+ select * from table where rowno < 10 order by 1
+
+ This means that we have to use the adoconnection base class SelectLimit when
+ there is an "order by".
+
+ See http://listserv.sap.com/pipermail/sapdb.general/2002-January/010405.html
+ */
+
+};
+
+
+class ADORecordSet_sapdb extends ADORecordSet_odbc {
+
+ var $databaseType = "sapdb";
+
+ function ADORecordSet_sapdb($id,$mode=false)
+ {
+ $this->ADORecordSet_odbc($id,$mode);
+ }
+}
+
+} //define
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-sqlanywhere.inc.php b/lib/adodb/drivers/adodb-sqlanywhere.inc.php
new file mode 100644
index 0000000..88af3ae
--- /dev/null
+++ b/lib/adodb/drivers/adodb-sqlanywhere.inc.php
@@ -0,0 +1,169 @@
+<?php
+/*
+version V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights
+reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ 21.02.2002 - Wade Johnson wade@wadejohnson.de
+ Extended ODBC class for Sybase SQLAnywhere.
+ 1) Added support to retrieve the last row insert ID on tables with
+ primary key column using autoincrement function.
+
+ 2) Added blob support. Usage:
+ a) create blob variable on db server:
+
+ $dbconn->create_blobvar($blobVarName);
+
+ b) load blob var from file. $filename must be complete path
+
+ $dbcon->load_blobvar_from_file($blobVarName, $filename);
+
+ c) Use the $blobVarName in SQL insert or update statement in the values
+ clause:
+
+ $recordSet = $dbconn->Execute('INSERT INTO tabname (idcol, blobcol) '
+ .
+ 'VALUES (\'test\', ' . $blobVarName . ')');
+
+ instead of loading blob from a file, you can also load from
+ an unformatted (raw) blob variable:
+ $dbcon->load_blobvar_from_var($blobVarName, $varName);
+
+ d) drop blob variable on db server to free up resources:
+ $dbconn->drop_blobvar($blobVarName);
+
+ Sybase_SQLAnywhere data driver. Requires ODBC.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+
+if (!defined('ADODB_SYBASE_SQLANYWHERE')){
+
+ define('ADODB_SYBASE_SQLANYWHERE',1);
+
+ class ADODB_sqlanywhere extends ADODB_odbc {
+ var $databaseType = "sqlanywhere";
+ var $hasInsertID = true;
+
+ function ADODB_sqlanywhere()
+ {
+ $this->ADODB_odbc();
+ }
+
+ function _insertid() {
+ return $this->GetOne('select @@identity');
+ }
+
+ function create_blobvar($blobVarName) {
+ $this->Execute("create variable $blobVarName long binary");
+ return;
+ }
+
+ function drop_blobvar($blobVarName) {
+ $this->Execute("drop variable $blobVarName");
+ return;
+ }
+
+ function load_blobvar_from_file($blobVarName, $filename) {
+ $chunk_size = 1000;
+
+ $fd = fopen ($filename, "rb");
+
+ $integer_chunks = (integer)filesize($filename) / $chunk_size;
+ $modulus = filesize($filename) % $chunk_size;
+ if ($modulus != 0){
+ $integer_chunks += 1;
+ }
+
+ for($loop=1;$loop<=$integer_chunks;$loop++){
+ $contents = fread ($fd, $chunk_size);
+ $contents = bin2hex($contents);
+
+ $hexstring = '';
+
+ for($loop2=0;$loop2<strlen($contents);$loop2+=2){
+ $hexstring .= '\x' . substr($contents,$loop2,2);
+ }
+
+ $hexstring = $this->qstr($hexstring);
+
+ $this->Execute("set $blobVarName = $blobVarName || " . $hexstring);
+ }
+
+ fclose ($fd);
+ return;
+ }
+
+ function load_blobvar_from_var($blobVarName, &$varName) {
+ $chunk_size = 1000;
+
+ $integer_chunks = (integer)strlen($varName) / $chunk_size;
+ $modulus = strlen($varName) % $chunk_size;
+ if ($modulus != 0){
+ $integer_chunks += 1;
+ }
+
+ for($loop=1;$loop<=$integer_chunks;$loop++){
+ $contents = substr ($varName, (($loop - 1) * $chunk_size), $chunk_size);
+ $contents = bin2hex($contents);
+
+ $hexstring = '';
+
+ for($loop2=0;$loop2<strlen($contents);$loop2+=2){
+ $hexstring .= '\x' . substr($contents,$loop2,2);
+ }
+
+ $hexstring = $this->qstr($hexstring);
+
+ $this->Execute("set $blobVarName = $blobVarName || " . $hexstring);
+ }
+
+ return;
+ }
+
+ /*
+ Insert a null into the blob field of the table first.
+ Then use UpdateBlob to store the blob.
+
+ Usage:
+
+ $conn->Execute('INSERT INTO blobtable (id, blobcol) VALUES (1, null)');
+ $conn->UpdateBlob('blobtable','blobcol',$blob,'id=1');
+ */
+ function UpdateBlob($table,$column,&$val,$where,$blobtype='BLOB')
+ {
+ $blobVarName = 'hold_blob';
+ $this->create_blobvar($blobVarName);
+ $this->load_blobvar_from_var($blobVarName, $val);
+ $this->Execute("UPDATE $table SET $column=$blobVarName WHERE $where");
+ $this->drop_blobvar($blobVarName);
+ return true;
+ }
+ }; //class
+
+ class ADORecordSet_sqlanywhere extends ADORecordSet_odbc {
+
+ var $databaseType = "sqlanywhere";
+
+ function ADORecordSet_sqlanywhere($id,$mode=false)
+ {
+ $this->ADORecordSet_odbc($id,$mode);
+ }
+
+
+ }; //class
+
+
+} //define
+?>
diff --git a/lib/adodb/drivers/adodb-sqlite.inc.php b/lib/adodb/drivers/adodb-sqlite.inc.php
new file mode 100644
index 0000000..665cc54
--- /dev/null
+++ b/lib/adodb/drivers/adodb-sqlite.inc.php
@@ -0,0 +1,398 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ SQLite info: http://www.hwaci.com/sw/sqlite/
+
+ Install Instructions:
+ ====================
+ 1. Place this in adodb/drivers
+ 2. Rename the file, remove the .txt prefix.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB_sqlite extends ADOConnection {
+ var $databaseType = "sqlite";
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $concat_operator='||';
+ var $_errorNo = 0;
+ var $hasLimit = true;
+ var $hasInsertID = true; /// supports autoincrement ID?
+ var $hasAffectedRows = true; /// supports affected rows for update/delete?
+ var $metaTablesSQL = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
+ var $sysDate = "adodb_date('Y-m-d')";
+ var $sysTimeStamp = "adodb_date('Y-m-d H:i:s')";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+
+ function ADODB_sqlite()
+ {
+ }
+
+/*
+ function __get($name)
+ {
+ switch($name) {
+ case 'sysDate': return "'".date($this->fmtDate)."'";
+ case 'sysTimeStamp' : return "'".date($this->sysTimeStamp)."'";
+ }
+ }*/
+
+ function ServerInfo()
+ {
+ $arr['version'] = sqlite_libversion();
+ $arr['description'] = 'SQLite ';
+ $arr['encoding'] = sqlite_libencoding();
+ return $arr;
+ }
+
+ function BeginTrans()
+ {
+ if ($this->transOff) return true;
+ $ret = $this->Execute("BEGIN TRANSACTION");
+ $this->transCnt += 1;
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+ if (!$ok) return $this->RollbackTrans();
+ $ret = $this->Execute("COMMIT");
+ if ($this->transCnt>0)$this->transCnt -= 1;
+ return !empty($ret);
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ $ret = $this->Execute("ROLLBACK");
+ if ($this->transCnt>0)$this->transCnt -= 1;
+ return !empty($ret);
+ }
+
+ // mark newnham
+ function &MetaColumns($tab)
+ {
+ global $ADODB_FETCH_MODE;
+ $false = false;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
+ $rs = $this->Execute("PRAGMA table_info('$tab')");
+ if (isset($savem)) $this->SetFetchMode($savem);
+ if (!$rs) {
+ $ADODB_FETCH_MODE = $save;
+ return $false;
+ }
+ $arr = array();
+ while ($r = $rs->FetchRow()) {
+ $type = explode('(',$r['type']);
+ $size = '';
+ if (sizeof($type)==2)
+ $size = trim($type[1],')');
+ $fn = strtoupper($r['name']);
+ $fld = new ADOFieldObject;
+ $fld->name = $r['name'];
+ $fld->type = $type[0];
+ $fld->max_length = $size;
+ $fld->not_null = $r['notnull'];
+ $fld->default_value = $r['dflt_value'];
+ $fld->scale = 0;
+ if ($save == ADODB_FETCH_NUM) $arr[] = $fld;
+ else $arr[strtoupper($fld->name)] = $fld;
+ }
+ $rs->Close();
+ $ADODB_FETCH_MODE = $save;
+ return $arr;
+ }
+
+ function _init($parentDriver)
+ {
+
+ $parentDriver->hasTransactions = false;
+ $parentDriver->hasInsertID = true;
+ }
+
+ function _insertid()
+ {
+ return sqlite_last_insert_rowid($this->_connectionID);
+ }
+
+ function _affectedrows()
+ {
+ return sqlite_changes($this->_connectionID);
+ }
+
+ function ErrorMsg()
+ {
+ if ($this->_logsql) return $this->_errorMsg;
+ return ($this->_errorNo) ? sqlite_error_string($this->_errorNo) : '';
+ }
+
+ function ErrorNo()
+ {
+ return $this->_errorNo;
+ }
+
+ function SQLDate($fmt, $col=false)
+ {
+ $fmt = $this->qstr($fmt);
+ return ($col) ? "adodb_date2($fmt,$col)" : "adodb_date($fmt)";
+ }
+
+
+ function _createFunctions()
+ {
+ @sqlite_create_function($this->_connectionID, 'adodb_date', 'adodb_date', 1);
+ @sqlite_create_function($this->_connectionID, 'adodb_date2', 'adodb_date2', 2);
+ }
+
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!function_exists('sqlite_open')) return null;
+ if (empty($argHostname) && $argDatabasename) $argHostname = $argDatabasename;
+
+ $this->_connectionID = sqlite_open($argHostname);
+ if ($this->_connectionID === false) return false;
+ $this->_createFunctions();
+ return true;
+ }
+
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!function_exists('sqlite_open')) return null;
+ if (empty($argHostname) && $argDatabasename) $argHostname = $argDatabasename;
+
+ $this->_connectionID = sqlite_popen($argHostname);
+ if ($this->_connectionID === false) return false;
+ $this->_createFunctions();
+ return true;
+ }
+
+ // returns query ID if successful, otherwise false
+ function _query($sql,$inputarr=false)
+ {
+ $rez = sqlite_query($sql,$this->_connectionID);
+ if (!$rez) {
+ $this->_errorNo = sqlite_last_error($this->_connectionID);
+ }
+
+ return $rez;
+ }
+
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ {
+ $offsetStr = ($offset >= 0) ? " OFFSET $offset" : '';
+ $limitStr = ($nrows >= 0) ? " LIMIT $nrows" : ($offset >= 0 ? ' LIMIT 999999999' : '');
+ if ($secs2cache)
+ $rs =& $this->CacheExecute($secs2cache,$sql."$limitStr$offsetStr",$inputarr);
+ else
+ $rs =& $this->Execute($sql."$limitStr$offsetStr",$inputarr);
+
+ return $rs;
+ }
+
+ /*
+ This algorithm is not very efficient, but works even if table locking
+ is not available.
+
+ Will return false if unable to generate an ID after $MAXLOOPS attempts.
+ */
+ var $_genSeqSQL = "create table %s (id integer)";
+
+ function GenID($seq='adodbseq',$start=1)
+ {
+ // if you have to modify the parameter below, your database is overloaded,
+ // or you need to implement generation of id's yourself!
+ $MAXLOOPS = 100;
+ //$this->debug=1;
+ while (--$MAXLOOPS>=0) {
+ @($num = $this->GetOne("select id from $seq"));
+ if ($num === false) {
+ $this->Execute(sprintf($this->_genSeqSQL ,$seq));
+ $start -= 1;
+ $num = '0';
+ $ok = $this->Execute("insert into $seq values($start)");
+ if (!$ok) return false;
+ }
+ $this->Execute("update $seq set id=id+1 where id=$num");
+
+ if ($this->affected_rows() > 0) {
+ $num += 1;
+ $this->genID = $num;
+ return $num;
+ }
+ }
+ if ($fn = $this->raiseErrorFn) {
+ $fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
+ }
+ return false;
+ }
+
+ function CreateSequence($seqname='adodbseq',$start=1)
+ {
+ if (empty($this->_genSeqSQL)) return false;
+ $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname));
+ if (!$ok) return false;
+ $start -= 1;
+ return $this->Execute("insert into $seqname values($start)");
+ }
+
+ var $_dropSeqSQL = 'drop table %s';
+ function DropSequence($seqname)
+ {
+ if (empty($this->_dropSeqSQL)) return false;
+ return $this->Execute(sprintf($this->_dropSeqSQL,$seqname));
+ }
+
+ // returns true or false
+ function _close()
+ {
+ return @sqlite_close($this->_connectionID);
+ }
+
+ function &MetaIndexes($table, $primary = FALSE, $owner=false)
+ {
+ $false = false;
+ // save old fetch mode
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->fetchMode !== FALSE) {
+ $savem = $this->SetFetchMode(FALSE);
+ }
+ $SQL=sprintf("SELECT name,sql FROM sqlite_master WHERE type='index' AND tbl_name='%s'", strtolower($table));
+ $rs = $this->Execute($SQL);
+ if (!is_object($rs)) {
+ if (isset($savem))
+ $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ return $false;
+ }
+
+ $indexes = array ();
+ while ($row = $rs->FetchRow()) {
+ if ($primary && preg_match("/primary/i",$row[1]) == 0) continue;
+ if (!isset($indexes[$row[0]])) {
+
+ $indexes[$row[0]] = array(
+ 'unique' => preg_match("/unique/i",$row[1]),
+ 'columns' => array());
+ }
+ /**
+ * There must be a more elegant way of doing this,
+ * the index elements appear in the SQL statement
+ * in cols[1] between parentheses
+ * e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse)
+ */
+ $cols = explode("(",$row[1]);
+ $cols = explode(")",$cols[1]);
+ array_pop($cols);
+ $indexes[$row[0]]['columns'] = $cols;
+ }
+ if (isset($savem)) {
+ $this->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+ }
+ return $indexes;
+ }
+
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_sqlite extends ADORecordSet {
+
+ var $databaseType = "sqlite";
+ var $bind = false;
+
+ function ADORecordset_sqlite($queryID,$mode=false)
+ {
+
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ switch($mode) {
+ case ADODB_FETCH_NUM: $this->fetchMode = SQLITE_NUM; break;
+ case ADODB_FETCH_ASSOC: $this->fetchMode = SQLITE_ASSOC; break;
+ default: $this->fetchMode = SQLITE_BOTH; break;
+ }
+ $this->adodbFetchMode = $mode;
+
+ $this->_queryID = $queryID;
+
+ $this->_inited = true;
+ $this->fields = array();
+ if ($queryID) {
+ $this->_currentRow = 0;
+ $this->EOF = !$this->_fetch();
+ @$this->_initrs();
+ } else {
+ $this->_numOfRows = 0;
+ $this->_numOfFields = 0;
+ $this->EOF = true;
+ }
+
+ return $this->_queryID;
+ }
+
+
+ function &FetchField($fieldOffset = -1)
+ {
+ $fld = new ADOFieldObject;
+ $fld->name = sqlite_field_name($this->_queryID, $fieldOffset);
+ $fld->type = 'VARCHAR';
+ $fld->max_length = -1;
+ return $fld;
+ }
+
+ function _initrs()
+ {
+ $this->_numOfRows = @sqlite_num_rows($this->_queryID);
+ $this->_numOfFields = @sqlite_num_fields($this->_queryID);
+ }
+
+ function Fields($colname)
+ {
+ if ($this->fetchMode != SQLITE_NUM) 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)]];
+ }
+
+ function _seek($row)
+ {
+ return sqlite_seek($this->_queryID, $row);
+ }
+
+ function _fetch($ignore_fields=false)
+ {
+ $this->fields = @sqlite_fetch_array($this->_queryID,$this->fetchMode);
+ return !empty($this->fields);
+ }
+
+ function _close()
+ {
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-sqlitepo.inc.php b/lib/adodb/drivers/adodb-sqlitepo.inc.php
new file mode 100644
index 0000000..dbd0271
--- /dev/null
+++ b/lib/adodb/drivers/adodb-sqlitepo.inc.php
@@ -0,0 +1,62 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Portable version of sqlite driver, to make it more similar to other database drivers.
+ The main differences are
+
+ 1. When selecting (joining) multiple tables, in assoc mode the table
+ names are included in the assoc keys in the "sqlite" driver.
+
+ In "sqlitepo" driver, the table names are stripped from the returned column names.
+ When this results in a conflict, the first field get preference.
+
+ Contributed by Herman Kuiper herman#ozuzo.net
+*/
+
+if (!defined('ADODB_DIR')) die();
+
+include_once(ADODB_DIR.'/drivers/adodb-sqlite.inc.php');
+
+class ADODB_sqlitepo extends ADODB_sqlite {
+ var $databaseType = 'sqlitepo';
+
+ function ADODB_sqlitepo()
+ {
+ $this->ADODB_sqlite();
+ }
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+
+class ADORecordset_sqlitepo extends ADORecordset_sqlite {
+
+ var $databaseType = 'sqlitepo';
+
+ function ADORecordset_sqlitepo($queryID,$mode=false)
+ {
+ $this->ADORecordset_sqlite($queryID,$mode);
+ }
+
+ // Modified to strip table names from returned fields
+ function _fetch($ignore_fields=false)
+ {
+ $this->fields = array();
+ $fields = @sqlite_fetch_array($this->_queryID,$this->fetchMode);
+ if(is_array($fields))
+ foreach($fields as $n => $v)
+ {
+ if(($p = strpos($n, ".")) !== false)
+ $n = substr($n, $p+1);
+ $this->fields[$n] = $v;
+ }
+
+ return !empty($this->fields);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-sybase.inc.php b/lib/adodb/drivers/adodb-sybase.inc.php
new file mode 100644
index 0000000..ba6b919
--- /dev/null
+++ b/lib/adodb/drivers/adodb-sybase.inc.php
@@ -0,0 +1,418 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Sybase driver contributed by Toni (toni.tunkkari@finebyte.com)
+
+ - MSSQL date patch applied.
+
+ Date patch by Toni 15 Feb 2002
+*/
+
+ // security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class ADODB_sybase extends ADOConnection {
+ var $databaseType = "sybase";
+ var $dataProvider = 'sybase';
+ var $replaceQuote = "''"; // string to use to replace quotes
+ var $fmtDate = "'Y-m-d'";
+ var $fmtTimeStamp = "'Y-m-d H:i:s'";
+ var $hasInsertID = true;
+ var $hasAffectedRows = true;
+ var $metaTablesSQL="select name from sysobjects where type='U' or type='V'";
+ // see http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=5981;uf=0?target=0;window=new;showtoc=true;book=dbrfen8
+ var $metaColumnsSQL = "SELECT c.column_name, c.column_type, c.width FROM syscolumn c, systable t WHERE t.table_name='%s' AND c.table_id=t.table_id AND t.table_type='BASE'";
+ /*
+ "select c.name,t.name,c.length from
+ syscolumns c join systypes t on t.xusertype=c.xusertype join sysobjects o on o.id=c.id
+ where o.name='%s'";
+ */
+ var $concat_operator = '+';
+ var $arrayClass = 'ADORecordSet_array_sybase';
+ var $sysDate = 'GetDate()';
+ var $leftOuter = '*=';
+ var $rightOuter = '=*';
+
+ function ADODB_sybase()
+ {
+ }
+
+ // might require begintrans -- committrans
+ function _insertid()
+ {
+ return $this->GetOne('select @@identity');
+ }
+ // might require begintrans -- committrans
+ function _affectedrows()
+ {
+ return $this->GetOne('select @@rowcount');
+ }
+
+
+ function BeginTrans()
+ {
+
+ if ($this->transOff) return true;
+ $this->transCnt += 1;
+
+ $this->Execute('BEGIN TRAN');
+ return true;
+ }
+
+ function CommitTrans($ok=true)
+ {
+ if ($this->transOff) return true;
+
+ if (!$ok) return $this->RollbackTrans();
+
+ $this->transCnt -= 1;
+ $this->Execute('COMMIT TRAN');
+ return true;
+ }
+
+ function RollbackTrans()
+ {
+ if ($this->transOff) return true;
+ $this->transCnt -= 1;
+ $this->Execute('ROLLBACK TRAN');
+ return true;
+ }
+
+ // http://www.isug.com/Sybase_FAQ/ASE/section6.1.html#6.1.4
+ function RowLock($tables,$where,$flds='top 1 null as ignore')
+ {
+ if (!$this->_hastrans) $this->BeginTrans();
+ $tables = str_replace(',',' HOLDLOCK,',$tables);
+ return $this->GetOne("select $flds from $tables HOLDLOCK where $where");
+
+ }
+
+ function SelectDB($dbName)
+ {
+ $this->database = $dbName;
+ $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions
+ if ($this->_connectionID) {
+ return @sybase_select_db($dbName);
+ }
+ else return false;
+ }
+
+ /* Returns: the last error message from previous database operation
+ Note: This function is NOT available for Microsoft SQL Server. */
+
+
+ function ErrorMsg()
+ {
+ if ($this->_logsql) return $this->_errorMsg;
+ if (function_exists('sybase_get_last_message'))
+ $this->_errorMsg = sybase_get_last_message();
+ else
+ $this->_errorMsg = isset($php_errormsg) ? $php_errormsg : 'SYBASE error messages not supported on this platform';
+ return $this->_errorMsg;
+ }
+
+ // returns true or false
+ function _connect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!function_exists('sybase_connect')) return null;
+
+ $this->_connectionID = sybase_connect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+ // returns true or false
+ function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
+ {
+ if (!function_exists('sybase_connect')) return null;
+
+ $this->_connectionID = sybase_pconnect($argHostname,$argUsername,$argPassword);
+ if ($this->_connectionID === false) return false;
+ if ($argDatabasename) return $this->SelectDB($argDatabasename);
+ return true;
+ }
+
+ // returns query ID if successful, otherwise false
+ function _query($sql,$inputarr)
+ {
+ global $ADODB_COUNTRECS;
+
+ if ($ADODB_COUNTRECS == false && ADODB_PHPVER >= 0x4300)
+ return sybase_unbuffered_query($sql,$this->_connectionID);
+ else
+ return sybase_query($sql,$this->_connectionID);
+ }
+
+ // See http://www.isug.com/Sybase_FAQ/ASE/section6.2.html#6.2.12
+ function &SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0)
+ {
+ if ($secs2cache > 0) {// we do not cache rowcount, so we have to load entire recordset
+ $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+ return $rs;
+ }
+
+ $nrows = (integer) $nrows;
+ $offset = (integer) $offset;
+
+ $cnt = ($nrows >= 0) ? $nrows : 999999999;
+ if ($offset > 0 && $cnt) $cnt += $offset;
+
+ $this->Execute("set rowcount $cnt");
+ $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,0);
+ $this->Execute("set rowcount 0");
+
+ return $rs;
+ }
+
+ // returns true or false
+ function _close()
+ {
+ return @sybase_close($this->_connectionID);
+ }
+
+ function UnixDate($v)
+ {
+ return ADORecordSet_array_sybase::UnixDate($v);
+ }
+
+ function UnixTimeStamp($v)
+ {
+ return ADORecordSet_array_sybase::UnixTimeStamp($v);
+ }
+
+
+
+ # Added 2003-10-05 by Chris Phillipson
+ # Used ASA SQL Reference Manual -- http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=16756?target=%25N%15_12018_START_RESTART_N%25
+ # to convert similar Microsoft SQL*Server (mssql) API into Sybase compatible version
+ // Format date column in sql string given an input format that understands Y M D
+ function SQLDate($fmt, $col=false)
+ {
+ if (!$col) $col = $this->sysTimeStamp;
+ $s = '';
+
+ $len = strlen($fmt);
+ for ($i=0; $i < $len; $i++) {
+ if ($s) $s .= '+';
+ $ch = $fmt[$i];
+ switch($ch) {
+ case 'Y':
+ case 'y':
+ $s .= "datename(yy,$col)";
+ break;
+ case 'M':
+ $s .= "convert(char(3),$col,0)";
+ break;
+ case 'm':
+ $s .= "replace(str(month($col),2),' ','0')";
+ break;
+ case 'Q':
+ case 'q':
+ $s .= "datename(qq,$col)";
+ break;
+ case 'D':
+ case 'd':
+ $s .= "replace(str(datepart(dd,$col),2),' ','0')";
+ break;
+ case 'h':
+ $s .= "substring(convert(char(14),$col,0),13,2)";
+ break;
+
+ case 'H':
+ $s .= "replace(str(datepart(hh,$col),2),' ','0')";
+ break;
+
+ case 'i':
+ $s .= "replace(str(datepart(mi,$col),2),' ','0')";
+ break;
+ case 's':
+ $s .= "replace(str(datepart(ss,$col),2),' ','0')";
+ break;
+ case 'a':
+ case 'A':
+ $s .= "substring(convert(char(19),$col,0),18,2)";
+ break;
+
+ default:
+ if ($ch == '\\') {
+ $i++;
+ $ch = substr($fmt,$i,1);
+ }
+ $s .= $this->qstr($ch);
+ break;
+ }
+ }
+ return $s;
+ }
+
+ # Added 2003-10-07 by Chris Phillipson
+ # Used ASA SQL Reference Manual -- http://sybooks.sybase.com/onlinebooks/group-aw/awg0800e/dbrfen8/@ebt-link;pt=5981;uf=0?target=0;window=new;showtoc=true;book=dbrfen8
+ # to convert similar Microsoft SQL*Server (mssql) API into Sybase compatible version
+ function MetaPrimaryKeys($table)
+ {
+ $sql = "SELECT c.column_name " .
+ "FROM syscolumn c, systable t " .
+ "WHERE t.table_name='$table' AND c.table_id=t.table_id " .
+ "AND t.table_type='BASE' " .
+ "AND c.pkey = 'Y' " .
+ "ORDER BY c.column_id";
+
+ $a = $this->GetCol($sql);
+ if ($a && sizeof($a)>0) return $a;
+ return false;
+ }
+}
+
+/*--------------------------------------------------------------------------------------
+ Class Name: Recordset
+--------------------------------------------------------------------------------------*/
+global $ADODB_sybase_mths;
+$ADODB_sybase_mths = array(
+ 'JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,
+ 'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
+
+class ADORecordset_sybase extends ADORecordSet {
+
+ var $databaseType = "sybase";
+ var $canSeek = true;
+ // _mths works only in non-localised system
+ var $_mths = array('JAN'=>1,'FEB'=>2,'MAR'=>3,'APR'=>4,'MAY'=>5,'JUN'=>6,'JUL'=>7,'AUG'=>8,'SEP'=>9,'OCT'=>10,'NOV'=>11,'DEC'=>12);
+
+ function ADORecordset_sybase($id,$mode=false)
+ {
+ if ($mode === false) {
+ global $ADODB_FETCH_MODE;
+ $mode = $ADODB_FETCH_MODE;
+ }
+ if (!$mode) $this->fetchMode = ADODB_FETCH_ASSOC;
+ else $this->fetchMode = $mode;
+ $this->ADORecordSet($id,$mode);
+ }
+
+ /* Returns: an object containing field information.
+ Get column information in the Recordset object. fetchField() can be used in order to obtain information about
+ fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
+ fetchField() is retrieved. */
+ function &FetchField($fieldOffset = -1)
+ {
+ if ($fieldOffset != -1) {
+ $o = @sybase_fetch_field($this->_queryID, $fieldOffset);
+ }
+ else if ($fieldOffset == -1) { /* The $fieldOffset argument is not provided thus its -1 */
+ $o = @sybase_fetch_field($this->_queryID);
+ }
+ // older versions of PHP did not support type, only numeric
+ if ($o && !isset($o->type)) $o->type = ($o->numeric) ? 'float' : 'varchar';
+ return $o;
+ }
+
+ function _initrs()
+ {
+ global $ADODB_COUNTRECS;
+ $this->_numOfRows = ($ADODB_COUNTRECS)? @sybase_num_rows($this->_queryID):-1;
+ $this->_numOfFields = @sybase_num_fields($this->_queryID);
+ }
+
+ function _seek($row)
+ {
+ return @sybase_data_seek($this->_queryID, $row);
+ }
+
+ function _fetch($ignore_fields=false)
+ {
+ if ($this->fetchMode == ADODB_FETCH_NUM) {
+ $this->fields = @sybase_fetch_row($this->_queryID);
+ } else if ($this->fetchMode == ADODB_FETCH_ASSOC) {
+ $this->fields = @sybase_fetch_row($this->_queryID);
+ if (is_array($this->fields)) {
+ $this->fields = $this->GetRowAssoc(ADODB_ASSOC_CASE);
+ return true;
+ }
+ return false;
+ } else {
+ $this->fields = @sybase_fetch_array($this->_queryID);
+ }
+ if ( is_array($this->fields)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /* close() only needs to be called if you are worried about using too much memory while your script
+ is running. All associated result memory for the specified result identifier will automatically be freed. */
+ function _close() {
+ return @sybase_free_result($this->_queryID);
+ }
+
+ // sybase/mssql uses a default date like Dec 30 2000 12:00AM
+ function UnixDate($v)
+ {
+ return ADORecordSet_array_sybase::UnixDate($v);
+ }
+
+ function UnixTimeStamp($v)
+ {
+ return ADORecordSet_array_sybase::UnixTimeStamp($v);
+ }
+}
+
+class ADORecordSet_array_sybase extends ADORecordSet_array {
+ function ADORecordSet_array_sybase($id=-1)
+ {
+ $this->ADORecordSet_array($id);
+ }
+
+ // sybase/mssql uses a default date like Dec 30 2000 12:00AM
+ function UnixDate($v)
+ {
+ global $ADODB_sybase_mths;
+
+ //Dec 30 2000 12:00AM
+ if (!ereg( "([A-Za-z]{3})[-/\. ]+([0-9]{1,2})[-/\. ]+([0-9]{4})"
+ ,$v, $rr)) return parent::UnixDate($v);
+
+ if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+
+ $themth = substr(strtoupper($rr[1]),0,3);
+ $themth = $ADODB_sybase_mths[$themth];
+ if ($themth <= 0) return false;
+ // h-m-s-MM-DD-YY
+ return mktime(0,0,0,$themth,$rr[2],$rr[3]);
+ }
+
+ function UnixTimeStamp($v)
+ {
+ global $ADODB_sybase_mths;
+ //11.02.2001 Toni Tunkkari toni.tunkkari@finebyte.com
+ //Changed [0-9] to [0-9 ] in day conversion
+ if (!ereg( "([A-Za-z]{3})[-/\. ]([0-9 ]{1,2})[-/\. ]([0-9]{4}) +([0-9]{1,2}):([0-9]{1,2}) *([apAP]{0,1})"
+ ,$v, $rr)) return parent::UnixTimeStamp($v);
+ if ($rr[3] <= TIMESTAMP_FIRST_YEAR) return 0;
+
+ $themth = substr(strtoupper($rr[1]),0,3);
+ $themth = $ADODB_sybase_mths[$themth];
+ if ($themth <= 0) return false;
+
+ switch (strtoupper($rr[6])) {
+ case 'P':
+ if ($rr[4]<12) $rr[4] += 12;
+ break;
+ case 'A':
+ if ($rr[4]==12) $rr[4] = 0;
+ break;
+ default:
+ break;
+ }
+ // h-m-s-MM-DD-YY
+ return mktime($rr[4],$rr[5],0,$themth,$rr[2],$rr[3]);
+ }
+}
+?>
diff --git a/lib/adodb/drivers/adodb-sybase_ase.inc.php b/lib/adodb/drivers/adodb-sybase_ase.inc.php
new file mode 100644
index 0000000..9b5334d
--- /dev/null
+++ b/lib/adodb/drivers/adodb-sybase_ase.inc.php
@@ -0,0 +1,119 @@
+<?php
+/*
+ V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Set tabs to 4.
+
+ Contributed by Interakt Online. Thx Cristian MARIN cristic#interaktonline.com
+*/
+
+
+require_once ADODB_DIR."/drivers/adodb-sybase.inc.php";
+
+class ADODB_sybase_ase extends ADODB_sybase {
+ var $databaseType = "sybase_ase";
+
+ var $metaTablesSQL="SELECT sysobjects.name FROM sysobjects, sysusers WHERE sysobjects.type='U' AND sysobjects.uid = sysusers.uid";
+ var $metaColumnsSQL = "SELECT syscolumns.name AS field_name, systypes.name AS type, systypes.length AS width FROM sysobjects, syscolumns, systypes WHERE sysobjects.name='%s' AND syscolumns.id = sysobjects.id AND systypes.type=syscolumns.type";
+ var $metaDatabasesSQL ="SELECT a.name FROM master.dbo.sysdatabases a, master.dbo.syslogins b WHERE a.suid = b.suid and a.name like '%' and a.name != 'tempdb' and a.status3 != 256 order by 1";
+
+ function ADODB_sybase_ase()
+ {
+ }
+
+ // split the Views, Tables and procedures.
+ function &MetaTables($ttype=false,$showSchema=false,$mask=false)
+ {
+ $false = false;
+ if ($this->metaTablesSQL) {
+ // complicated state saving by the need for backward compat
+
+ if ($ttype == 'VIEWS'){
+ $sql = str_replace('U', 'V', $this->metaTablesSQL);
+ }elseif (false === $ttype){
+ $sql = str_replace('U',"U' OR type='V", $this->metaTablesSQL);
+ }else{ // TABLES OR ANY OTHER
+ $sql = $this->metaTablesSQL;
+ }
+ $rs = $this->Execute($sql);
+
+ if ($rs === false || !method_exists($rs, 'GetArray')){
+ return $false;
+ }
+ $arr =& $rs->GetArray();
+
+ $arr2 = array();
+ foreach($arr as $key=>$value){
+ $arr2[] = trim($value['name']);
+ }
+ return $arr2;
+ }
+ return $false;
+ }
+
+ function MetaDatabases()
+ {
+ $arr = array();
+ if ($this->metaDatabasesSQL!='') {
+ $rs = $this->Execute($this->metaDatabasesSQL);
+ if ($rs && !$rs->EOF){
+ while (!$rs->EOF){
+ $arr[] = $rs->Fields('name');
+ $rs->MoveNext();
+ }
+ return $arr;
+ }
+ }
+ return false;
+ }
+
+ // fix a bug which prevent the metaColumns query to be executed for Sybase ASE
+ function &MetaColumns($table,$upper=false)
+ {
+ $false = false;
+ if (!empty($this->metaColumnsSQL)) {
+
+ $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table));
+ if ($rs === false) return $false;
+
+ $retarr = array();
+ while (!$rs->EOF) {
+ $fld =& new ADOFieldObject();
+ $fld->name = $rs->Fields('field_name');
+ $fld->type = $rs->Fields('type');
+ $fld->max_length = $rs->Fields('width');
+ $retarr[strtoupper($fld->name)] = $fld;
+ $rs->MoveNext();
+ }
+ $rs->Close();
+ return $retarr;
+ }
+ return $false;
+ }
+
+ function getProcedureList($schema)
+ {
+ return false;
+ }
+
+ function ErrorMsg()
+ {
+ if (!function_exists('sybase_connect')){
+ return 'Your PHP doesn\'t contain the Sybase connection module!';
+ }
+ return parent::ErrorMsg();
+ }
+}
+
+class adorecordset_sybase_ase extends ADORecordset_sybase {
+var $databaseType = "sybase_ase";
+function ADORecordset_sybase_ase($id,$mode=false)
+ {
+ $this->ADORecordSet_sybase($id,$mode);
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/drivers/adodb-vfp.inc.php b/lib/adodb/drivers/adodb-vfp.inc.php
new file mode 100644
index 0000000..034eee2
--- /dev/null
+++ b/lib/adodb/drivers/adodb-vfp.inc.php
@@ -0,0 +1,107 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Microsoft Visual FoxPro data driver. Requires ODBC. Works only on MS Windows.
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+if (!defined('_ADODB_ODBC_LAYER')) {
+ include(ADODB_DIR."/drivers/adodb-odbc.inc.php");
+}
+if (!defined('ADODB_VFP')){
+define('ADODB_VFP',1);
+class ADODB_vfp extends ADODB_odbc {
+ var $databaseType = "vfp";
+ var $fmtDate = "{^Y-m-d}";
+ var $fmtTimeStamp = "{^Y-m-d, h:i:sA}";
+ var $replaceQuote = "'+chr(39)+'" ;
+ var $true = '.T.';
+ var $false = '.F.';
+ var $hasTop = 'top'; // support mssql SELECT TOP 10 * FROM TABLE
+ var $_bindInputArray = false; // strangely enough, setting to true does not work reliably
+ var $sysTimeStamp = 'datetime()';
+ var $sysDate = 'date()';
+ var $ansiOuter = true;
+ var $hasTransactions = false;
+ var $curmode = false ; // See sqlext.h, SQL_CUR_DEFAULT == SQL_CUR_USE_DRIVER == 2L
+
+ function ADODB_vfp()
+ {
+ $this->ADODB_odbc();
+ }
+
+ function Time()
+ {
+ return time();
+ }
+
+ function BeginTrans() { return false;}
+
+ // quote string to be sent back to database
+ function qstr($s,$nofixquotes=false)
+ {
+ if (!$nofixquotes) return "'".str_replace("\r\n","'+chr(13)+'",str_replace("'",$this->replaceQuote,$s))."'";
+ return "'".$s."'";
+ }
+
+
+ // TOP requires ORDER BY for VFP
+ function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
+ {
+ $this->hasTop = preg_match('/ORDER[ \t\r\n]+BY/is',$sql) ? 'top' : false;
+ $ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
+ return $ret;
+ }
+
+
+
+};
+
+
+class ADORecordSet_vfp extends ADORecordSet_odbc {
+
+ var $databaseType = "vfp";
+
+
+ function ADORecordSet_vfp($id,$mode=false)
+ {
+ return $this->ADORecordSet_odbc($id,$mode);
+ }
+
+ function MetaType($t,$len=-1)
+ {
+ if (is_object($t)) {
+ $fieldobj = $t;
+ $t = $fieldobj->type;
+ $len = $fieldobj->max_length;
+ }
+ switch (strtoupper($t)) {
+ case 'C':
+ if ($len <= $this->blobSize) return 'C';
+ case 'M':
+ return 'X';
+
+ case 'D': return 'D';
+
+ case 'T': return 'T';
+
+ case 'L': return 'L';
+
+ case 'I': return 'I';
+
+ default: return 'N';
+ }
+ }
+}
+
+} //define
+?> \ No newline at end of file
diff --git a/lib/adodb/icons/adodb.gif b/lib/adodb/icons/adodb.gif
new file mode 100644
index 0000000..c5e8dfc
--- /dev/null
+++ b/lib/adodb/icons/adodb.gif
Binary files differ
diff --git a/lib/adodb/icons/adodb2.gif b/lib/adodb/icons/adodb2.gif
new file mode 100644
index 0000000..f12ae20
--- /dev/null
+++ b/lib/adodb/icons/adodb2.gif
Binary files differ
diff --git a/lib/adodb/lang/adodb-ar.inc.php b/lib/adodb/lang/adodb-ar.inc.php
new file mode 100644
index 0000000..dd0f830
--- /dev/null
+++ b/lib/adodb/lang/adodb-ar.inc.php
@@ -0,0 +1,34 @@
+<?php
+// by "El-Shamaa, Khaled" <k.el-shamaa#cgiar.org>
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'ar',
+ DB_ERROR => 'ÎØÃ ÛíÑ ãÍÏÏ',
+ DB_ERROR_ALREADY_EXISTS => 'ãæÌæÏ ãÓÈÞÇ',
+ DB_ERROR_CANNOT_CREATE => 'áÇ íãßä ÅäÔÇÁ',
+ DB_ERROR_CANNOT_DELETE => 'áÇ íãßä ÍÐÝ',
+ DB_ERROR_CANNOT_DROP => 'áÇ íãßä ÍÐÝ',
+ DB_ERROR_CONSTRAINT => 'ÚãáíÉ ÅÏÎÇá ããäæÚÉ',
+ DB_ERROR_DIVZERO => 'ÚãáíÉ ÇáÊÞÓíã Úáì ÕÝÑ',
+ DB_ERROR_INVALID => 'ÛíÑ ÕÍíÍ',
+ DB_ERROR_INVALID_DATE => 'ÕíÛÉ æÞÊ Ãæ ÊÇÑíÎ ÛíÑ ÕÍíÍÉ',
+ DB_ERROR_INVALID_NUMBER => 'ÕíÛÉ ÑÞã ÛíÑ ÕÍíÍÉ',
+ DB_ERROR_MISMATCH => 'ÛíÑ ãÊØÇÈÞ',
+ DB_ERROR_NODBSELECTED => 'áã íÊã ÅÎÊíÇÑ ÞÇÚÏÉ ÇáÈíÇäÇÊ ÈÚÏ',
+ DB_ERROR_NOSUCHFIELD => 'áíÓ åäÇáß ÍÞá ÈåÐÇ ÇáÇÓã',
+ DB_ERROR_NOSUCHTABLE => 'áíÓ åäÇáß ÌÏæá ÈåÐÇ ÇáÇÓã',
+ DB_ERROR_NOT_CAPABLE => 'ÞÇÚÏÉ ÇáÈíÇäÇÊ ÇáãÑÊÈØ ÈåÇ ÛíÑ ÞÇÏÑÉ',
+ DB_ERROR_NOT_FOUND => 'áã íÊã ÅíÌÇÏå',
+ DB_ERROR_NOT_LOCKED => 'ÛíÑ ãÞÝæá',
+ DB_ERROR_SYNTAX => 'ÎØÃ Ýí ÇáÕíÛÉ',
+ DB_ERROR_UNSUPPORTED => 'ÛíÑ ãÏÚæã',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'ÚÏÏ ÇáÞíã Ýí ÇáÓÌá',
+ DB_ERROR_INVALID_DSN => 'DSN ÛíÑ ÕÍíÍ',
+ DB_ERROR_CONNECT_FAILED => 'ÝÔá ÚãáíÉ ÇáÅÊÕÇá',
+ 0 => 'áíÓ åäÇáß ÃÎØÇÁ', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'ÇáÈíÇäÇÊ ÇáãÒæÏÉ ÛíÑ ßÇÝíÉ',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'áã íÊã ÅíÌÇÏ ÇáÅÖÇÝÉ ÇáãÊÚáÞÉ',
+ DB_ERROR_NOSUCHDB => 'áíÓ åäÇáß ÞÇÚÏÉ ÈíÇäÇÊ ÈåÐÇ ÇáÇÓã',
+ DB_ERROR_ACCESS_VIOLATION => 'ÓãÇÍíÇÊ ÛíÑ ßÇÝíÉ'
+);
+?>
+
diff --git a/lib/adodb/lang/adodb-bg.inc.php b/lib/adodb/lang/adodb-bg.inc.php
new file mode 100644
index 0000000..4fb1dc0
--- /dev/null
+++ b/lib/adodb/lang/adodb-bg.inc.php
@@ -0,0 +1,38 @@
+<?php
+/*
+ Bulgarian language, v1.0, 25.03.2004, encoding by Windows-1251 charset
+ contributed by Valentin Sheiretsky <valio#valio.eu.org>
+*/
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'bg',
+ DB_ERROR => 'íåèçâåñòíà ãðåøêà',
+ DB_ERROR_ALREADY_EXISTS => 'âå÷å ñúùåñòâóâà',
+ DB_ERROR_CANNOT_CREATE => 'íå ìîæå äà áúäå ñúçäàäåíà',
+ DB_ERROR_CANNOT_DELETE => 'íå ìîæå äà áúäå èçòðèòà',
+ DB_ERROR_CANNOT_DROP => 'íå ìîæå äà áúäå óíèùîæåíà',
+ DB_ERROR_CONSTRAINT => 'íàðóøåíî óñëîâèå',
+ DB_ERROR_DIVZERO => 'äåëåíèå íà íóëà',
+ DB_ERROR_INVALID => 'íåïðàâèëíî',
+ DB_ERROR_INVALID_DATE => 'íåêîðåêòíà äàòà èëè ÷àñ',
+ DB_ERROR_INVALID_NUMBER => 'íåâàëèäåí íîìåð',
+ DB_ERROR_MISMATCH => 'ïîãðåøíà óïîòðåáà',
+ DB_ERROR_NODBSELECTED => 'íå å èçáðàíà áàçà äàííè',
+ DB_ERROR_NOSUCHFIELD => 'íåñúùåñòâóâàùî ïîëå',
+ DB_ERROR_NOSUCHTABLE => 'íåñúùåñòâóâàùà òàáëèöà',
+ DB_ERROR_NOT_CAPABLE => 'DB backend not capable',
+ DB_ERROR_NOT_FOUND => 'íå å íàìåðåíà',
+ DB_ERROR_NOT_LOCKED => 'íå å çàêëþ÷åíà',
+ DB_ERROR_SYNTAX => 'ãðåøåí ñèíòàêñèñ',
+ DB_ERROR_UNSUPPORTED => 'íå ñå ïîääúðæà',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'íåêîðåêòåí áðîé êîëîíè â ðåäà',
+ DB_ERROR_INVALID_DSN => 'íåâàëèäåí DSN',
+ DB_ERROR_CONNECT_FAILED => 'âðúçêàòà íå ìîæå äà áúäå îñúùåñòâåíà',
+ 0 => 'íÿìà ãðåøêè', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'ïðåäîñòàâåíèòå äàííè ñà íåäîñòàòú÷íè',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'ðàçøèðåíèåòî íå å íàìåðåíî',
+ DB_ERROR_NOSUCHDB => 'íåñúùåñòâóâàùà áàçà äàííè',
+ DB_ERROR_ACCESS_VIOLATION => 'íÿìàòå äîñòàòú÷íî ïðàâà'
+);
+?>
+ \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-bgutf8.inc.php b/lib/adodb/lang/adodb-bgutf8.inc.php
new file mode 100644
index 0000000..6f3a417
--- /dev/null
+++ b/lib/adodb/lang/adodb-bgutf8.inc.php
@@ -0,0 +1,38 @@
+<?php
+/*
+ Bulgarian language, v1.0, 25.03.2004, encoding by UTF-8 charset
+ contributed by Valentin Sheiretsky <valio#valio.eu.org>
+*/
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'bgutf8',
+ DB_ERROR => 'неизвеÑтна грешка',
+ DB_ERROR_ALREADY_EXISTS => 'вече ÑъщеÑтвува',
+ DB_ERROR_CANNOT_CREATE => 'не може да бъде Ñъздадена',
+ DB_ERROR_CANNOT_DELETE => 'не може да бъде изтрита',
+ DB_ERROR_CANNOT_DROP => 'не може да бъде унищожена',
+ DB_ERROR_CONSTRAINT => 'нарушено уÑловие',
+ DB_ERROR_DIVZERO => 'деление на нула',
+ DB_ERROR_INVALID => 'неправилно',
+ DB_ERROR_INVALID_DATE => 'некоректна дата или чаÑ',
+ DB_ERROR_INVALID_NUMBER => 'невалиден номер',
+ DB_ERROR_MISMATCH => 'погрешна употреба',
+ DB_ERROR_NODBSELECTED => 'не е избрана база данни',
+ DB_ERROR_NOSUCHFIELD => 'неÑъщеÑтвуващо поле',
+ DB_ERROR_NOSUCHTABLE => 'неÑъщеÑтвуваща таблица',
+ DB_ERROR_NOT_CAPABLE => 'DB backend not capable',
+ DB_ERROR_NOT_FOUND => 'не е намерена',
+ DB_ERROR_NOT_LOCKED => 'не е заключена',
+ DB_ERROR_SYNTAX => 'грешен ÑинтакÑиÑ',
+ DB_ERROR_UNSUPPORTED => 'не Ñе поддържа',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'некоректен брой колони в реда',
+ DB_ERROR_INVALID_DSN => 'невалиден DSN',
+ DB_ERROR_CONNECT_FAILED => 'връзката не може да бъде оÑъщеÑтвена',
+ 0 => 'нÑма грешки', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'предоÑтавените данни Ñа недоÑтатъчни',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'разширението не е намерено',
+ DB_ERROR_NOSUCHDB => 'неÑъщеÑтвуваща база данни',
+ DB_ERROR_ACCESS_VIOLATION => 'нÑмате доÑтатъчно права'
+);
+?>
+ \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-ca.inc.php b/lib/adodb/lang/adodb-ca.inc.php
new file mode 100644
index 0000000..3e6a449
--- /dev/null
+++ b/lib/adodb/lang/adodb-ca.inc.php
@@ -0,0 +1,35 @@
+<?php
+// Catalan language
+// contributed by "Josep Lladonosa" jlladono#pie.xtec.es
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'ca',
+ DB_ERROR => 'error desconegut',
+ DB_ERROR_ALREADY_EXISTS => 'ja existeix',
+ DB_ERROR_CANNOT_CREATE => 'no es pot crear',
+ DB_ERROR_CANNOT_DELETE => 'no es pot esborrar',
+ DB_ERROR_CANNOT_DROP => 'no es pot eliminar',
+ DB_ERROR_CONSTRAINT => 'violació de constraint',
+ DB_ERROR_DIVZERO => 'divisió per zero',
+ DB_ERROR_INVALID => 'no és vàlid',
+ DB_ERROR_INVALID_DATE => 'la data o l\'hora no són vàlides',
+ DB_ERROR_INVALID_NUMBER => 'el nombre no és vàlid',
+ DB_ERROR_MISMATCH => 'no hi ha coincidència',
+ DB_ERROR_NODBSELECTED => 'cap base de dades seleccionada',
+ DB_ERROR_NOSUCHFIELD => 'camp inexistent',
+ DB_ERROR_NOSUCHTABLE => 'taula inexistent',
+ DB_ERROR_NOT_CAPABLE => 'l\'execució secundària de DB no pot',
+ DB_ERROR_NOT_FOUND => 'no trobat',
+ DB_ERROR_NOT_LOCKED => 'no blocat',
+ DB_ERROR_SYNTAX => 'error de sintaxi',
+ DB_ERROR_UNSUPPORTED => 'no suportat',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'el nombre de columnes no coincideix amb el nombre de valors en la fila',
+ DB_ERROR_INVALID_DSN => 'el DSN no és vàlid',
+ DB_ERROR_CONNECT_FAILED => 'connexió fallida',
+ 0 => 'cap error', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'les dades subministrades són insuficients',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extensió no trobada',
+ DB_ERROR_NOSUCHDB => 'base de dades inexistent',
+ DB_ERROR_ACCESS_VIOLATION => 'permisos insuficients'
+);
+?>
+ \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-cn.inc.php b/lib/adodb/lang/adodb-cn.inc.php
new file mode 100644
index 0000000..eb8c7de
--- /dev/null
+++ b/lib/adodb/lang/adodb-cn.inc.php
@@ -0,0 +1,35 @@
+<?php
+// Chinese language file contributed by "Cuiyan (cysoft)" cysoft#php.net.
+// Encode by GB2312
+// Simplified Chinese
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'cn',
+ DB_ERROR => 'δ֪´íÎó',
+ DB_ERROR_ALREADY_EXISTS => 'ÒѾ­´æÔÚ',
+ DB_ERROR_CANNOT_CREATE => '²»ÄÜ´´½¨',
+ DB_ERROR_CANNOT_DELETE => '²»ÄÜɾ³ý',
+ DB_ERROR_CANNOT_DROP => '²»ÄܶªÆú',
+ DB_ERROR_CONSTRAINT => 'Ô¼ÊøÏÞÖÆ',
+ DB_ERROR_DIVZERO => '±»0³ý',
+ DB_ERROR_INVALID => 'ÎÞЧ',
+ DB_ERROR_INVALID_DATE => 'ÎÞЧµÄÈÕÆÚ»òÕßʱ¼ä',
+ DB_ERROR_INVALID_NUMBER => 'ÎÞЧµÄÊý×Ö',
+ DB_ERROR_MISMATCH => '²»Æ¥Åä',
+ DB_ERROR_NODBSELECTED => 'ûÓÐÊý¾Ý¿â±»Ñ¡Ôñ',
+ DB_ERROR_NOSUCHFIELD => 'ûÓÐÏàÓ¦µÄ×Ö¶Î',
+ DB_ERROR_NOSUCHTABLE => 'ûÓÐÏàÓ¦µÄ±í',
+ DB_ERROR_NOT_CAPABLE => 'Êý¾Ý¿âºǫ́²»¼æÈÝ',
+ DB_ERROR_NOT_FOUND => 'ûÓз¢ÏÖ',
+ DB_ERROR_NOT_LOCKED => 'ûÓб»Ëø¶¨',
+ DB_ERROR_SYNTAX => 'Óï·¨´íÎó',
+ DB_ERROR_UNSUPPORTED => '²»Ö§³Ö',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'ÔÚÐÐÉÏÀÛ¼ÆÖµ',
+ DB_ERROR_INVALID_DSN => 'ÎÞЧµÄÊý¾ÝÔ´ (DSN)',
+ DB_ERROR_CONNECT_FAILED => 'Á¬½Óʧ°Ü',
+ 0 => 'ûÓдíÎó', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'ÌṩµÄÊý¾Ý²»ÄÜ·ûºÏÒªÇó',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'À©Õ¹Ã»Óб»·¢ÏÖ',
+ DB_ERROR_NOSUCHDB => 'ûÓÐÏàÓ¦µÄÊý¾Ý¿â',
+ DB_ERROR_ACCESS_VIOLATION => 'ûÓкÏÊʵÄȨÏÞ'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-cz.inc.php b/lib/adodb/lang/adodb-cz.inc.php
new file mode 100644
index 0000000..2424c24
--- /dev/null
+++ b/lib/adodb/lang/adodb-cz.inc.php
@@ -0,0 +1,40 @@
+<?php
+
+# Czech language, encoding by ISO 8859-2 charset (Iso Latin-2)
+# For convert to MS Windows use shell command:
+# iconv -f ISO_8859-2 -t CP1250 < adodb-cz.inc.php
+# For convert to ASCII use shell command:
+# unaccent ISO_8859-2 < adodb-cz.inc.php
+# v1.0, 19.06.2003 Kamil Jakubovic <jake@host.sk>
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'cz',
+ DB_ERROR => 'neznámá chyba',
+ DB_ERROR_ALREADY_EXISTS => 'ji? existuje',
+ DB_ERROR_CANNOT_CREATE => 'nelze vytvo?it',
+ DB_ERROR_CANNOT_DELETE => 'nelze smazat',
+ DB_ERROR_CANNOT_DROP => 'nelze odstranit',
+ DB_ERROR_CONSTRAINT => 'poru?ení omezující podmínky',
+ DB_ERROR_DIVZERO => 'd?lení nulou',
+ DB_ERROR_INVALID => 'neplatné',
+ DB_ERROR_INVALID_DATE => 'neplatné datum nebo ?as',
+ DB_ERROR_INVALID_NUMBER => 'neplatné ?íslo',
+ DB_ERROR_MISMATCH => 'nesouhlasí',
+ DB_ERROR_NODBSELECTED => '?ádná databáze není vybrána',
+ DB_ERROR_NOSUCHFIELD => 'pole nenalezeno',
+ DB_ERROR_NOSUCHTABLE => 'tabulka nenalezena',
+ DB_ERROR_NOT_CAPABLE => 'nepodporováno',
+ DB_ERROR_NOT_FOUND => 'nenalezeno',
+ DB_ERROR_NOT_LOCKED => 'nezam?eno',
+ DB_ERROR_SYNTAX => 'syntaktická chyba',
+ DB_ERROR_UNSUPPORTED => 'nepodporováno',
+ DB_ERROR_VALUE_COUNT_ON_ROW => '',
+ DB_ERROR_INVALID_DSN => 'neplatné DSN',
+ DB_ERROR_CONNECT_FAILED => 'p?ipojení selhalo',
+ 0 => 'bez chyb', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'málo zdrojových dat',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'roz?í?ení nenalezeno',
+ DB_ERROR_NOSUCHDB => 'databáze neexistuje',
+ DB_ERROR_ACCESS_VIOLATION => 'nedostate?ná práva'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-da.inc.php b/lib/adodb/lang/adodb-da.inc.php
new file mode 100644
index 0000000..ca0e72d
--- /dev/null
+++ b/lib/adodb/lang/adodb-da.inc.php
@@ -0,0 +1,33 @@
+<?php
+// Arne Eckmann bananstat#users.sourceforge.net
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'da',
+ DB_ERROR => 'ukendt fejl',
+ DB_ERROR_ALREADY_EXISTS => 'eksisterer allerede',
+ DB_ERROR_CANNOT_CREATE => 'kan ikke oprette',
+ DB_ERROR_CANNOT_DELETE => 'kan ikke slette',
+ DB_ERROR_CANNOT_DROP => 'kan ikke droppe',
+ DB_ERROR_CONSTRAINT => 'begr&aelig;nsning kr&aelig;nket',
+ DB_ERROR_DIVZERO => 'division med nul',
+ DB_ERROR_INVALID => 'ugyldig',
+ DB_ERROR_INVALID_DATE => 'ugyldig dato eller klokkeslet',
+ DB_ERROR_INVALID_NUMBER => 'ugyldigt tal',
+ DB_ERROR_MISMATCH => 'mismatch',
+ DB_ERROR_NODBSELECTED => 'ingen database valgt',
+ DB_ERROR_NOSUCHFIELD => 'felt findes ikke',
+ DB_ERROR_NOSUCHTABLE => 'tabel findes ikke',
+ DB_ERROR_NOT_CAPABLE => 'DB backend opgav',
+ DB_ERROR_NOT_FOUND => 'ikke fundet',
+ DB_ERROR_NOT_LOCKED => 'ikke l&aring;st',
+ DB_ERROR_SYNTAX => 'syntaksfejl',
+ DB_ERROR_UNSUPPORTED => 'ikke underst&oslash;ttet',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'resulterende antal felter svarer ikke til foresp&oslash;rgslens antal felter',
+ DB_ERROR_INVALID_DSN => 'ugyldig DSN',
+ DB_ERROR_CONNECT_FAILED => 'tilslutning mislykkedes',
+ 0 => 'ingen fejl', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'utilstr&aelig;kkelige data angivet',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'udvidelse ikke fundet',
+ DB_ERROR_NOSUCHDB => 'database ikke fundet',
+ DB_ERROR_ACCESS_VIOLATION => 'utilstr&aelig;kkelige rettigheder'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-de.inc.php b/lib/adodb/lang/adodb-de.inc.php
new file mode 100644
index 0000000..244cb2f
--- /dev/null
+++ b/lib/adodb/lang/adodb-de.inc.php
@@ -0,0 +1,33 @@
+<?php
+// contributed by "Heinz Hombergs" <opn@hhombergs.de>
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'de',
+ DB_ERROR => 'Unbekannter Fehler',
+ DB_ERROR_ALREADY_EXISTS => 'existiert bereits',
+ DB_ERROR_CANNOT_CREATE => 'kann nicht erstellen',
+ DB_ERROR_CANNOT_DELETE => 'kann nicht l&ouml;schen',
+ DB_ERROR_CANNOT_DROP => 'Tabelle oder Index konnte nicht gel&ouml;scht werden',
+ DB_ERROR_CONSTRAINT => 'Constraint Verletzung',
+ DB_ERROR_DIVZERO => 'Division durch Null',
+ DB_ERROR_INVALID => 'ung&uml;ltig',
+ DB_ERROR_INVALID_DATE => 'ung&uml;ltiges Datum oder Zeit',
+ DB_ERROR_INVALID_NUMBER => 'ung&uml;ltige Zahl',
+ DB_ERROR_MISMATCH => 'Unvertr&auml;glichkeit',
+ DB_ERROR_NODBSELECTED => 'keine Dantebank ausgew&auml;hlt',
+ DB_ERROR_NOSUCHFIELD => 'Feld nicht vorhanden',
+ DB_ERROR_NOSUCHTABLE => 'Tabelle nicht vorhanden',
+ DB_ERROR_NOT_CAPABLE => 'Funktion nicht installiert',
+ DB_ERROR_NOT_FOUND => 'nicht gefunden',
+ DB_ERROR_NOT_LOCKED => 'nicht gesperrt',
+ DB_ERROR_SYNTAX => 'Syntaxfehler',
+ DB_ERROR_UNSUPPORTED => 'nicht Unterst&uml;tzt',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'Anzahl der zur&uml;ckgelieferten Felder entspricht nicht der Anzahl der Felder in der Abfrage',
+ DB_ERROR_INVALID_DSN => 'ung&uml;ltiger DSN',
+ DB_ERROR_CONNECT_FAILED => 'Verbindung konnte nicht hergestellt werden',
+ 0 => 'kein Fehler', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'Nicht gen&uml;gend Daten geliefert',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'erweiterung nicht gefunden',
+ DB_ERROR_NOSUCHDB => 'keine Datenbank',
+ DB_ERROR_ACCESS_VIOLATION => 'ungen&uml;gende Rechte'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-en.inc.php b/lib/adodb/lang/adodb-en.inc.php
new file mode 100644
index 0000000..ed1b8f1
--- /dev/null
+++ b/lib/adodb/lang/adodb-en.inc.php
@@ -0,0 +1,34 @@
+<?php
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'en',
+ DB_ERROR => 'unknown error',
+ DB_ERROR_ALREADY_EXISTS => 'already exists',
+ DB_ERROR_CANNOT_CREATE => 'can not create',
+ DB_ERROR_CANNOT_DELETE => 'can not delete',
+ DB_ERROR_CANNOT_DROP => 'can not drop',
+ DB_ERROR_CONSTRAINT => 'constraint violation',
+ DB_ERROR_DIVZERO => 'division by zero',
+ DB_ERROR_INVALID => 'invalid',
+ DB_ERROR_INVALID_DATE => 'invalid date or time',
+ DB_ERROR_INVALID_NUMBER => 'invalid number',
+ DB_ERROR_MISMATCH => 'mismatch',
+ DB_ERROR_NODBSELECTED => 'no database selected',
+ DB_ERROR_NOSUCHFIELD => 'no such field',
+ DB_ERROR_NOSUCHTABLE => 'no such table',
+ DB_ERROR_NOT_CAPABLE => 'DB backend not capable',
+ DB_ERROR_NOT_FOUND => 'not found',
+ DB_ERROR_NOT_LOCKED => 'not locked',
+ DB_ERROR_SYNTAX => 'syntax error',
+ DB_ERROR_UNSUPPORTED => 'not supported',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'value count on row',
+ DB_ERROR_INVALID_DSN => 'invalid DSN',
+ DB_ERROR_CONNECT_FAILED => 'connect failed',
+ 0 => 'no error', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'insufficient data supplied',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extension not found',
+ DB_ERROR_NOSUCHDB => 'no such database',
+ DB_ERROR_ACCESS_VIOLATION => 'insufficient permissions'
+);
+?>
+ \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-es.inc.php b/lib/adodb/lang/adodb-es.inc.php
new file mode 100644
index 0000000..1e0afbb
--- /dev/null
+++ b/lib/adodb/lang/adodb-es.inc.php
@@ -0,0 +1,33 @@
+<?php
+// contributed by "Horacio Degiorgi" <horaciod@codigophp.com>
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'es',
+ DB_ERROR => 'error desconocido',
+ DB_ERROR_ALREADY_EXISTS => 'ya existe',
+ DB_ERROR_CANNOT_CREATE => 'imposible crear',
+ DB_ERROR_CANNOT_DELETE => 'imposible borrar',
+ DB_ERROR_CANNOT_DROP => 'imposible hacer drop',
+ DB_ERROR_CONSTRAINT => 'violacion de constraint',
+ DB_ERROR_DIVZERO => 'division por cero',
+ DB_ERROR_INVALID => 'invalido',
+ DB_ERROR_INVALID_DATE => 'fecha u hora invalida',
+ DB_ERROR_INVALID_NUMBER => 'numero invalido',
+ DB_ERROR_MISMATCH => 'error',
+ DB_ERROR_NODBSELECTED => 'no hay base de datos seleccionada',
+ DB_ERROR_NOSUCHFIELD => 'campo invalido',
+ DB_ERROR_NOSUCHTABLE => 'tabla no existe',
+ DB_ERROR_NOT_CAPABLE => 'capacidad invalida para esta DB',
+ DB_ERROR_NOT_FOUND => 'no encontrado',
+ DB_ERROR_NOT_LOCKED => 'no bloqueado',
+ DB_ERROR_SYNTAX => 'error de sintaxis',
+ DB_ERROR_UNSUPPORTED => 'no soportado',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'la cantidad de columnas no corresponden a la cantidad de valores',
+ DB_ERROR_INVALID_DSN => 'DSN invalido',
+ DB_ERROR_CONNECT_FAILED => 'fallo la conexion',
+ 0 => 'sin error', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'insuficientes datos',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extension no encontrada',
+ DB_ERROR_NOSUCHDB => 'base de datos no encontrada',
+ DB_ERROR_ACCESS_VIOLATION => 'permisos insuficientes'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-esperanto.inc.php b/lib/adodb/lang/adodb-esperanto.inc.php
new file mode 100644
index 0000000..16ca00e
--- /dev/null
+++ b/lib/adodb/lang/adodb-esperanto.inc.php
@@ -0,0 +1,35 @@
+<?php
+// Vivu Esperanto cxiam!
+// Traduko fare de Antono Vasiljev (anders[#]brainactive.org)
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'eo',
+ DB_ERROR => 'nekonata eraro',
+ DB_ERROR_ALREADY_EXISTS => 'jam ekzistas',
+ DB_ERROR_CANNOT_CREATE => 'maleblas krei',
+ DB_ERROR_CANNOT_DELETE => 'maleblas elimini',
+ DB_ERROR_CANNOT_DROP => 'maleblas elimini (drop)',
+ DB_ERROR_CONSTRAINT => 'rompo de kondicxoj de provo',
+ DB_ERROR_DIVZERO => 'divido per 0 (nul)',
+ DB_ERROR_INVALID => 'malregule',
+ DB_ERROR_INVALID_DATE => 'malregula dato kaj tempo',
+ DB_ERROR_INVALID_NUMBER => 'malregula nombro',
+ DB_ERROR_MISMATCH => 'eraro',
+ DB_ERROR_NODBSELECTED => 'datumbazo ne elektita',
+ DB_ERROR_NOSUCHFIELD => 'ne ekzistas kampo',
+ DB_ERROR_NOSUCHTABLE => 'ne ekzistas tabelo',
+ DB_ERROR_NOT_CAPABLE => 'DBMS ne povas',
+ DB_ERROR_NOT_FOUND => 'ne trovita',
+ DB_ERROR_NOT_LOCKED => 'ne blokita',
+ DB_ERROR_SYNTAX => 'sintaksa eraro',
+ DB_ERROR_UNSUPPORTED => 'ne apogata',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'nombrilo de valoroj en linio',
+ DB_ERROR_INVALID_DSN => 'malregula DSN-o',
+ DB_ERROR_CONNECT_FAILED => 'konekto malsukcesa',
+ 0 => 'cxio bone', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'ne suficxe da datumo',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'etendo ne trovita',
+ DB_ERROR_NOSUCHDB => 'datumbazo ne ekzistas',
+ DB_ERROR_ACCESS_VIOLATION => 'ne suficxe da rajto por atingo'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-fr.inc.php b/lib/adodb/lang/adodb-fr.inc.php
new file mode 100644
index 0000000..066a2a5
--- /dev/null
+++ b/lib/adodb/lang/adodb-fr.inc.php
@@ -0,0 +1,33 @@
+<?php
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'fr',
+ DB_ERROR => 'erreur inconnue',
+ DB_ERROR_ALREADY_EXISTS => 'existe d&eacute;j&agrave;',
+ DB_ERROR_CANNOT_CREATE => 'cr&eacute;tion impossible',
+ DB_ERROR_CANNOT_DELETE => 'effacement impossible',
+ DB_ERROR_CANNOT_DROP => 'suppression impossible',
+ DB_ERROR_CONSTRAINT => 'violation de contrainte',
+ DB_ERROR_DIVZERO => 'division par z&eacute;ro',
+ DB_ERROR_INVALID => 'invalide',
+ DB_ERROR_INVALID_DATE => 'date ou heure invalide',
+ DB_ERROR_INVALID_NUMBER => 'nombre invalide',
+ DB_ERROR_MISMATCH => 'erreur de concordance',
+ DB_ERROR_NODBSELECTED => 'pas de base de donn&eacute;ess&eacute;lectionn&eacute;e',
+ DB_ERROR_NOSUCHFIELD => 'nom de colonne invalide',
+ DB_ERROR_NOSUCHTABLE => 'table ou vue inexistante',
+ DB_ERROR_NOT_CAPABLE => 'fonction optionnelle non install&eacute;e',
+ DB_ERROR_NOT_FOUND => 'pas trouv&eacute;',
+ DB_ERROR_NOT_LOCKED => 'non verrouill&eacute;',
+ DB_ERROR_SYNTAX => 'erreur de syntaxe',
+ DB_ERROR_UNSUPPORTED => 'non support&eacute;',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'valeur ins&eacute;r&eacute;e trop grande pour colonne',
+ DB_ERROR_INVALID_DSN => 'DSN invalide',
+ DB_ERROR_CONNECT_FAILED => '&eacute;chec &agrave; la connexion',
+ 0 => "pas d'erreur", // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'donn&eacute;es fournies insuffisantes',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extension non trouv&eacute;e',
+ DB_ERROR_NOSUCHDB => 'base de donn&eacute;es inconnue',
+ DB_ERROR_ACCESS_VIOLATION => 'droits insuffisants'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-hu.inc.php b/lib/adodb/lang/adodb-hu.inc.php
new file mode 100644
index 0000000..d6f0ef8
--- /dev/null
+++ b/lib/adodb/lang/adodb-hu.inc.php
@@ -0,0 +1,34 @@
+<?php
+# Hungarian language, encoding by ISO 8859-2 charset (Iso Latin-2)
+# Halászvári Gábor <g.halaszvari#portmax.hu>
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'hu',
+ DB_ERROR => 'ismeretlen hiba',
+ DB_ERROR_ALREADY_EXISTS => 'már létezik',
+ DB_ERROR_CANNOT_CREATE => 'nem sikerült létrehozni',
+ DB_ERROR_CANNOT_DELETE => 'nem sikerült törölni',
+ DB_ERROR_CANNOT_DROP => 'nem sikerült eldobni',
+ DB_ERROR_CONSTRAINT => 'szabályok megszegése',
+ DB_ERROR_DIVZERO => 'osztás nullával',
+ DB_ERROR_INVALID => 'érvénytelen',
+ DB_ERROR_INVALID_DATE => 'érvénytelen dátum vagy idõ',
+ DB_ERROR_INVALID_NUMBER => 'érvénytelen szám',
+ DB_ERROR_MISMATCH => 'nem megfelelõ',
+ DB_ERROR_NODBSELECTED => 'nincs kiválasztott adatbázis',
+ DB_ERROR_NOSUCHFIELD => 'nincs ilyen mezõ',
+ DB_ERROR_NOSUCHTABLE => 'nincs ilyen tábla',
+ DB_ERROR_NOT_CAPABLE => 'DB backend nem támogatja',
+ DB_ERROR_NOT_FOUND => 'nem található',
+ DB_ERROR_NOT_LOCKED => 'nincs lezárva',
+ DB_ERROR_SYNTAX => 'szintaktikai hiba',
+ DB_ERROR_UNSUPPORTED => 'nem támogatott',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'soron végzett érték számlálás',
+ DB_ERROR_INVALID_DSN => 'hibás DSN',
+ DB_ERROR_CONNECT_FAILED => 'sikertelen csatlakozás',
+ 0 => 'nincs hiba', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'túl kevés az adat',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'bõvítmény nem található',
+ DB_ERROR_NOSUCHDB => 'nincs ilyen adatbázis',
+ DB_ERROR_ACCESS_VIOLATION => 'nincs jogosultság'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-it.inc.php b/lib/adodb/lang/adodb-it.inc.php
new file mode 100644
index 0000000..20c5b93
--- /dev/null
+++ b/lib/adodb/lang/adodb-it.inc.php
@@ -0,0 +1,34 @@
+<?php
+// Italian language file contributed by Tiraboschi Massimiliano aka TiMax
+// www.maxdev.com timax@maxdev.com
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'it',
+ DB_ERROR => 'errore sconosciuto',
+ DB_ERROR_ALREADY_EXISTS => 'esiste gi&agrave;',
+ DB_ERROR_CANNOT_CREATE => 'non posso creare',
+ DB_ERROR_CANNOT_DELETE => 'non posso cancellare',
+ DB_ERROR_CANNOT_DROP => 'non posso eliminare',
+ DB_ERROR_CONSTRAINT => 'violazione constraint',
+ DB_ERROR_DIVZERO => 'divisione per zero',
+ DB_ERROR_INVALID => 'non valido',
+ DB_ERROR_INVALID_DATE => 'data od ora non valida',
+ DB_ERROR_INVALID_NUMBER => 'numero non valido',
+ DB_ERROR_MISMATCH => 'diversi',
+ DB_ERROR_NODBSELECTED => 'nessun database selezionato',
+ DB_ERROR_NOSUCHFIELD => 'nessun campo trovato',
+ DB_ERROR_NOSUCHTABLE => 'nessuna tabella trovata',
+ DB_ERROR_NOT_CAPABLE => 'DB backend non abilitato',
+ DB_ERROR_NOT_FOUND => 'non trovato',
+ DB_ERROR_NOT_LOCKED => 'non bloccato',
+ DB_ERROR_SYNTAX => 'errore di sintassi',
+ DB_ERROR_UNSUPPORTED => 'non supportato',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'valore inserito troppo grande per una colonna',
+ DB_ERROR_INVALID_DSN => 'DSN non valido',
+ DB_ERROR_CONNECT_FAILED => 'connessione fallita',
+ 0 => 'nessun errore', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'dati inseriti insufficienti',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'estensione non trovata',
+ DB_ERROR_NOSUCHDB => 'database non trovato',
+ DB_ERROR_ACCESS_VIOLATION => 'permessi insufficienti'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-nl.inc.php b/lib/adodb/lang/adodb-nl.inc.php
new file mode 100644
index 0000000..abe77b5
--- /dev/null
+++ b/lib/adodb/lang/adodb-nl.inc.php
@@ -0,0 +1,33 @@
+<?php
+// Translated by Pim Koeman (pim#wittenborg-university.com)
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'nl',
+ DB_ERROR => 'onbekende fout',
+ DB_ERROR_ALREADY_EXISTS => 'bestaat al',
+ DB_ERROR_CANNOT_CREATE => 'kan niet aanmaken',
+ DB_ERROR_CANNOT_DELETE => 'kan niet wissen',
+ DB_ERROR_CANNOT_DROP => 'kan niet verwijderen',
+ DB_ERROR_CONSTRAINT => 'constraint overtreding',
+ DB_ERROR_DIVZERO => 'poging tot delen door nul',
+ DB_ERROR_INVALID => 'ongeldig',
+ DB_ERROR_INVALID_DATE => 'ongeldige datum of tijd',
+ DB_ERROR_INVALID_NUMBER => 'ongeldig nummer',
+ DB_ERROR_MISMATCH => 'is incorrect',
+ DB_ERROR_NODBSELECTED => 'geen database geselecteerd',
+ DB_ERROR_NOSUCHFIELD => 'onbekend veld',
+ DB_ERROR_NOSUCHTABLE => 'onbekende tabel',
+ DB_ERROR_NOT_CAPABLE => 'database systeem is niet tot uitvoer in staat',
+ DB_ERROR_NOT_FOUND => 'niet gevonden',
+ DB_ERROR_NOT_LOCKED => 'niet vergrendeld',
+ DB_ERROR_SYNTAX => 'syntaxis fout',
+ DB_ERROR_UNSUPPORTED => 'niet ondersteund',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'waarde telling op rij',
+ DB_ERROR_INVALID_DSN => 'ongeldige DSN',
+ DB_ERROR_CONNECT_FAILED => 'connectie mislukt',
+ 0 => 'geen fout', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'onvoldoende data gegeven',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extensie niet gevonden',
+ DB_ERROR_NOSUCHDB => 'onbekende database',
+ DB_ERROR_ACCESS_VIOLATION => 'onvoldoende rechten'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-pl.inc.php b/lib/adodb/lang/adodb-pl.inc.php
new file mode 100644
index 0000000..aee5bfd
--- /dev/null
+++ b/lib/adodb/lang/adodb-pl.inc.php
@@ -0,0 +1,36 @@
+<?php
+
+// Contributed by Grzegorz Pacan <gp#dione.cc>
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'pl',
+ DB_ERROR => 'niezidentyfikowany b³±d',
+ DB_ERROR_ALREADY_EXISTS => 'ju¿ istniej±',
+ DB_ERROR_CANNOT_CREATE => 'nie mo¿na stworzyæ',
+ DB_ERROR_CANNOT_DELETE => 'nie mo¿na usun±æ',
+ DB_ERROR_CANNOT_DROP => 'nie mo¿na porzuciæ',
+ DB_ERROR_CONSTRAINT => 'pogwa³cenie uprawnieñ',
+ DB_ERROR_DIVZERO => 'dzielenie przez zero',
+ DB_ERROR_INVALID => 'b³êdny',
+ DB_ERROR_INVALID_DATE => 'b³êdna godzina lub data',
+ DB_ERROR_INVALID_NUMBER => 'b³êdny numer',
+ DB_ERROR_MISMATCH => 'niedopasowanie',
+ DB_ERROR_NODBSELECTED => 'baza danych nie zosta³a wybrana',
+ DB_ERROR_NOSUCHFIELD => 'nie znaleziono pola',
+ DB_ERROR_NOSUCHTABLE => 'nie znaleziono tabeli',
+ DB_ERROR_NOT_CAPABLE => 'nie zdolny',
+ DB_ERROR_NOT_FOUND => 'nie znaleziono',
+ DB_ERROR_NOT_LOCKED => 'nie zakmniêty',
+ DB_ERROR_SYNTAX => 'b³±d sk³adni',
+ DB_ERROR_UNSUPPORTED => 'nie obs³uguje',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'warto¶æ liczona w szeregu',
+ DB_ERROR_INVALID_DSN => 'b³êdny DSN',
+ DB_ERROR_CONNECT_FAILED => 'po³±czenie nie zosta³o zrealizowane',
+ 0 => 'brak b³êdów', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'niedostateczna ilo¶æ informacji',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'nie znaleziono rozszerzenia',
+ DB_ERROR_NOSUCHDB => 'nie znaleziono bazy',
+ DB_ERROR_ACCESS_VIOLATION => 'niedostateczne uprawnienia'
+);
+?>
+ \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-pt-br.inc.php b/lib/adodb/lang/adodb-pt-br.inc.php
new file mode 100644
index 0000000..3424099
--- /dev/null
+++ b/lib/adodb/lang/adodb-pt-br.inc.php
@@ -0,0 +1,35 @@
+<?php
+// contributed by "Levi Fukumori" levi _AT_ fukumori _DOT_ com _DOT_ br
+// portugese (brazilian)
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'pt-br',
+ DB_ERROR => 'erro desconhecido',
+ DB_ERROR_ALREADY_EXISTS => 'já existe',
+ DB_ERROR_CANNOT_CREATE => 'impossível criar',
+ DB_ERROR_CANNOT_DELETE => 'impossível excluír',
+ DB_ERROR_CANNOT_DROP => 'impossível remover',
+ DB_ERROR_CONSTRAINT => 'violação do confinamente',
+ DB_ERROR_DIVZERO => 'divisão por zero',
+ DB_ERROR_INVALID => 'inválido',
+ DB_ERROR_INVALID_DATE => 'data ou hora inválida',
+ DB_ERROR_INVALID_NUMBER => 'número inválido',
+ DB_ERROR_MISMATCH => 'erro',
+ DB_ERROR_NODBSELECTED => 'nenhum banco de dados selecionado',
+ DB_ERROR_NOSUCHFIELD => 'campo inválido',
+ DB_ERROR_NOSUCHTABLE => 'tabela inexistente',
+ DB_ERROR_NOT_CAPABLE => 'capacidade inválida para este BD',
+ DB_ERROR_NOT_FOUND => 'não encontrado',
+ DB_ERROR_NOT_LOCKED => 'não bloqueado',
+ DB_ERROR_SYNTAX => 'erro de sintaxe',
+ DB_ERROR_UNSUPPORTED =>
+'não suportado',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'a quantidade de colunas não corresponde ao de valores',
+ DB_ERROR_INVALID_DSN => 'DSN inválido',
+ DB_ERROR_CONNECT_FAILED => 'falha na conexão',
+ 0 => 'sem erro', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'dados insuficientes',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extensão não encontrada',
+ DB_ERROR_NOSUCHDB => 'banco de dados não encontrado',
+ DB_ERROR_ACCESS_VIOLATION => 'permissão insuficiente'
+);
+?>
diff --git a/lib/adodb/lang/adodb-ro.inc.php b/lib/adodb/lang/adodb-ro.inc.php
new file mode 100644
index 0000000..7c9aa52
--- /dev/null
+++ b/lib/adodb/lang/adodb-ro.inc.php
@@ -0,0 +1,36 @@
+<?php
+
+/* Romanian - by "bogdan stefan" <sbogdan#rsb.ro> */
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'ro',
+ DB_ERROR => 'eroare necunoscuta',
+ DB_ERROR_ALREADY_EXISTS => 'deja exista',
+ DB_ERROR_CANNOT_CREATE => 'nu se poate creea',
+ DB_ERROR_CANNOT_DELETE => 'nu se poate sterge',
+ DB_ERROR_CANNOT_DROP => 'nu se poate executa drop',
+ DB_ERROR_CONSTRAINT => 'violare de constrain',
+ DB_ERROR_DIVZERO => 'se divide la zero',
+ DB_ERROR_INVALID => 'invalid',
+ DB_ERROR_INVALID_DATE => 'data sau timp invalide',
+ DB_ERROR_INVALID_NUMBER => 'numar invalid',
+ DB_ERROR_MISMATCH => 'nepotrivire-mismatch',
+ DB_ERROR_NODBSELECTED => 'nu exista baza de date selectata',
+ DB_ERROR_NOSUCHFIELD => 'camp inexistent',
+ DB_ERROR_NOSUCHTABLE => 'tabela inexistenta',
+ DB_ERROR_NOT_CAPABLE => 'functie optionala neinstalata',
+ DB_ERROR_NOT_FOUND => 'negasit',
+ DB_ERROR_NOT_LOCKED => 'neblocat',
+ DB_ERROR_SYNTAX => 'eroare de sintaxa',
+ DB_ERROR_UNSUPPORTED => 'nu e suportat',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'valoare prea mare pentru coloana',
+ DB_ERROR_INVALID_DSN => 'DSN invalid',
+ DB_ERROR_CONNECT_FAILED => 'conectare esuata',
+ 0 => 'fara eroare', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'data introduse insuficiente',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'extensie negasita',
+ DB_ERROR_NOSUCHDB => 'nu exista baza de date',
+ DB_ERROR_ACCESS_VIOLATION => 'permisiuni insuficiente'
+);
+?>
+
diff --git a/lib/adodb/lang/adodb-ru1251.inc.php b/lib/adodb/lang/adodb-ru1251.inc.php
new file mode 100644
index 0000000..3a20538
--- /dev/null
+++ b/lib/adodb/lang/adodb-ru1251.inc.php
@@ -0,0 +1,35 @@
+<?php
+
+// Russian language file contributed by "Cyrill Malevanov" cyrill#malevanov.spb.ru.
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'ru1251',
+ DB_ERROR => 'íåèçâåñòíàÿ îøèáêà',
+ DB_ERROR_ALREADY_EXISTS => 'óæå ñóùåñòâóåò',
+ DB_ERROR_CANNOT_CREATE => 'íåâîçìîæíî ñîçäàòü',
+ DB_ERROR_CANNOT_DELETE => 'íåâîçìîæíî óäàëèòü',
+ DB_ERROR_CANNOT_DROP => 'íåâîçìîæíî óäàëèòü (drop)',
+ DB_ERROR_CONSTRAINT => 'íàðóøåíèå óñëîâèé ïðîâåðêè',
+ DB_ERROR_DIVZERO => 'äåëåíèå íà 0',
+ DB_ERROR_INVALID => 'íåïðàâèëüíî',
+ DB_ERROR_INVALID_DATE => 'íåêîððåêòíàÿ äàòà èëè âðåìÿ',
+ DB_ERROR_INVALID_NUMBER => 'íåêîððåêòíîå ÷èñëî',
+ DB_ERROR_MISMATCH => 'îøèáêà',
+ DB_ERROR_NODBSELECTED => 'ÁÄ íå âûáðàíà',
+ DB_ERROR_NOSUCHFIELD => 'íå ñóùåñòâóåò ïîëå',
+ DB_ERROR_NOSUCHTABLE => 'íå ñóùåñòâóåò òàáëèöà',
+ DB_ERROR_NOT_CAPABLE => 'ÑÓÁÄ íå â ñîñòîÿíèè',
+ DB_ERROR_NOT_FOUND => 'íå íàéäåíî',
+ DB_ERROR_NOT_LOCKED => 'íå çàáëîêèðîâàíî',
+ DB_ERROR_SYNTAX => 'ñèíòàêñè÷åñêàÿ îøèáêà',
+ DB_ERROR_UNSUPPORTED => 'íå ïîääåðæèâàåòñÿ',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'ñ÷åò÷èê çíà÷åíèé â ñòðîêå',
+ DB_ERROR_INVALID_DSN => 'íåïðàâèëüíàÿ DSN',
+ DB_ERROR_CONNECT_FAILED => 'ñîåäèíåíèå íåóñïåøíî',
+ 0 => 'íåò îøèáêè', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'ïðåäîñòàâëåíî íåäîñòàòî÷íî äàííûõ',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'ðàñøèðåíèå íå íàéäåíî',
+ DB_ERROR_NOSUCHDB => 'íå ñóùåñòâóåò ÁÄ',
+ DB_ERROR_ACCESS_VIOLATION => 'íåäîñòàòî÷íî ïðàâ äîñòóïà'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-sv.inc.php b/lib/adodb/lang/adodb-sv.inc.php
new file mode 100644
index 0000000..a9fd698
--- /dev/null
+++ b/lib/adodb/lang/adodb-sv.inc.php
@@ -0,0 +1,33 @@
+<?php
+// Christian Tiberg" christian@commsoft.nu
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'en',
+ DB_ERROR => 'Okänt fel',
+ DB_ERROR_ALREADY_EXISTS => 'finns redan',
+ DB_ERROR_CANNOT_CREATE => 'kan inte skapa',
+ DB_ERROR_CANNOT_DELETE => 'kan inte ta bort',
+ DB_ERROR_CANNOT_DROP => 'kan inte släppa',
+ DB_ERROR_CONSTRAINT => 'begränsning kränkt',
+ DB_ERROR_DIVZERO => 'division med noll',
+ DB_ERROR_INVALID => 'ogiltig',
+ DB_ERROR_INVALID_DATE => 'ogiltigt datum eller tid',
+ DB_ERROR_INVALID_NUMBER => 'ogiltigt tal',
+ DB_ERROR_MISMATCH => 'felaktig matchning',
+ DB_ERROR_NODBSELECTED => 'ingen databas vald',
+ DB_ERROR_NOSUCHFIELD => 'inget sådant fält',
+ DB_ERROR_NOSUCHTABLE => 'ingen sådan tabell',
+ DB_ERROR_NOT_CAPABLE => 'DB backend klarar det inte',
+ DB_ERROR_NOT_FOUND => 'finns inte',
+ DB_ERROR_NOT_LOCKED => 'inte låst',
+ DB_ERROR_SYNTAX => 'syntaxfel',
+ DB_ERROR_UNSUPPORTED => 'stöds ej',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'värde räknat på rad',
+ DB_ERROR_INVALID_DSN => 'ogiltig DSN',
+ DB_ERROR_CONNECT_FAILED => 'anslutning misslyckades',
+ 0 => 'inget fel', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'otillräckligt med data angivet',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'utökning hittades ej',
+ DB_ERROR_NOSUCHDB => 'ingen sådan databas',
+ DB_ERROR_ACCESS_VIOLATION => 'otillräckliga rättigheter'
+);
+?> \ No newline at end of file
diff --git a/lib/adodb/lang/adodb-uk1251.inc.php b/lib/adodb/lang/adodb-uk1251.inc.php
new file mode 100644
index 0000000..9fa32ed
--- /dev/null
+++ b/lib/adodb/lang/adodb-uk1251.inc.php
@@ -0,0 +1,35 @@
+<?php
+
+// Ukrainian language file contributed by Alex Rootoff rootoff{AT}pisem.net.
+
+$ADODB_LANG_ARRAY = array (
+ 'LANG' => 'uk1251',
+ DB_ERROR => 'íåâ³äîìà ïîìèëêà',
+ DB_ERROR_ALREADY_EXISTS => 'âæå ³ñíóº',
+ DB_ERROR_CANNOT_CREATE => 'íåìîæëèâî ñòâîðèòè',
+ DB_ERROR_CANNOT_DELETE => 'íåìîæëèâî âèäàëèòè',
+ DB_ERROR_CANNOT_DROP => 'íåìîæëèâî çíèùèòè (drop)',
+ DB_ERROR_CONSTRAINT => 'ïîðóøåííÿ óìîâ ïåðåâ³ðêè',
+ DB_ERROR_DIVZERO => 'ä³ëåííÿ íà 0',
+ DB_ERROR_INVALID => 'íåïðàâèëüíî',
+ DB_ERROR_INVALID_DATE => 'íåïðàâèëüíà äàòà ÷è ÷àñ',
+ DB_ERROR_INVALID_NUMBER => 'íåïðàâèëüíå ÷èñëî',
+ DB_ERROR_MISMATCH => 'ïîìèëêà',
+ DB_ERROR_NODBSELECTED => 'íå âèáðàíî ÁÄ',
+ DB_ERROR_NOSUCHFIELD => 'íå ³ñíóº ïîëå',
+ DB_ERROR_NOSUCHTABLE => 'íå ³ñíóº òàáëèöÿ',
+ DB_ERROR_NOT_CAPABLE => 'ÑÓÁÄ íå â ñòàí³',
+ DB_ERROR_NOT_FOUND => 'íå çíàéäåíî',
+ DB_ERROR_NOT_LOCKED => 'íå çàáëîêîâàíî',
+ DB_ERROR_SYNTAX => 'ñèíòàêñè÷íà ïîìèëêà',
+ DB_ERROR_UNSUPPORTED => 'íå ï³äòðèìóºòüñÿ',
+ DB_ERROR_VALUE_COUNT_ON_ROW => 'ðàõ³âíèê çíà÷åíü â ñòð³÷ö³',
+ DB_ERROR_INVALID_DSN => 'íåïðàâèëüíà DSN',
+ DB_ERROR_CONNECT_FAILED => 'ç\'ºäíàííÿ íåóñï³øíå',
+ 0 => 'âñå ãàðàçä', // DB_OK
+ DB_ERROR_NEED_MORE_DATA => 'íàäàíî íåäîñòàòíüî äàíèõ',
+ DB_ERROR_EXTENSION_NOT_FOUND=> 'ðîçøèðåííÿ íå çíàéäåíî',
+ DB_ERROR_NOSUCHDB => 'íå ³ñíóº ÁÄ',
+ DB_ERROR_ACCESS_VIOLATION => 'íåäîñòàòíüî ïðàâ äîñòóïà'
+);
+?>
diff --git a/lib/adodb/perf/perf-db2.inc.php b/lib/adodb/perf/perf-db2.inc.php
new file mode 100644
index 0000000..9c8e772
--- /dev/null
+++ b/lib/adodb/perf/perf-db2.inc.php
@@ -0,0 +1,102 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Library for basic performance monitoring and tuning
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+// Simple guide to configuring db2: so-so http://www.devx.com/gethelpon/10MinuteSolution/16575
+
+// SELECT * FROM TABLE(SNAPSHOT_APPL('SAMPLE', -1)) as t
+class perf_db2 extends adodb_perf{
+ var $createTableSQL = "CREATE TABLE adodb_logsql (
+ created TIMESTAMP NOT NULL,
+ sql0 varchar(250) NOT NULL,
+ sql1 varchar(4000) NOT NULL,
+ params varchar(3000) NOT NULL,
+ tracer varchar(500) NOT NULL,
+ timer decimal(16,6) NOT NULL
+ )";
+
+ var $settings = array(
+ 'Ratios',
+ 'data cache hit ratio' => array('RATIO',
+ "SELECT
+ case when sum(POOL_DATA_L_READS+POOL_INDEX_L_READS)=0 then 0
+ else 100*(1-sum(POOL_DATA_P_READS+POOL_INDEX_P_READS)/sum(POOL_DATA_L_READS+POOL_INDEX_L_READS)) end
+ FROM TABLE(SNAPSHOT_APPL('',-2)) as t",
+ '=WarnCacheRatio'),
+
+ 'Data Cache',
+ 'data cache buffers' => array('DATAC',
+ 'select sum(npages) from SYSCAT.BUFFERPOOLS',
+ 'See <a href=http://www7b.boulder.ibm.com/dmdd/library/techarticle/anshum/0107anshum.html#bufferpoolsize>tuning reference</a>.' ),
+ 'cache blocksize' => array('DATAC',
+ 'select avg(pagesize) from SYSCAT.BUFFERPOOLS',
+ '' ),
+ 'data cache size' => array('DATAC',
+ 'select sum(npages*pagesize) from SYSCAT.BUFFERPOOLS',
+ '' ),
+ 'Connections',
+ 'current connections' => array('SESS',
+ "SELECT count(*) FROM TABLE(SNAPSHOT_APPL_INFO('',-2)) as t",
+ ''),
+
+ false
+ );
+
+
+ function perf_db2(&$conn)
+ {
+ $this->conn =& $conn;
+ }
+
+ function Explain($sql,$partial=false)
+ {
+ $save = $this->conn->LogSQL(false);
+ if ($partial) {
+ $sqlq = $this->conn->qstr($sql.'%');
+ $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
+ if ($arr) {
+ foreach($arr as $row) {
+ $sql = reset($row);
+ if (crc32($sql) == $partial) break;
+ }
+ }
+ }
+ $qno = rand();
+ $ok = $this->conn->Execute("EXPLAIN PLAN SET QUERYNO=$qno FOR $sql");
+ ob_start();
+ if (!$ok) echo "<p>Have EXPLAIN tables been created?</p>";
+ else {
+ $rs = $this->conn->Execute("select * from explain_statement where queryno=$qno");
+ if ($rs) rs2html($rs);
+ }
+ $s = ob_get_contents();
+ ob_end_clean();
+ $this->conn->LogSQL($save);
+
+ $s .= $this->Tracer($sql);
+ return $s;
+ }
+
+
+ function Tables()
+ {
+ $rs = $this->conn->Execute("select tabschema,tabname,card as rows,
+ npages pages_used,fpages pages_allocated, tbspace tablespace
+ from syscat.tables where tabschema not in ('SYSCAT','SYSIBM','SYSSTAT') order by 1,2");
+ return rs2html($rs,false,false,false,false);
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/perf/perf-informix.inc.php b/lib/adodb/perf/perf-informix.inc.php
new file mode 100644
index 0000000..d5e4757
--- /dev/null
+++ b/lib/adodb/perf/perf-informix.inc.php
@@ -0,0 +1,70 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Library for basic performance monitoring and tuning
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+//
+// Thx to Fernando Ortiz, mailto:fortiz#lacorona.com.mx
+// With info taken from http://www.oninit.com/oninit/sysmaster/index.html
+//
+class perf_informix extends adodb_perf{
+
+ // Maximum size on varchar upto 9.30 255 chars
+ // better truncate varchar to 255 than char(4000) ?
+ var $createTableSQL = "CREATE TABLE adodb_logsql (
+ created datetime year to second NOT NULL,
+ sql0 varchar(250) NOT NULL,
+ sql1 varchar(255) NOT NULL,
+ params varchar(255) NOT NULL,
+ tracer varchar(255) NOT NULL,
+ timer decimal(16,6) NOT NULL
+ )";
+
+ var $tablesSQL = "select a.tabname tablename, ti_nptotal*2 size_in_k, ti_nextns extents, ti_nrows records from systables c, sysmaster:systabnames a, sysmaster:systabinfo b where c.tabname not matches 'sys*' and c.partnum = a.partnum and c.partnum = b.ti_partnum";
+
+ var $settings = array(
+ 'Ratios',
+ 'data cache hit ratio' => array('RATIOH',
+ "select round((1-(wt.value / (rd.value + wr.value)))*100,2)
+ from sysmaster:sysprofile wr, sysmaster:sysprofile rd, sysmaster:sysprofile wt
+ where rd.name = 'pagreads' and
+ wr.name = 'pagwrites' and
+ wt.name = 'buffwts'",
+ '=WarnCacheRatio'),
+ 'IO',
+ 'data reads' => array('IO',
+ "select value from sysmaster:sysprofile where name='pagreads'",
+ 'Page reads'),
+
+ 'data writes' => array('IO',
+ "select value from sysmaster:sysprofile where name='pagwrites'",
+ 'Page writes'),
+
+ 'Connections',
+ 'current connections' => array('SESS',
+ 'select count(*) from sysmaster:syssessions',
+ 'Number of sessions'),
+
+ false
+
+ );
+
+ function perf_informix(&$conn)
+ {
+ $this->conn =& $conn;
+ }
+
+}
+?>
diff --git a/lib/adodb/perf/perf-mssql.inc.php b/lib/adodb/perf/perf-mssql.inc.php
new file mode 100644
index 0000000..f2dfa7b
--- /dev/null
+++ b/lib/adodb/perf/perf-mssql.inc.php
@@ -0,0 +1,164 @@
+<?php
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Library for basic performance monitoring and tuning
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+/*
+ MSSQL has moved most performance info to Performance Monitor
+*/
+class perf_mssql extends adodb_perf{
+ var $sql1 = 'cast(sql1 as text)';
+ var $createTableSQL = "CREATE TABLE adodb_logsql (
+ created datetime NOT NULL,
+ sql0 varchar(250) NOT NULL,
+ sql1 varchar(4000) NOT NULL,
+ params varchar(3000) NOT NULL,
+ tracer varchar(500) NOT NULL,
+ timer decimal(16,6) NOT NULL
+ )";
+
+ var $settings = array(
+ 'Ratios',
+ 'data cache hit ratio' => array('RATIO',
+ "select round((a.cntr_value*100.0)/b.cntr_value,2) from master.dbo.sysperfinfo a, master.dbo.sysperfinfo b where a.counter_name = 'Buffer cache hit ratio' and b.counter_name='Buffer cache hit ratio base'",
+ '=WarnCacheRatio'),
+ 'prepared sql hit ratio' => array('RATIO',
+ array('dbcc cachestats','Prepared',1,100),
+ ''),
+ 'adhoc sql hit ratio' => array('RATIO',
+ array('dbcc cachestats','Adhoc',1,100),
+ ''),
+ 'IO',
+ 'data reads' => array('IO',
+ "select cntr_value from master.dbo.sysperfinfo where counter_name = 'Page reads/sec'"),
+ 'data writes' => array('IO',
+ "select cntr_value from master.dbo.sysperfinfo where counter_name = 'Page writes/sec'"),
+
+ 'Data Cache',
+ 'data cache size' => array('DATAC',
+ "select cntr_value*8192 from master.dbo.sysperfinfo where counter_name = 'Total Pages' and object_name='SQLServer:Buffer Manager'",
+ '' ),
+ 'data cache blocksize' => array('DATAC',
+ "select 8192",'page size'),
+ 'Connections',
+ 'current connections' => array('SESS',
+ '=sp_who',
+ ''),
+ 'max connections' => array('SESS',
+ "SELECT @@MAX_CONNECTIONS",
+ ''),
+
+ false
+ );
+
+
+ function perf_mssql(&$conn)
+ {
+ if ($conn->dataProvider == 'odbc') {
+ $this->sql1 = 'sql1';
+ //$this->explain = false;
+ }
+ $this->conn =& $conn;
+ }
+
+ function Explain($sql,$partial=false)
+ {
+
+ $save = $this->conn->LogSQL(false);
+ if ($partial) {
+ $sqlq = $this->conn->qstr($sql.'%');
+ $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
+ if ($arr) {
+ foreach($arr as $row) {
+ $sql = reset($row);
+ if (crc32($sql) == $partial) break;
+ }
+ }
+ }
+
+ $s = '<p><b>Explain</b>: '.htmlspecialchars($sql).'</p>';
+ $this->conn->Execute("SET SHOWPLAN_ALL ON;");
+ $sql = str_replace('?',"''",$sql);
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $rs =& $this->conn->Execute($sql);
+ //adodb_printr($rs);
+ $ADODB_FETCH_MODE = $save;
+ if ($rs) {
+ $rs->MoveNext();
+ $s .= '<table bgcolor=white border=0 cellpadding="1" callspacing=0><tr><td nowrap align=center> Rows<td nowrap align=center> IO<td nowrap align=center> CPU<td align=left> &nbsp; &nbsp; Plan</tr>';
+ while (!$rs->EOF) {
+ $s .= '<tr><td>'.round($rs->fields[8],1).'<td>'.round($rs->fields[9],3).'<td align=right>'.round($rs->fields[10],3).'<td nowrap><pre>'.htmlspecialchars($rs->fields[0])."</td></pre></tr>\n"; ## NOTE CORRUPT </td></pre> tag is intentional!!!!
+ $rs->MoveNext();
+ }
+ $s .= '</table>';
+
+ $rs->NextRecordSet();
+ }
+
+ $this->conn->Execute("SET SHOWPLAN_ALL OFF;");
+ $this->conn->LogSQL($save);
+ $s .= $this->Tracer($sql);
+ return $s;
+ }
+
+ function Tables()
+ {
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ //$this->conn->debug=1;
+ $s = '<table border=1 bgcolor=white><tr><td><b>tablename</b></td><td><b>size_in_k</b></td><td><b>index size</b></td><td><b>reserved size</b></td></tr>';
+ $rs1 = $this->conn->Execute("select distinct name from sysobjects where xtype='U'");
+ if ($rs1) {
+ while (!$rs1->EOF) {
+ $tab = $rs1->fields[0];
+ $tabq = $this->conn->qstr($tab);
+ $rs2 = $this->conn->Execute("sp_spaceused $tabq");
+ if ($rs2) {
+ $s .= '<tr><td>'.$tab.'</td><td align=right>'.$rs2->fields[3].'</td><td align=right>'.$rs2->fields[4].'</td><td align=right>'.$rs2->fields[2].'</td></tr>';
+ $rs2->Close();
+ }
+ $rs1->MoveNext();
+ }
+ $rs1->Close();
+ }
+ $ADODB_FETCH_MODE = $save;
+ return $s.'</table>';
+ }
+
+ function sp_who()
+ {
+ $arr = $this->conn->GetArray('sp_who');
+ return sizeof($arr);
+ }
+
+ function HealthCheck($cli=false)
+ {
+
+ $this->conn->Execute('dbcc traceon(3604)');
+ $html = adodb_perf::HealthCheck($cli);
+ $this->conn->Execute('dbcc traceoff(3604)');
+ return $html;
+ }
+
+
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/perf/perf-mysql.inc.php b/lib/adodb/perf/perf-mysql.inc.php
new file mode 100644
index 0000000..50639d9
--- /dev/null
+++ b/lib/adodb/perf/perf-mysql.inc.php
@@ -0,0 +1,315 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Library for basic performance monitoring and tuning
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class perf_mysql extends adodb_perf{
+
+ var $tablesSQL = 'show table status';
+
+ var $createTableSQL = "CREATE TABLE adodb_logsql (
+ created datetime NOT NULL,
+ sql0 varchar(250) NOT NULL,
+ sql1 text NOT NULL,
+ params text NOT NULL,
+ tracer text NOT NULL,
+ timer decimal(16,6) NOT NULL
+ )";
+
+ var $settings = array(
+ 'Ratios',
+ 'MyISAM cache hit ratio' => array('RATIO',
+ '=GetKeyHitRatio',
+ '=WarnCacheRatio'),
+ 'InnoDB cache hit ratio' => array('RATIO',
+ '=GetInnoDBHitRatio',
+ '=WarnCacheRatio'),
+ 'data cache hit ratio' => array('HIDE', # only if called
+ '=FindDBHitRatio',
+ '=WarnCacheRatio'),
+ 'sql cache hit ratio' => array('RATIO',
+ '=GetQHitRatio',
+ ''),
+ 'IO',
+ 'data reads' => array('IO',
+ '=GetReads',
+ 'Number of selects (Key_reads is not accurate)'),
+ 'data writes' => array('IO',
+ '=GetWrites',
+ 'Number of inserts/updates/deletes * coef (Key_writes is not accurate)'),
+
+ 'Data Cache',
+ 'MyISAM data cache size' => array('DATAC',
+ array("show variables", 'key_buffer_size'),
+ '' ),
+ 'BDB data cache size' => array('DATAC',
+ array("show variables", 'bdb_cache_size'),
+ '' ),
+ 'InnoDB data cache size' => array('DATAC',
+ array("show variables", 'innodb_buffer_pool_size'),
+ '' ),
+ 'Memory Usage',
+ 'read buffer size' => array('CACHE',
+ array("show variables", 'read_buffer_size'),
+ '(per session)'),
+ 'sort buffer size' => array('CACHE',
+ array("show variables", 'sort_buffer_size'),
+ 'Size of sort buffer (per session)' ),
+ 'table cache' => array('CACHE',
+ array("show variables", 'table_cache'),
+ 'Number of tables to keep open'),
+ 'Connections',
+ 'current connections' => array('SESS',
+ array('show status','Threads_connected'),
+ ''),
+ 'max connections' => array( 'SESS',
+ array("show variables",'max_connections'),
+ ''),
+
+ false
+ );
+
+ function perf_mysql(&$conn)
+ {
+ $this->conn =& $conn;
+ }
+
+ function Explain($sql,$partial=false)
+ {
+
+ if (strtoupper(substr(trim($sql),0,6)) !== 'SELECT') return '<p>Unable to EXPLAIN non-select statement</p>';
+ $save = $this->conn->LogSQL(false);
+ if ($partial) {
+ $sqlq = $this->conn->qstr($sql.'%');
+ $arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
+ if ($arr) {
+ foreach($arr as $row) {
+ $sql = reset($row);
+ if (crc32($sql) == $partial) break;
+ }
+ }
+ }
+ $sql = str_replace('?',"''",$sql);
+
+ if ($partial) {
+ $sqlq = $this->conn->qstr($sql.'%');
+ $sql = $this->conn->GetOne("select sql1 from adodb_logsql where sql1 like $sqlq");
+ }
+
+ $s = '<p><b>Explain</b>: '.htmlspecialchars($sql).'</p>';
+ $rs = $this->conn->Execute('EXPLAIN '.$sql);
+ $s .= rs2html($rs,false,false,false,false);
+ $this->conn->LogSQL($save);
+ $s .= $this->Tracer($sql);
+ return $s;
+ }
+
+ function Tables()
+ {
+ if (!$this->tablesSQL) return false;
+
+ $rs = $this->conn->Execute($this->tablesSQL);
+ if (!$rs) return false;
+
+ $html = rs2html($rs,false,false,false,false);
+ return $html;
+ }
+
+ function GetReads()
+ {
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $rs = $this->conn->Execute('show status');
+
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if (!$rs) return 0;
+ $val = 0;
+ while (!$rs->EOF) {
+ switch($rs->fields[0]) {
+ case 'Com_select':
+ $val = $rs->fields[1];
+ $rs->Close();
+ return $val;
+ }
+ $rs->MoveNext();
+ }
+
+ $rs->Close();
+
+ return $val;
+ }
+
+ function GetWrites()
+ {
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $rs = $this->conn->Execute('show status');
+
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if (!$rs) return 0;
+ $val = 0.0;
+ while (!$rs->EOF) {
+ switch($rs->fields[0]) {
+ case 'Com_insert':
+ $val += $rs->fields[1]; break;
+ case 'Com_delete':
+ $val += $rs->fields[1]; break;
+ case 'Com_update':
+ $val += $rs->fields[1]/2;
+ $rs->Close();
+ return $val;
+ }
+ $rs->MoveNext();
+ }
+
+ $rs->Close();
+
+ return $val;
+ }
+
+ function FindDBHitRatio()
+ {
+ // first find out type of table
+ //$this->conn->debug=1;
+
+ global $ADODB_FETCH_MODE;
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $rs = $this->conn->Execute('show table status');
+
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if (!$rs) return '';
+ $type = strtoupper($rs->fields[1]);
+ $rs->Close();
+ switch($type){
+ case 'MYISAM':
+ case 'ISAM':
+ return $this->DBParameter('MyISAM cache hit ratio').' (MyISAM)';
+ case 'INNODB':
+ return $this->DBParameter('InnoDB cache hit ratio').' (InnoDB)';
+ default:
+ return $type.' not supported';
+ }
+
+ }
+
+ function GetQHitRatio()
+ {
+ //Total number of queries = Qcache_inserts + Qcache_hits + Qcache_not_cached
+ $hits = $this->_DBParameter(array("show status","Qcache_hits"));
+ $total = $this->_DBParameter(array("show status","Qcache_inserts"));
+ $total += $this->_DBParameter(array("show status","Qcache_not_cached"));
+
+ $total += $hits;
+ if ($total) return round(($hits*100)/$total,2);
+ return 0;
+ }
+
+ /*
+ Use session variable to store Hit percentage, because MySQL
+ does not remember last value of SHOW INNODB STATUS hit ratio
+
+ # 1st query to SHOW INNODB STATUS
+ 0.00 reads/s, 0.00 creates/s, 0.00 writes/s
+ Buffer pool hit rate 1000 / 1000
+
+ # 2nd query to SHOW INNODB STATUS
+ 0.00 reads/s, 0.00 creates/s, 0.00 writes/s
+ No buffer pool activity since the last printout
+ */
+ function GetInnoDBHitRatio()
+ {
+ global $ADODB_FETCH_MODE;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $rs = $this->conn->Execute('show innodb status');
+
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_FETCH_MODE = $save;
+
+ if (!$rs || $rs->EOF) return 0;
+ $stat = $rs->fields[0];
+ $rs->Close();
+ $at = strpos($stat,'Buffer pool hit rate');
+ $stat = substr($stat,$at,200);
+ if (preg_match('!Buffer pool hit rate\s*([0-9]*) / ([0-9]*)!',$stat,$arr)) {
+ $val = 100*$arr[1]/$arr[2];
+ $_SESSION['INNODB_HIT_PCT'] = $val;
+ return round($val,2);
+ } else {
+ if (isset($_SESSION['INNODB_HIT_PCT'])) return $_SESSION['INNODB_HIT_PCT'];
+ return 0;
+ }
+ return 0;
+ }
+
+ function GetKeyHitRatio()
+ {
+ $hits = $this->_DBParameter(array("show status","Key_read_requests"));
+ $reqs = $this->_DBParameter(array("show status","Key_reads"));
+ if ($reqs == 0) return 0;
+
+ return round(($hits/($reqs+$hits))*100,2);
+ }
+
+ // start hack
+ var $optimizeTableLow = 'CHECK TABLE %s FAST QUICK';
+ var $optimizeTableHigh = 'OPTIMIZE TABLE %s';
+
+ /**
+ * @see adodb_perf#optimizeTable
+ */
+ function optimizeTable( $table, $mode = ADODB_OPT_LOW)
+ {
+ if ( !is_string( $table)) return false;
+
+ $conn = $this->conn;
+ if ( !$conn) return false;
+
+ $sql = '';
+ switch( $mode) {
+ case ADODB_OPT_LOW : $sql = $this->optimizeTableLow; break;
+ case ADODB_OPT_HIGH : $sql = $this->optimizeTableHigh; break;
+ default :
+ {
+ // May dont use __FUNCTION__ constant for BC (__FUNCTION__ Added in PHP 4.3.0)
+ ADOConnection::outp( sprintf( "<p>%s: '%s' using of undefined mode '%s'</p>", __CLASS__, __FUNCTION__, $mode));
+ return false;
+ }
+ }
+ $sql = sprintf( $sql, $table);
+
+ return $conn->Execute( $sql) !== false;
+ }
+ // end hack
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/perf/perf-oci8.inc.php b/lib/adodb/perf/perf-oci8.inc.php
new file mode 100644
index 0000000..a4bcda6
--- /dev/null
+++ b/lib/adodb/perf/perf-oci8.inc.php
@@ -0,0 +1,509 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Library for basic performance monitoring and tuning
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+class perf_oci8 extends ADODB_perf{
+
+ var $tablesSQL = "select segment_name as \"tablename\", sum(bytes)/1024 as \"size_in_k\",tablespace_name as \"tablespace\",count(*) \"extents\" from sys.user_extents
+ group by segment_name,tablespace_name";
+
+ var $version;
+ var $createTableSQL = "CREATE TABLE adodb_logsql (
+ created date NOT NULL,
+ sql0 varchar(250) NOT NULL,
+ sql1 varchar(4000) NOT NULL,
+ params varchar(4000),
+ tracer varchar(4000),
+ timer decimal(16,6) NOT NULL
+ )";
+
+ var $settings = array(
+ 'Ratios',
+ 'data cache hit ratio' => array('RATIOH',
+ "select round((1-(phy.value / (cur.value + con.value)))*100,2)
+ from v\$sysstat cur, v\$sysstat con, v\$sysstat phy
+ where cur.name = 'db block gets' and
+ con.name = 'consistent gets' and
+ phy.name = 'physical reads'",
+ '=WarnCacheRatio'),
+
+ 'sql cache hit ratio' => array( 'RATIOH',
+ 'select round(100*(sum(pins)-sum(reloads))/sum(pins),2) from v$librarycache',
+ 'increase <i>shared_pool_size</i> if too ratio low'),
+
+ 'datadict cache hit ratio' => array('RATIOH',
+ "select
+ round((1 - (sum(getmisses) / (sum(gets) +
+ sum(getmisses))))*100,2)
+ from v\$rowcache",
+ 'increase <i>shared_pool_size</i> if too ratio low'),
+
+ 'memory sort ratio' => array('RATIOH',
+ "SELECT ROUND((100 * b.VALUE) /DECODE ((a.VALUE + b.VALUE),
+ 0,1,(a.VALUE + b.VALUE)),2)
+FROM v\$sysstat a,
+ v\$sysstat b
+WHERE a.name = 'sorts (disk)'
+AND b.name = 'sorts (memory)'",
+ "% of memory sorts compared to disk sorts - should be over 95%"),
+
+ 'IO',
+ 'data reads' => array('IO',
+ "select value from v\$sysstat where name='physical reads'"),
+
+ 'data writes' => array('IO',
+ "select value from v\$sysstat where name='physical writes'"),
+
+ 'Data Cache',
+ 'data cache buffers' => array( 'DATAC',
+ "select a.value/b.value from v\$parameter a, v\$parameter b
+ where a.name = 'db_cache_size' and b.name= 'db_block_size'",
+ 'Number of cache buffers. Tune <i>db_cache_size</i> if the <i>data cache hit ratio</i> is too low.'),
+ 'data cache blocksize' => array('DATAC',
+ "select value from v\$parameter where name='db_block_size'",
+ '' ),
+ 'Memory Pools',
+ 'data cache size' => array('DATAC',
+ "select value from v\$parameter where name = 'db_cache_size'",
+ 'db_cache_size' ),
+ 'shared pool size' => array('DATAC',
+ "select value from v\$parameter where name = 'shared_pool_size'",
+ 'shared_pool_size, which holds shared sql, stored procedures, dict cache and similar shared structs' ),
+ 'java pool size' => array('DATAJ',
+ "select value from v\$parameter where name = 'java_pool_size'",
+ 'java_pool_size' ),
+ 'large pool buffer size' => array('CACHE',
+ "select value from v\$parameter where name='large_pool_size'",
+ 'this pool is for large mem allocations (not because it is larger than shared pool), for MTS sessions, parallel queries, io buffers (large_pool_size) ' ),
+
+ 'pga buffer size' => array('CACHE',
+ "select value from v\$parameter where name='pga_aggregate_target'",
+ 'program global area is private memory for sorting, and hash and bitmap merges - since oracle 9i (pga_aggregate_target)' ),
+
+
+ 'Connections',
+ 'current connections' => array('SESS',
+ 'select count(*) from sys.v_$session where username is not null',
+ ''),
+ 'max connections' => array( 'SESS',
+ "select value from v\$parameter where name='sessions'",
+ ''),
+
+ 'Memory Utilization',
+ 'data cache utilization ratio' => array('RATIOU',
+ "select round((1-bytes/sgasize)*100, 2)
+ from (select sum(bytes) sgasize from sys.v_\$sgastat) s, sys.v_\$sgastat f
+ where name = 'free memory' and pool = 'shared pool'",
+ 'Percentage of data cache actually in use - should be over 85%'),
+
+ 'shared pool utilization ratio' => array('RATIOU',
+ 'select round((sga.bytes/p.value)*100,2)
+ from v$sgastat sga, v$parameter p
+ where sga.name = \'free memory\' and sga.pool = \'shared pool\'
+ and p.name = \'shared_pool_size\'',
+ 'Percentage of shared pool actually used - too low is bad, too high is worse'),
+
+ 'large pool utilization ratio' => array('RATIOU',
+ "select round((1-bytes/sgasize)*100, 2)
+ from (select sum(bytes) sgasize from sys.v_\$sgastat) s, sys.v_\$sgastat f
+ where name = 'free memory' and pool = 'large pool'",
+ 'Percentage of large_pool actually in use - too low is bad, too high is worse'),
+ 'sort buffer size' => array('CACHE',
+ "select value from v\$parameter where name='sort_area_size'",
+ 'max in-mem sort_area_size (per query), uses memory in pga' ),
+
+ 'pga usage at peak' => array('RATIOU',
+ '=PGA','Mb utilization at peak transactions (requires Oracle 9i+)'),
+ 'Transactions',
+ 'rollback segments' => array('ROLLBACK',
+ "select count(*) from sys.v_\$rollstat",
+ ''),
+
+ 'peak transactions' => array('ROLLBACK',
+ "select max_utilization tx_hwm
+ from sys.v_\$resource_limit
+ where resource_name = 'transactions'",
+ 'Taken from high-water-mark'),
+ 'max transactions' => array('ROLLBACK',
+ "select value from v\$parameter where name = 'transactions'",
+ 'max transactions / rollback segments < 3.5 (or transactions_per_rollback_segment)'),
+ 'Parameters',
+ 'cursor sharing' => array('CURSOR',
+ "select value from v\$parameter where name = 'cursor_sharing'",
+ 'Cursor reuse strategy. Recommended is FORCE (8i+) or SIMILAR (9i+). See <a href=http://www.praetoriate.com/oracle_tips_cursor_sharing.htm>cursor_sharing</a>.'),
+ /*
+ 'cursor reuse' => array('CURSOR',
+ "select count(*) from (select sql_text_wo_constants, count(*)
+ from t1
+ group by sql_text_wo_constants
+having count(*) > 100)",'These are sql statements that should be using bind variables'),*/
+ 'index cache cost' => array('COST',
+ "select value from v\$parameter where name = 'optimizer_index_caching'",
+ '=WarnIndexCost'),
+ 'random page cost' => array('COST',
+ "select value from v\$parameter where name = 'optimizer_index_cost_adj'",
+ '=WarnPageCost'),
+
+ false
+
+ );
+
+
+ function perf_oci8(&$conn)
+ {
+ $savelog = $conn->LogSQL(false);
+ $this->version = $conn->ServerInfo();
+ $conn->LogSQL($savelog);
+ $this->conn =& $conn;
+ }
+
+ function WarnPageCost($val)
+ {
+ if ($val == 100) $s = '<font color=red><b>Too High</b>. </font>';
+ else $s = '';
+
+ return $s.'Recommended is 20-50 for TP, and 50 for data warehouses. Default is 100. See <a href=http://www.dba-oracle.com/oracle_tips_cost_adj.htm>optimizer_index_cost_adj</a>. ';
+ }
+
+ function WarnIndexCost($val)
+ {
+ if ($val == 0) $s = '<font color=red><b>Too Low</b>. </font>';
+ else $s = '';
+
+ return $s.'Percentage of indexed data blocks expected in the cache.
+ Recommended is 20 (fast disk array) to 50 (slower hard disks). Default is 0.
+ See <a href=http://www.dba-oracle.com/oracle_tips_cbo_part1.htm>optimizer_index_caching</a>.';
+ }
+
+ function PGA()
+ {
+ if ($this->version['version'] < 9) return 'Oracle 9i or later required';
+
+ $rs = $this->conn->Execute("select a.mb,a.targ as pga_size_pct,a.pct from
+ (select round(pga_target_for_estimate/1024.0/1024.0,0) Mb,
+ pga_target_factor targ,estd_pga_cache_hit_percentage pct,rownum as r
+ from v\$pga_target_advice) a left join
+ (select round(pga_target_for_estimate/1024.0/1024.0,0) Mb,
+ pga_target_factor targ,estd_pga_cache_hit_percentage pct,rownum as r
+ from v\$pga_target_advice) b on
+ a.r = b.r+1 where
+ b.pct < 100");
+ if (!$rs) return "Only in 9i or later";
+ $rs->Close();
+ if ($rs->EOF) return "PGA could be too big";
+
+ return reset($rs->fields);
+ }
+
+ function Explain($sql,$partial=false)
+ {
+ $savelog = $this->conn->LogSQL(false);
+ $rs =& $this->conn->SelectLimit("select ID FROM PLAN_TABLE");
+ if (!$rs) {
+ echo "<p><b>Missing PLAN_TABLE</b></p>
+<pre>
+CREATE TABLE PLAN_TABLE (
+ STATEMENT_ID VARCHAR2(30),
+ TIMESTAMP DATE,
+ REMARKS VARCHAR2(80),
+ OPERATION VARCHAR2(30),
+ OPTIONS VARCHAR2(30),
+ OBJECT_NODE VARCHAR2(128),
+ OBJECT_OWNER VARCHAR2(30),
+ OBJECT_NAME VARCHAR2(30),
+ OBJECT_INSTANCE NUMBER(38),
+ OBJECT_TYPE VARCHAR2(30),
+ OPTIMIZER VARCHAR2(255),
+ SEARCH_COLUMNS NUMBER,
+ ID NUMBER(38),
+ PARENT_ID NUMBER(38),
+ POSITION NUMBER(38),
+ COST NUMBER(38),
+ CARDINALITY NUMBER(38),
+ BYTES NUMBER(38),
+ OTHER_TAG VARCHAR2(255),
+ PARTITION_START VARCHAR2(255),
+ PARTITION_STOP VARCHAR2(255),
+ PARTITION_ID NUMBER(38),
+ OTHER LONG,
+ DISTRIBUTION VARCHAR2(30)
+);
+</pre>";
+ return false;
+ }
+
+ $rs->Close();
+ // $this->conn->debug=1;
+
+ if ($partial) {
+ $sqlq = $this->conn->qstr($sql.'%');
+ $arr = $this->conn->GetArray("select distinct distinct sql1 from adodb_logsql where sql1 like $sqlq");
+ if ($arr) {
+ foreach($arr as $row) {
+ $sql = reset($row);
+ if (crc32($sql) == $partial) break;
+ }
+ }
+ }
+
+ $s = "<p><b>Explain</b>: ".htmlspecialchars($sql)."</p>";
+
+ $this->conn->BeginTrans();
+ $id = "ADODB ".microtime();
+
+ $rs =& $this->conn->Execute("EXPLAIN PLAN SET STATEMENT_ID='$id' FOR $sql");
+ $m = $this->conn->ErrorMsg();
+ if ($m) {
+ $this->conn->RollbackTrans();
+ $this->conn->LogSQL($savelog);
+ $s .= "<p>$m</p>";
+ return $s;
+ }
+ $rs =& $this->conn->Execute("
+ select
+ '<pre>'||lpad('--', (level-1)*2,'-') || trim(operation) || ' ' || trim(options)||'</pre>' as Operation,
+ object_name,COST,CARDINALITY,bytes
+ FROM plan_table
+START WITH id = 0 and STATEMENT_ID='$id'
+CONNECT BY prior id=parent_id and statement_id='$id'");
+
+ $s .= rs2html($rs,false,false,false,false);
+ $this->conn->RollbackTrans();
+ $this->conn->LogSQL($savelog);
+ $s .= $this->Tracer($sql,$partial);
+ return $s;
+ }
+
+
+ function CheckMemory()
+ {
+ if ($this->version['version'] < 9) return 'Oracle 9i or later required';
+
+ $rs =& $this->conn->Execute("
+select a.size_for_estimate as cache_mb_estimate,
+ case when a.size_factor=1 then
+ '&lt;&lt;= current'
+ when a.estd_physical_read_factor-b.estd_physical_read_factor > 0 and a.estd_physical_read_factor<1 then
+ '- BETTER - '
+ else ' ' end as currsize,
+ a.estd_physical_read_factor-b.estd_physical_read_factor as best_when_0
+ from (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r from v\$db_cache_advice) a ,
+ (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r from v\$db_cache_advice) b where a.r = b.r-1");
+ if (!$rs) return false;
+
+ /*
+ The v$db_cache_advice utility show the marginal changes in physical data block reads for different sizes of db_cache_size
+ */
+ $s = "<h3>Data Cache Estimate</h3>";
+ if ($rs->EOF) {
+ $s .= "<p>Cache that is 50% of current size is still too big</p>";
+ } else {
+ $s .= "Ideal size of Data Cache is when \"best_when_0\" changes from a positive number and becomes zero.";
+ $s .= rs2html($rs,false,false,false,false);
+ }
+ return $s;
+ }
+
+ /*
+ Generate html for suspicious/expensive sql
+ */
+ function tohtml(&$rs,$type)
+ {
+ $o1 = $rs->FetchField(0);
+ $o2 = $rs->FetchField(1);
+ $o3 = $rs->FetchField(2);
+ if ($rs->EOF) return '<p>None found</p>';
+ $check = '';
+ $sql = '';
+ $s = "\n\n<table border=1 bgcolor=white><tr><td><b>".$o1->name.'</b></td><td><b>'.$o2->name.'</b></td><td><b>'.$o3->name.'</b></td></tr>';
+ while (!$rs->EOF) {
+ if ($check != $rs->fields[0].'::'.$rs->fields[1]) {
+ if ($check) {
+ $carr = explode('::',$check);
+ $prefix = "<a href=\"?$type=1&sql=".rawurlencode($sql).'&x#explain">';
+ $suffix = '</a>';
+ if (strlen($prefix)>2000) {
+ $prefix = '';
+ $suffix = '';
+ }
+
+ $s .= "\n<tr><td align=right>".$carr[0].'</td><td align=right>'.$carr[1].'</td><td>'.$prefix.$sql.$suffix.'</td></tr>';
+ }
+ $sql = $rs->fields[2];
+ $check = $rs->fields[0].'::'.$rs->fields[1];
+ } else
+ $sql .= $rs->fields[2];
+ if (substr($sql,strlen($sql)-1) == "\0") $sql = substr($sql,0,strlen($sql)-1);
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $carr = explode('::',$check);
+ $prefix = "<a target=".rand()." href=\"?&hidem=1&$type=1&sql=".rawurlencode($sql).'&x#explain">';
+ $suffix = '</a>';
+ if (strlen($prefix)>2000) {
+ $prefix = '';
+ $suffix = '';
+ }
+ $s .= "\n<tr><td align=right>".$carr[0].'</td><td align=right>'.$carr[1].'</td><td>'.$prefix.$sql.$suffix.'</td></tr>';
+
+ return $s."</table>\n\n";
+ }
+
+ // code thanks to Ixora.
+ // http://www.ixora.com.au/scripts/query_opt.htm
+ // requires oracle 8.1.7 or later
+ function SuspiciousSQL($numsql=10)
+ {
+ $sql = "
+select
+ substr(to_char(s.pct, '99.00'), 2) || '%' load,
+ s.executions executes,
+ p.sql_text
+from
+ (
+ select
+ address,
+ buffer_gets,
+ executions,
+ pct,
+ rank() over (order by buffer_gets desc) ranking
+ from
+ (
+ select
+ address,
+ buffer_gets,
+ executions,
+ 100 * ratio_to_report(buffer_gets) over () pct
+ from
+ sys.v_\$sql
+ where
+ command_type != 47 and module != 'T.O.A.D.'
+ )
+ where
+ buffer_gets > 50 * executions
+ ) s,
+ sys.v_\$sqltext p
+where
+ s.ranking <= $numsql and
+ p.address = s.address
+order by
+ 1 desc, s.address, p.piece";
+
+ global $ADODB_CACHE_MODE;
+ if (isset($_GET['expsixora']) && isset($_GET['sql'])) {
+ $partial = empty($_GET['part']);
+ echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
+ }
+
+ if (isset($_GET['sql'])) return $this->_SuspiciousSQL($numsql);
+
+ $s = '';
+ $s .= $this->_SuspiciousSQL($numsql);
+ $s .= '<p>';
+
+ $save = $ADODB_CACHE_MODE;
+ $ADODB_CACHE_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $savelog = $this->conn->LogSQL(false);
+ $rs =& $this->conn->SelectLimit($sql);
+ $this->conn->LogSQL($savelog);
+
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_CACHE_MODE = $save;
+ if ($rs) {
+ $s .= "\n<h3>Ixora Suspicious SQL</h3>";
+ $s .= $this->tohtml($rs,'expsixora');
+ }
+
+ return $s;
+ }
+
+ // code thanks to Ixora.
+ // http://www.ixora.com.au/scripts/query_opt.htm
+ // requires oracle 8.1.7 or later
+ function ExpensiveSQL($numsql = 10)
+ {
+ $sql = "
+select
+ substr(to_char(s.pct, '99.00'), 2) || '%' load,
+ s.executions executes,
+ p.sql_text
+from
+ (
+ select
+ address,
+ disk_reads,
+ executions,
+ pct,
+ rank() over (order by disk_reads desc) ranking
+ from
+ (
+ select
+ address,
+ disk_reads,
+ executions,
+ 100 * ratio_to_report(disk_reads) over () pct
+ from
+ sys.v_\$sql
+ where
+ command_type != 47 and module != 'T.O.A.D.'
+ )
+ where
+ disk_reads > 50 * executions
+ ) s,
+ sys.v_\$sqltext p
+where
+ s.ranking <= $numsql and
+ p.address = s.address
+order by
+ 1 desc, s.address, p.piece
+";
+ global $ADODB_CACHE_MODE;
+ if (isset($_GET['expeixora']) && isset($_GET['sql'])) {
+ $partial = empty($_GET['part']);
+ echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
+ }
+ if (isset($_GET['sql'])) {
+ $var = $this->_ExpensiveSQL($numsql);
+ return $var;
+ }
+
+ $s = '';
+ $s .= $this->_ExpensiveSQL($numsql);
+ $s .= '<p>';
+ $save = $ADODB_CACHE_MODE;
+ $ADODB_CACHE_MODE = ADODB_FETCH_NUM;
+ if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
+
+ $savelog = $this->conn->LogSQL(false);
+ $rs =& $this->conn->Execute($sql);
+ $this->conn->LogSQL($savelog);
+
+ if (isset($savem)) $this->conn->SetFetchMode($savem);
+ $ADODB_CACHE_MODE = $save;
+
+ if ($rs) {
+ $s .= "\n<h3>Ixora Expensive SQL</h3>";
+ $s .= $this->tohtml($rs,'expeixora');
+ }
+
+ return $s;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/perf/perf-postgres.inc.php b/lib/adodb/perf/perf-postgres.inc.php
new file mode 100644
index 0000000..da41ebe
--- /dev/null
+++ b/lib/adodb/perf/perf-postgres.inc.php
@@ -0,0 +1,124 @@
+<?php
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence. See License.txt.
+ Set tabs to 4 for best viewing.
+
+ Latest version is available at http://adodb.sourceforge.net
+
+ Library for basic performance monitoring and tuning
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_DIR')) die();
+
+/*
+ Notice that PostgreSQL has no sql query cache
+*/
+class perf_postgres extends adodb_perf{
+
+ var $tablesSQL =
+ "select a.relname as tablename,(a.relpages+CASE WHEN b.relpages is null THEN 0 ELSE b.relpages END+CASE WHEN c.relpages is null THEN 0 ELSE c.relpages END)*8 as size_in_K,a.relfilenode as \"OID\" from pg_class a left join pg_class b
+ on b.relname = 'pg_toast_'||trim(a.relfilenode)
+ left join pg_class c on c.relname = 'pg_toast_'||trim(a.relfilenode)||'_index'
+ where a.relname in (select tablename from pg_tables where tablename not like 'pg_%')";
+
+ var $createTableSQL = "CREATE TABLE adodb_logsql (
+ created timestamp NOT NULL,
+ sql0 varchar(250) NOT NULL,
+ sql1 text NOT NULL,
+ params text NOT NULL,
+ tracer text NOT NULL,
+ timer decimal(16,6) NOT NULL
+ )";
+
+ var $settings = array(
+ 'Ratios',
+ 'statistics collector' => array('RATIO',
+ "select case when count(*)=3 then 'TRUE' else 'FALSE' end from pg_settings where (name='stats_block_level' or name='stats_row_level' or name='stats_start_collector') and setting='on' ",
+ 'Value must be TRUE to enable hit ratio statistics (<i>stats_start_collector</i>,<i>stats_row_level</i> and <i>stats_block_level</i> must be set to true in postgresql.conf)'),
+ 'data cache hit ratio' => array('RATIO',
+ "select case when blks_hit=0 then 0 else round( ((1-blks_read::float/blks_hit)*100)::numeric, 2) end from pg_stat_database where datname='\$DATABASE'",
+ '=WarnCacheRatio'),
+ 'IO',
+ 'data reads' => array('IO',
+ 'select sum(heap_blks_read+toast_blks_read) from pg_statio_user_tables',
+ ),
+ 'data writes' => array('IO',
+ 'select round((sum(n_tup_ins/4.0+n_tup_upd/8.0+n_tup_del/4.0)/16)::numeric,2) from pg_stat_user_tables',
+ 'Count of inserts/updates/deletes * coef'),
+
+ 'Data Cache',
+ 'data cache buffers' => array('DATAC',
+ "select setting from pg_settings where name='shared_buffers'",
+ 'Number of cache buffers. <a href=http://www.varlena.com/GeneralBits/Tidbits/perf.html#basic>Tuning</a>'),
+ 'cache blocksize' => array('DATAC',
+ 'select 8192',
+ '(estimate)' ),
+ 'data cache size' => array( 'DATAC',
+ "select setting::integer*8192 from pg_settings where name='shared_buffers'",
+ '' ),
+ 'operating system cache size' => array( 'DATA',
+ "select setting::integer*8192 from pg_settings where name='effective_cache_size'",
+ '(effective cache size)' ),
+ 'Memory Usage',
+ # Postgres 7.5 changelog: Rename server parameters SortMem and VacuumMem to work_mem and maintenance_work_mem;
+ 'sort/work buffer size' => array('CACHE',
+ "select setting::integer*1024 from pg_settings where name='sort_mem' or name = 'work_mem' order by name",
+ 'Size of sort buffer (per query)' ),
+ 'Connections',
+ 'current connections' => array('SESS',
+ 'select count(*) from pg_stat_activity',
+ ''),
+ 'max connections' => array('SESS',
+ "select setting from pg_settings where name='max_connections'",
+ ''),
+ 'Parameters',
+ 'rollback buffers' => array('COST',
+ "select setting from pg_settings where name='wal_buffers'",
+ 'WAL buffers'),
+ 'random page cost' => array('COST',
+ "select setting from pg_settings where name='random_page_cost'",
+ 'Cost of doing a seek (default=4). See <a href=http://www.varlena.com/GeneralBits/Tidbits/perf.html#less>random_page_cost</a>'),
+ false
+ );
+
+ function perf_postgres(&$conn)
+ {
+ $this->conn =& $conn;
+ }
+
+ function Explain($sql,$partial=false)
+ {
+ $save = $this->conn->LogSQL(false);
+
+ if ($partial) {
+ $sqlq = $this->conn->qstr($sql.'%');
+ $arr = $this->conn->GetArray("select distinct distinct sql1 from adodb_logsql where sql1 like $sqlq");
+ if ($arr) {
+ foreach($arr as $row) {
+ $sql = reset($row);
+ if (crc32($sql) == $partial) break;
+ }
+ }
+ }
+ $sql = str_replace('?',"''",$sql);
+ $s = '<p><b>Explain</b>: '.htmlspecialchars($sql).'</p>';
+ $rs = $this->conn->Execute('EXPLAIN '.$sql);
+ $this->conn->LogSQL($save);
+ $s .= '<pre>';
+ if ($rs)
+ while (!$rs->EOF) {
+ $s .= reset($rs->fields)."\n";
+ $rs->MoveNext();
+ }
+ $s .= '</pre>';
+ $s .= $this->Tracer($sql,$partial);
+ return $s;
+ }
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/pivottable.inc.php b/lib/adodb/pivottable.inc.php
new file mode 100644
index 0000000..0e0e7b1
--- /dev/null
+++ b/lib/adodb/pivottable.inc.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * @version V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+*/
+
+/*
+ * Concept from daniel.lucazeau@ajornet.com.
+ *
+ * @param db Adodb database connection
+ * @param tables List of tables to join
+ * @rowfields List of fields to display on each row
+ * @colfield Pivot field to slice and display in columns, if we want to calculate
+ * ranges, we pass in an array (see example2)
+ * @where Where clause. Optional.
+ * @aggfield This is the field to sum. Optional.
+ * Since 2.3.1, if you can use your own aggregate function
+ * instead of SUM, eg. $aggfield = 'fieldname'; $aggfn = 'AVG';
+ * @sumlabel Prefix to display in sum columns. Optional.
+ * @aggfn Aggregate function to use (could be AVG, SUM, COUNT)
+ * @showcount Show count of records
+ *
+ * @returns Sql generated
+ */
+
+ function PivotTableSQL(&$db,$tables,$rowfields,$colfield, $where=false,
+ $aggfield = false,$sumlabel='Sum ',$aggfn ='SUM', $showcount = true)
+ {
+ if ($aggfield) $hidecnt = true;
+ else $hidecnt = false;
+
+ $iif = strpos($db->databaseType,'access') !== false;
+ // note - vfp 6 still doesn' work even with IIF enabled || $db->databaseType == 'vfp';
+
+ //$hidecnt = false;
+
+ if ($where) $where = "\nWHERE $where";
+ if (!is_array($colfield)) $colarr = $db->GetCol("select distinct $colfield from $tables $where order by 1");
+ if (!$aggfield) $hidecnt = false;
+
+ $sel = "$rowfields, ";
+ if (is_array($colfield)) {
+ foreach ($colfield as $k => $v) {
+ $k = trim($k);
+ if (!$hidecnt) {
+ $sel .= $iif ?
+ "\n\t$aggfn(IIF($v,1,0)) AS \"$k\", "
+ :
+ "\n\t$aggfn(CASE WHEN $v THEN 1 ELSE 0 END) AS \"$k\", ";
+ }
+ if ($aggfield) {
+ $sel .= $iif ?
+ "\n\t$aggfn(IIF($v,$aggfield,0)) AS \"$sumlabel$k\", "
+ :
+ "\n\t$aggfn(CASE WHEN $v THEN $aggfield ELSE 0 END) AS \"$sumlabel$k\", ";
+ }
+ }
+ } else {
+ foreach ($colarr as $v) {
+ if (!is_numeric($v)) $vq = $db->qstr($v);
+ else $vq = $v;
+ $v = trim($v);
+ if (strlen($v) == 0 ) $v = 'null';
+ if (!$hidecnt) {
+ $sel .= $iif ?
+ "\n\t$aggfn(IIF($colfield=$vq,1,0)) AS \"$v\", "
+ :
+ "\n\t$aggfn(CASE WHEN $colfield=$vq THEN 1 ELSE 0 END) AS \"$v\", ";
+ }
+ if ($aggfield) {
+ if ($hidecnt) $label = $v;
+ else $label = "{$v}_$aggfield";
+ $sel .= $iif ?
+ "\n\t$aggfn(IIF($colfield=$vq,$aggfield,0)) AS \"$label\", "
+ :
+ "\n\t$aggfn(CASE WHEN $colfield=$vq THEN $aggfield ELSE 0 END) AS \"$label\", ";
+ }
+ }
+ }
+ if ($aggfield && $aggfield != '1'){
+ $agg = "$aggfn($aggfield)";
+ $sel .= "\n\t$agg as \"$sumlabel$aggfield\", ";
+ }
+
+ if ($showcount)
+ $sel .= "\n\tSUM(1) as Total";
+ else
+ $sel = substr($sel,0,strlen($sel)-2);
+
+
+ // Strip aliases
+ $rowfields = preg_replace('/ AS (\w+)/i', '', $rowfields);
+
+ $sql = "SELECT $sel \nFROM $tables $where \nGROUP BY $rowfields";
+
+ return $sql;
+ }
+
+/* EXAMPLES USING MS NORTHWIND DATABASE */
+if (0) {
+
+# example1
+#
+# Query the main "product" table
+# Set the rows to CompanyName and QuantityPerUnit
+# and the columns to the Categories
+# and define the joins to link to lookup tables
+# "categories" and "suppliers"
+#
+
+ $sql = PivotTableSQL(
+ $gDB, # adodb connection
+ 'products p ,categories c ,suppliers s', # tables
+ 'CompanyName,QuantityPerUnit', # row fields
+ 'CategoryName', # column fields
+ 'p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID' # joins/where
+);
+ print "<pre>$sql";
+ $rs = $gDB->Execute($sql);
+ rs2html($rs);
+
+/*
+Generated SQL:
+
+SELECT CompanyName,QuantityPerUnit,
+ SUM(CASE WHEN CategoryName='Beverages' THEN 1 ELSE 0 END) AS "Beverages",
+ SUM(CASE WHEN CategoryName='Condiments' THEN 1 ELSE 0 END) AS "Condiments",
+ SUM(CASE WHEN CategoryName='Confections' THEN 1 ELSE 0 END) AS "Confections",
+ SUM(CASE WHEN CategoryName='Dairy Products' THEN 1 ELSE 0 END) AS "Dairy Products",
+ SUM(CASE WHEN CategoryName='Grains/Cereals' THEN 1 ELSE 0 END) AS "Grains/Cereals",
+ SUM(CASE WHEN CategoryName='Meat/Poultry' THEN 1 ELSE 0 END) AS "Meat/Poultry",
+ SUM(CASE WHEN CategoryName='Produce' THEN 1 ELSE 0 END) AS "Produce",
+ SUM(CASE WHEN CategoryName='Seafood' THEN 1 ELSE 0 END) AS "Seafood",
+ SUM(1) as Total
+FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID
+GROUP BY CompanyName,QuantityPerUnit
+*/
+//=====================================================================
+
+# example2
+#
+# Query the main "product" table
+# Set the rows to CompanyName and QuantityPerUnit
+# and the columns to the UnitsInStock for diiferent ranges
+# and define the joins to link to lookup tables
+# "categories" and "suppliers"
+#
+ $sql = PivotTableSQL(
+ $gDB, # adodb connection
+ 'products p ,categories c ,suppliers s', # tables
+ 'CompanyName,QuantityPerUnit', # row fields
+ # column ranges
+array(
+' 0 ' => 'UnitsInStock <= 0',
+"1 to 5" => '0 < UnitsInStock and UnitsInStock <= 5',
+"6 to 10" => '5 < UnitsInStock and UnitsInStock <= 10',
+"11 to 15" => '10 < UnitsInStock and UnitsInStock <= 15',
+"16+" =>'15 < UnitsInStock'
+),
+ ' p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID', # joins/where
+ 'UnitsInStock', # sum this field
+ 'Sum' # sum label prefix
+);
+ print "<pre>$sql";
+ $rs = $gDB->Execute($sql);
+ rs2html($rs);
+ /*
+ Generated SQL:
+
+SELECT CompanyName,QuantityPerUnit,
+ SUM(CASE WHEN UnitsInStock <= 0 THEN UnitsInStock ELSE 0 END) AS "Sum 0 ",
+ SUM(CASE WHEN 0 < UnitsInStock and UnitsInStock <= 5 THEN UnitsInStock ELSE 0 END) AS "Sum 1 to 5",
+ SUM(CASE WHEN 5 < UnitsInStock and UnitsInStock <= 10 THEN UnitsInStock ELSE 0 END) AS "Sum 6 to 10",
+ SUM(CASE WHEN 10 < UnitsInStock and UnitsInStock <= 15 THEN UnitsInStock ELSE 0 END) AS "Sum 11 to 15",
+ SUM(CASE WHEN 15 < UnitsInStock THEN UnitsInStock ELSE 0 END) AS "Sum 16+",
+ SUM(UnitsInStock) AS "Sum UnitsInStock",
+ SUM(1) as Total
+FROM products p ,categories c ,suppliers s WHERE p.CategoryID = c.CategoryID and s.SupplierID= p.SupplierID
+GROUP BY CompanyName,QuantityPerUnit
+ */
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/rsfilter.inc.php b/lib/adodb/rsfilter.inc.php
new file mode 100644
index 0000000..29662a2
--- /dev/null
+++ b/lib/adodb/rsfilter.inc.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * @version V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Set tabs to 4 for best viewing.
+ *
+ * Latest version is available at http://php.weblogs.com
+ *
+ * Requires PHP4.01pl2 or later because it uses include_once
+*/
+
+/*
+ Filter all fields and all rows in a recordset and returns the
+ processed recordset. We scroll to the beginning of the new recordset
+ after processing.
+
+ We pass a recordset and function name to RSFilter($rs,'rowfunc');
+ and the function will be called multiple times, once
+ for each row in the recordset. The function will be passed
+ an array containing one row repeatedly.
+
+ Example:
+
+ // ucwords() every element in the recordset
+ function do_ucwords(&$arr,$rs)
+ {
+ foreach($arr as $k => $v) {
+ $arr[$k] = ucwords($v);
+ }
+ }
+ $rs = RSFilter($rs,'do_ucwords');
+ */
+function &RSFilter($rs,$fn)
+{
+ if ($rs->databaseType != 'array') {
+ if (!$rs->connection) return false;
+
+ $rs = &$rs->connection->_rs2rs($rs);
+ }
+ $rows = $rs->RecordCount();
+ for ($i=0; $i < $rows; $i++) {
+ if (is_array ($fn)) {
+ $obj = $fn[0];
+ $method = $fn[1];
+ $obj->$method ($rs->_array[$i],$rs);
+ } else {
+ $fn($rs->_array[$i],$rs);
+ }
+
+ }
+ if (!$rs->EOF) {
+ $rs->_currentRow = 0;
+ $rs->fields = $rs->_array[0];
+ }
+
+ return $rs;
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/server.php b/lib/adodb/server.php
new file mode 100644
index 0000000..a39f9c7
--- /dev/null
+++ b/lib/adodb/server.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @version V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ */
+
+/* Documentation on usage is at http://php.weblogs.com/adodb_csv
+ *
+ * Legal query string parameters:
+ *
+ * sql = holds sql string
+ * nrows = number of rows to return
+ * offset = skip offset rows of data
+ * fetch = $ADODB_FETCH_MODE
+ *
+ * example:
+ *
+ * http://localhost/php/server.php?select+*+from+table&nrows=10&offset=2
+ */
+
+
+/*
+ * Define the IP address you want to accept requests from
+ * as a security measure. If blank we accept anyone promisciously!
+ */
+$ACCEPTIP = '127.0.0.1';
+
+/*
+ * Connection parameters
+ */
+$driver = 'mysql';
+$host = 'localhost'; // DSN for odbc
+$uid = 'root';
+$pwd = 'garbase-it-is';
+$database = 'test';
+
+/*============================ DO NOT MODIFY BELOW HERE =================================*/
+// $sep must match csv2rs() in adodb.inc.php
+$sep = ' :::: ';
+
+include('./adodb.inc.php');
+include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+
+function err($s)
+{
+ die('**** '.$s.' ');
+}
+
+// undo stupid magic quotes
+function undomq(&$m)
+{
+ if (get_magic_quotes_gpc()) {
+ // undo the damage
+ $m = str_replace('\\\\','\\',$m);
+ $m = str_replace('\"','"',$m);
+ $m = str_replace('\\\'','\'',$m);
+
+ }
+ return $m;
+}
+
+///////////////////////////////////////// DEFINITIONS
+
+
+$remote = $_SERVER["REMOTE_ADDR"];
+
+
+if (!empty($ACCEPTIP))
+ if ($remote != '127.0.0.1' && $remote != $ACCEPTIP)
+ err("Unauthorised client: '$remote'");
+
+
+if (empty($_REQUEST['sql'])) err('No SQL');
+
+
+$conn = &ADONewConnection($driver);
+
+if (!$conn->Connect($host,$uid,$pwd,$database)) err($conn->ErrorNo(). $sep . $conn->ErrorMsg());
+$sql = undomq($_REQUEST['sql']);
+
+if (isset($_REQUEST['fetch']))
+ $ADODB_FETCH_MODE = $_REQUEST['fetch'];
+
+if (isset($_REQUEST['nrows'])) {
+ $nrows = $_REQUEST['nrows'];
+ $offset = isset($_REQUEST['offset']) ? $_REQUEST['offset'] : -1;
+ $rs = $conn->SelectLimit($sql,$nrows,$offset);
+} else
+ $rs = $conn->Execute($sql);
+if ($rs){
+ //$rs->timeToLive = 1;
+ echo _rs2serialize($rs,$conn,$sql);
+ $rs->Close();
+} else
+ err($conn->ErrorNo(). $sep .$conn->ErrorMsg());
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-compress-bzip2.php b/lib/adodb/session/adodb-compress-bzip2.php
new file mode 100644
index 0000000..79c3823
--- /dev/null
+++ b/lib/adodb/session/adodb-compress-bzip2.php
@@ -0,0 +1,118 @@
+<?php
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+*/
+
+if (!function_exists('bzcompress')) {
+ trigger_error('bzip2 functions are not available', E_USER_ERROR);
+ return 0;
+}
+
+/*
+*/
+class ADODB_Compress_Bzip2 {
+ /**
+ */
+ var $_block_size = null;
+
+ /**
+ */
+ var $_work_level = null;
+
+ /**
+ */
+ var $_min_length = 1;
+
+ /**
+ */
+ function getBlockSize() {
+ return $this->_block_size;
+ }
+
+ /**
+ */
+ function setBlockSize($block_size) {
+ assert('$block_size >= 1');
+ assert('$block_size <= 9');
+ $this->_block_size = (int) $block_size;
+ }
+
+ /**
+ */
+ function getWorkLevel() {
+ return $this->_work_level;
+ }
+
+ /**
+ */
+ function setWorkLevel($work_level) {
+ assert('$work_level >= 0');
+ assert('$work_level <= 250');
+ $this->_work_level = (int) $work_level;
+ }
+
+ /**
+ */
+ function getMinLength() {
+ return $this->_min_length;
+ }
+
+ /**
+ */
+ function setMinLength($min_length) {
+ assert('$min_length >= 0');
+ $this->_min_length = (int) $min_length;
+ }
+
+ /**
+ */
+ function ADODB_Compress_Bzip2($block_size = null, $work_level = null, $min_length = null) {
+ if (!is_null($block_size)) {
+ $this->setBlockSize($block_size);
+ }
+
+ if (!is_null($work_level)) {
+ $this->setWorkLevel($work_level);
+ }
+
+ if (!is_null($min_length)) {
+ $this->setMinLength($min_length);
+ }
+ }
+
+ /**
+ */
+ function write($data, $key) {
+ if (strlen($data) < $this->_min_length) {
+ return $data;
+ }
+
+ if (!is_null($this->_block_size)) {
+ if (!is_null($this->_work_level)) {
+ return bzcompress($data, $this->_block_size, $this->_work_level);
+ } else {
+ return bzcompress($data, $this->_block_size);
+ }
+ }
+
+ return bzcompress($data);
+ }
+
+ /**
+ */
+ function read($data, $key) {
+ return $data ? bzdecompress($data) : $data;
+ }
+
+}
+
+return 1;
+
+?>
diff --git a/lib/adodb/session/adodb-compress-gzip.php b/lib/adodb/session/adodb-compress-gzip.php
new file mode 100644
index 0000000..da8d3d4
--- /dev/null
+++ b/lib/adodb/session/adodb-compress-gzip.php
@@ -0,0 +1,93 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+*/
+
+if (!function_exists('gzcompress')) {
+ trigger_error('gzip functions are not available', E_USER_ERROR);
+ return 0;
+}
+
+/*
+*/
+class ADODB_Compress_Gzip {
+ /**
+ */
+ var $_level = null;
+
+ /**
+ */
+ var $_min_length = 1;
+
+ /**
+ */
+ function getLevel() {
+ return $this->_level;
+ }
+
+ /**
+ */
+ function setLevel($level) {
+ assert('$level >= 0');
+ assert('$level <= 9');
+ $this->_level = (int) $level;
+ }
+
+ /**
+ */
+ function getMinLength() {
+ return $this->_min_length;
+ }
+
+ /**
+ */
+ function setMinLength($min_length) {
+ assert('$min_length >= 0');
+ $this->_min_length = (int) $min_length;
+ }
+
+ /**
+ */
+ function ADODB_Compress_Gzip($level = null, $min_length = null) {
+ if (!is_null($level)) {
+ $this->setLevel($level);
+ }
+
+ if (!is_null($min_length)) {
+ $this->setMinLength($min_length);
+ }
+ }
+
+ /**
+ */
+ function write($data, $key) {
+ if (strlen($data) < $this->_min_length) {
+ return $data;
+ }
+
+ if (!is_null($this->_level)) {
+ return gzcompress($data, $this->_level);
+ } else {
+ return gzcompress($data);
+ }
+ }
+
+ /**
+ */
+ function read($data, $key) {
+ return $data ? gzuncompress($data) : $data;
+ }
+
+}
+
+return 1;
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-cryptsession.php b/lib/adodb/session/adodb-cryptsession.php
new file mode 100644
index 0000000..ddf619d
--- /dev/null
+++ b/lib/adodb/session/adodb-cryptsession.php
@@ -0,0 +1,27 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+*/
+
+/*
+
+This file is provided for backwards compatibility purposes
+
+*/
+
+if (!defined('ADODB_SESSION')) {
+ require_once dirname(__FILE__) . '/adodb-session.php';
+}
+
+require_once ADODB_SESSION . '/adodb-encrypt-md5.php';
+
+ADODB_Session::filter(new ADODB_Encrypt_MD5());
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-cryptsession2.php b/lib/adodb/session/adodb-cryptsession2.php
new file mode 100644
index 0000000..6334eaf
--- /dev/null
+++ b/lib/adodb/session/adodb-cryptsession2.php
@@ -0,0 +1,27 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+*/
+
+/*
+
+This file is provided for backwards compatibility purposes
+
+*/
+
+if (!defined('ADODB_SESSION')) {
+ require_once dirname(__FILE__) . '/adodb-session2.php';
+}
+
+require_once ADODB_SESSION . '/adodb-encrypt-md5.php';
+
+ADODB_Session::filter(new ADODB_Encrypt_MD5());
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-encrypt-mcrypt.php b/lib/adodb/session/adodb-encrypt-mcrypt.php
new file mode 100644
index 0000000..a047579
--- /dev/null
+++ b/lib/adodb/session/adodb-encrypt-mcrypt.php
@@ -0,0 +1,109 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+*/
+
+if (!function_exists('mcrypt_encrypt')) {
+ trigger_error('Mcrypt functions are not available', E_USER_ERROR);
+ return 0;
+}
+
+/**
+ */
+class ADODB_Encrypt_MCrypt {
+ /**
+ */
+ var $_cipher;
+
+ /**
+ */
+ var $_mode;
+
+ /**
+ */
+ var $_source;
+
+ /**
+ */
+ function getCipher() {
+ return $this->_cipher;
+ }
+
+ /**
+ */
+ function setCipher($cipher) {
+ $this->_cipher = $cipher;
+ }
+
+ /**
+ */
+ function getMode() {
+ return $this->_mode;
+ }
+
+ /**
+ */
+ function setMode($mode) {
+ $this->_mode = $mode;
+ }
+
+ /**
+ */
+ function getSource() {
+ return $this->_source;
+ }
+
+ /**
+ */
+ function setSource($source) {
+ $this->_source = $source;
+ }
+
+ /**
+ */
+ function ADODB_Encrypt_MCrypt($cipher = null, $mode = null, $source = null) {
+ if (!$cipher) {
+ $cipher = MCRYPT_RIJNDAEL_256;
+ }
+ if (!$mode) {
+ $mode = MCRYPT_MODE_ECB;
+ }
+ if (!$source) {
+ $source = MCRYPT_RAND;
+ }
+
+ $this->_cipher = $cipher;
+ $this->_mode = $mode;
+ $this->_source = $source;
+ }
+
+ /**
+ */
+ function write($data, $key) {
+ $iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode);
+ $iv = mcrypt_create_iv($iv_size, $this->_source);
+ return mcrypt_encrypt($this->_cipher, $key, $data, $this->_mode, $iv);
+ }
+
+ /**
+ */
+ function read($data, $key) {
+ $iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode);
+ $iv = mcrypt_create_iv($iv_size, $this->_source);
+ $rv = mcrypt_decrypt($this->_cipher, $key, $data, $this->_mode, $iv);
+ return rtrim($rv, "\0");
+ }
+
+}
+
+return 1;
+
+?>
diff --git a/lib/adodb/session/adodb-encrypt-md5.php b/lib/adodb/session/adodb-encrypt-md5.php
new file mode 100644
index 0000000..24caa66
--- /dev/null
+++ b/lib/adodb/session/adodb-encrypt-md5.php
@@ -0,0 +1,39 @@
+<?php
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+*/
+
+// security - hide paths
+if (!defined('ADODB_SESSION')) die();
+
+include_once ADODB_SESSION . '/crypt.inc.php';
+
+/**
+ */
+class ADODB_Encrypt_MD5 {
+ /**
+ */
+ function write($data, $key) {
+ $md5crypt =& new MD5Crypt();
+ return $md5crypt->encrypt($data, $key);
+ }
+
+ /**
+ */
+ function read($data, $key) {
+ $md5crypt =& new MD5Crypt();
+ return $md5crypt->decrypt($data, $key);
+ }
+
+}
+
+return 1;
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-encrypt-secret.php b/lib/adodb/session/adodb-encrypt-secret.php
new file mode 100644
index 0000000..cc7e2fb
--- /dev/null
+++ b/lib/adodb/session/adodb-encrypt-secret.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+*/
+
+@define('HORDE_BASE', dirname(dirname(dirname(__FILE__))) . '/horde');
+
+if (!is_dir(HORDE_BASE)) {
+ trigger_error(sprintf('Directory not found: \'%s\'', HORDE_BASE), E_USER_ERROR);
+ return 0;
+}
+
+include_once HORDE_BASE . '/lib/Horde.php';
+include_once HORDE_BASE . '/lib/Secret.php';
+
+/**
+
+NOTE: On Windows 2000 SP4 with PHP 4.3.1, MCrypt 2.4.x, and Apache 1.3.28,
+the session didn't work properly.
+
+This may be resolved with 4.3.3.
+
+ */
+class ADODB_Encrypt_Secret {
+ /**
+ */
+ function write($data, $key) {
+ return Secret::write($key, $data);
+ }
+
+ /**
+ */
+ function read($data, $key) {
+ return Secret::read($key, $data);
+ }
+
+}
+
+return 1;
+
+?>
diff --git a/lib/adodb/session/adodb-encrypt-sha1.php b/lib/adodb/session/adodb-encrypt-sha1.php
new file mode 100644
index 0000000..c876002
--- /dev/null
+++ b/lib/adodb/session/adodb-encrypt-sha1.php
@@ -0,0 +1,32 @@
+<?php
+if (!defined('ADODB_SESSION')) die();
+
+include_once ADODB_SESSION . '/crypt.inc.php';
+
+
+/**
+
+ */
+
+class ADODB_Encrypt_SHA1 {
+
+ function write($data, $key)
+ {
+ $sha1crypt =& new SHA1Crypt();
+ return $sha1crypt->encrypt($data, $key);
+
+ }
+
+
+ function read($data, $key)
+ {
+ $sha1crypt =& new SHA1Crypt();
+ return $sha1crypt->decrypt($data, $key);
+
+ }
+}
+
+
+
+return 1;
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-session-clob.php b/lib/adodb/session/adodb-session-clob.php
new file mode 100644
index 0000000..a2cd480
--- /dev/null
+++ b/lib/adodb/session/adodb-session-clob.php
@@ -0,0 +1,24 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+*/
+
+/*
+
+This file is provided for backwards compatibility purposes
+
+*/
+
+if (!defined('ADODB_SESSION')) {
+ require_once dirname(__FILE__) . '/adodb-session.php';
+}
+ADODB_Session::clob('CLOB');
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-session-clob2.php b/lib/adodb/session/adodb-session-clob2.php
new file mode 100644
index 0000000..54b8043
--- /dev/null
+++ b/lib/adodb/session/adodb-session-clob2.php
@@ -0,0 +1,24 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+*/
+
+/*
+
+This file is provided for backwards compatibility purposes
+
+*/
+
+if (!defined('ADODB_SESSION')) {
+ require_once dirname(__FILE__) . '/adodb-session2.php';
+}
+ADODB_Session::clob('CLOB');
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-session.php b/lib/adodb/session/adodb-session.php
new file mode 100644
index 0000000..f0054ef
--- /dev/null
+++ b/lib/adodb/session/adodb-session.php
@@ -0,0 +1,934 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+*/
+
+/*
+ You may want to rename the 'data' field to 'session_data' as
+ 'data' appears to be a reserved word for one or more of the following:
+ ANSI SQL
+ IBM DB2
+ MS SQL Server
+ Postgres
+ SAP
+
+ If you do, then execute:
+
+ ADODB_Session::dataFieldName('session_data');
+
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ require realpath(dirname(__FILE__) . '/../adodb.inc.php');
+}
+
+if (defined('ADODB_SESSION')) return 1;
+
+define('ADODB_SESSION', dirname(__FILE__));
+
+
+/*
+ Unserialize session data manually. See http://phplens.com/lens/lensforum/msgs.php?id=9821
+
+ From Kerr Schere, to unserialize session data stored via ADOdb.
+ 1. Pull the session data from the db and loop through it.
+ 2. Inside the loop, you will need to urldecode the data column.
+ 3. After urldecode, run the serialized string through this function:
+
+*/
+function adodb_unserialize( $serialized_string )
+{
+ $variables = array( );
+ $a = preg_split( "/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
+ for( $i = 0; $i < count( $a ); $i = $i+2 ) {
+ $variables[$a[$i]] = unserialize( $a[$i+1] );
+ }
+ return( $variables );
+}
+
+/*
+ Thanks Joe Li. See http://phplens.com/lens/lensforum/msgs.php?id=11487&x=1
+ Since adodb 4.61.
+*/
+function adodb_session_regenerate_id()
+{
+ $conn =& ADODB_Session::_conn();
+ if (!$conn) return false;
+
+ $old_id = session_id();
+ if (function_exists('session_regenerate_id')) {
+ session_regenerate_id();
+ } else {
+ session_id(md5(uniqid(rand(), true)));
+ $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ //@session_start();
+ }
+ $new_id = session_id();
+ $ok =& $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id));
+
+ /* it is possible that the update statement fails due to a collision */
+ if (!$ok) {
+ session_id($old_id);
+ if (empty($ck)) $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ Generate database table for session data
+ @see http://phplens.com/lens/lensforum/msgs.php?id=12280
+ @return 0 if failure, 1 if errors, 2 if successful.
+ @author Markus Staab http://www.public-4u.de
+*/
+function adodb_session_create_table($schemaFile=null,$conn = null)
+{
+ // set default values
+ if ($schemaFile===null) $schemaFile = ADODB_SESSION . '/session_schema.xml';
+ if ($conn===null) $conn =& ADODB_Session::_conn();
+
+ if (!$conn) return 0;
+
+ $schema = new adoSchema($conn);
+ $schema->ParseSchema($schemaFile);
+ return $schema->ExecuteSchema();
+}
+
+/*!
+ \static
+*/
+class ADODB_Session {
+ /////////////////////
+ // getter/setter methods
+ /////////////////////
+
+ /*
+
+ function Lock($lock=null)
+ {
+ static $_lock = false;
+
+ if (!is_null($lock)) $_lock = $lock;
+ return $lock;
+ }
+ */
+ /*!
+ */
+ function driver($driver = null) {
+ static $_driver = 'mysql';
+ static $set = false;
+
+ if (!is_null($driver)) {
+ $_driver = trim($driver);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_DRIVER'])) {
+ return $GLOBALS['ADODB_SESSION_DRIVER'];
+ }
+ }
+
+ return $_driver;
+ }
+
+ /*!
+ */
+ function host($host = null) {
+ static $_host = 'localhost';
+ static $set = false;
+
+ if (!is_null($host)) {
+ $_host = trim($host);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_CONNECT'])) {
+ return $GLOBALS['ADODB_SESSION_CONNECT'];
+ }
+ }
+
+ return $_host;
+ }
+
+ /*!
+ */
+ function user($user = null) {
+ static $_user = 'root';
+ static $set = false;
+
+ if (!is_null($user)) {
+ $_user = trim($user);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_USER'])) {
+ return $GLOBALS['ADODB_SESSION_USER'];
+ }
+ }
+
+ return $_user;
+ }
+
+ /*!
+ */
+ function password($password = null) {
+ static $_password = '';
+ static $set = false;
+
+ if (!is_null($password)) {
+ $_password = $password;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_PWD'])) {
+ return $GLOBALS['ADODB_SESSION_PWD'];
+ }
+ }
+
+ return $_password;
+ }
+
+ /*!
+ */
+ function database($database = null) {
+ static $_database = 'xphplens_2';
+ static $set = false;
+
+ if (!is_null($database)) {
+ $_database = trim($database);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_DB'])) {
+ return $GLOBALS['ADODB_SESSION_DB'];
+ }
+ }
+
+ return $_database;
+ }
+
+ /*!
+ */
+ function persist($persist = null)
+ {
+ static $_persist = true;
+
+ if (!is_null($persist)) {
+ $_persist = trim($persist);
+ }
+
+ return $_persist;
+ }
+
+ /*!
+ */
+ function lifetime($lifetime = null) {
+ static $_lifetime;
+ static $set = false;
+
+ if (!is_null($lifetime)) {
+ $_lifetime = (int) $lifetime;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESS_LIFE'])) {
+ return $GLOBALS['ADODB_SESS_LIFE'];
+ }
+ }
+ if (!$_lifetime) {
+ $_lifetime = ini_get('session.gc_maxlifetime');
+ if ($_lifetime <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $lifetime</h3>";
+ $_lifetime = 1440;
+ }
+ }
+
+ return $_lifetime;
+ }
+
+ /*!
+ */
+ function debug($debug = null) {
+ static $_debug = false;
+ static $set = false;
+
+ if (!is_null($debug)) {
+ $_debug = (bool) $debug;
+
+ $conn = ADODB_Session::_conn();
+ if ($conn) {
+ $conn->debug = $_debug;
+ }
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESS_DEBUG'])) {
+ return $GLOBALS['ADODB_SESS_DEBUG'];
+ }
+ }
+
+ return $_debug;
+ }
+
+ /*!
+ */
+ function expireNotify($expire_notify = null) {
+ static $_expire_notify;
+ static $set = false;
+
+ if (!is_null($expire_notify)) {
+ $_expire_notify = $expire_notify;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'])) {
+ return $GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'];
+ }
+ }
+
+ return $_expire_notify;
+ }
+
+ /*!
+ */
+ function table($table = null) {
+ static $_table = 'sessions';
+ static $set = false;
+
+ if (!is_null($table)) {
+ $_table = trim($table);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_TBL'])) {
+ return $GLOBALS['ADODB_SESSION_TBL'];
+ }
+ }
+
+ return $_table;
+ }
+
+ /*!
+ */
+ function optimize($optimize = null) {
+ static $_optimize = false;
+ static $set = false;
+
+ if (!is_null($optimize)) {
+ $_optimize = (bool) $optimize;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (defined('ADODB_SESSION_OPTIMIZE')) {
+ return true;
+ }
+ }
+
+ return $_optimize;
+ }
+
+ /*!
+ */
+ function syncSeconds($sync_seconds = null) {
+ static $_sync_seconds = 60;
+ static $set = false;
+
+ if (!is_null($sync_seconds)) {
+ $_sync_seconds = (int) $sync_seconds;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (defined('ADODB_SESSION_SYNCH_SECS')) {
+ return ADODB_SESSION_SYNCH_SECS;
+ }
+ }
+
+ return $_sync_seconds;
+ }
+
+ /*!
+ */
+ function clob($clob = null) {
+ static $_clob = false;
+ static $set = false;
+
+ if (!is_null($clob)) {
+ $_clob = strtolower(trim($clob));
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_USE_LOBS'])) {
+ return $GLOBALS['ADODB_SESSION_USE_LOBS'];
+ }
+ }
+
+ return $_clob;
+ }
+
+ /*!
+ */
+ function dataFieldName($data_field_name = null) {
+ static $_data_field_name = 'data';
+
+ if (!is_null($data_field_name)) {
+ $_data_field_name = trim($data_field_name);
+ }
+
+ return $_data_field_name;
+ }
+
+ /*!
+ */
+ function filter($filter = null) {
+ static $_filter = array();
+
+ if (!is_null($filter)) {
+ if (!is_array($filter)) {
+ $filter = array($filter);
+ }
+ $_filter = $filter;
+ }
+
+ return $_filter;
+ }
+
+ /*!
+ */
+ function encryptionKey($encryption_key = null) {
+ static $_encryption_key = 'CRYPTED ADODB SESSIONS ROCK!';
+
+ if (!is_null($encryption_key)) {
+ $_encryption_key = $encryption_key;
+ }
+
+ return $_encryption_key;
+ }
+
+ /////////////////////
+ // private methods
+ /////////////////////
+
+ /*!
+ */
+ function &_conn($conn=null) {
+ return $GLOBALS['ADODB_SESS_CONN'];
+ }
+
+ /*!
+ */
+ function _crc($crc = null) {
+ static $_crc = false;
+
+ if (!is_null($crc)) {
+ $_crc = $crc;
+ }
+
+ return $_crc;
+ }
+
+ /*!
+ */
+ function _init() {
+ session_module_name('user');
+ session_set_save_handler(
+ array('ADODB_Session', 'open'),
+ array('ADODB_Session', 'close'),
+ array('ADODB_Session', 'read'),
+ array('ADODB_Session', 'write'),
+ array('ADODB_Session', 'destroy'),
+ array('ADODB_Session', 'gc')
+ );
+ }
+
+
+ /*!
+ */
+ function _sessionKey() {
+ // use this function to create the encryption key for crypted sessions
+ // crypt the used key, ADODB_Session::encryptionKey() as key and session_id() as salt
+ return crypt(ADODB_Session::encryptionKey(), session_id());
+ }
+
+ /*!
+ */
+ function _dumprs($rs) {
+ $conn =& ADODB_Session::_conn();
+ $debug = ADODB_Session::debug();
+
+ if (!$conn) {
+ return;
+ }
+
+ if (!$debug) {
+ return;
+ }
+
+ if (!$rs) {
+ echo "<br />\$rs is null or false<br />\n";
+ return;
+ }
+
+ //echo "<br />\nAffected_Rows=",$conn->Affected_Rows(),"<br />\n";
+
+ if (!is_object($rs)) {
+ return;
+ }
+
+ require_once ADODB_SESSION.'/../tohtml.inc.php';
+ rs2html($rs);
+ }
+
+ /////////////////////
+ // public methods
+ /////////////////////
+
+ function config($driver, $host, $user, $password, $database=false,$options=false)
+ {
+ ADODB_Session::driver($driver);
+ ADODB_Session::host($host);
+ ADODB_Session::user($user);
+ ADODB_Session::password($password);
+ ADODB_Session::database($database);
+
+ if ($driver == 'oci8' || $driver == 'oci8po') $options['lob'] = 'CLOB';
+
+ if (isset($options['table'])) ADODB_Session::table($options['table']);
+ if (isset($options['lob'])) ADODB_Session::clob($options['lob']);
+ if (isset($options['debug'])) ADODB_Session::debug($options['debug']);
+ }
+
+ /*!
+ Create the connection to the database.
+
+ If $conn already exists, reuse that connection
+ */
+ function open($save_path, $session_name, $persist = null)
+ {
+ $conn =& ADODB_Session::_conn();
+
+ if ($conn) {
+ return true;
+ }
+
+ $database = ADODB_Session::database();
+ $debug = ADODB_Session::debug();
+ $driver = ADODB_Session::driver();
+ $host = ADODB_Session::host();
+ $password = ADODB_Session::password();
+ $user = ADODB_Session::user();
+
+ if (!is_null($persist)) {
+ ADODB_Session::persist($persist);
+ } else {
+ $persist = ADODB_Session::persist();
+ }
+
+# these can all be defaulted to in php.ini
+# assert('$database');
+# assert('$driver');
+# assert('$host');
+
+ $conn =& ADONewConnection($driver);
+
+ if ($debug) {
+ $conn->debug = true;
+// ADOConnection::outp( " driver=$driver user=$user pwd=$password db=$database ");
+ }
+
+ if ($persist) {
+ switch($persist) {
+ default:
+ case 'P': $ok = $conn->PConnect($host, $user, $password, $database); break;
+ case 'C': $ok = $conn->Connect($host, $user, $password, $database); break;
+ case 'N': $ok = $conn->NConnect($host, $user, $password, $database); break;
+ }
+ } else {
+ $ok = $conn->Connect($host, $user, $password, $database);
+ }
+
+ if ($ok) $GLOBALS['ADODB_SESS_CONN'] =& $conn;
+ else
+ ADOConnection::outp('<p>Session: connection failed</p>', false);
+
+
+ return $ok;
+ }
+
+ /*!
+ Close the connection
+ */
+ function close()
+ {
+/*
+ $conn =& ADODB_Session::_conn();
+ if ($conn) $conn->Close();
+*/
+ return true;
+ }
+
+ /*
+ Slurp in the session variables and return the serialized string
+ */
+ function read($key)
+ {
+ $conn =& ADODB_Session::_conn();
+ $data = ADODB_Session::dataFieldName();
+ $filter = ADODB_Session::filter();
+ $table = ADODB_Session::table();
+
+ if (!$conn) {
+ return '';
+ }
+
+ //assert('$table');
+
+ $qkey = $conn->quote($key);
+ $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+ $sql = "SELECT $data FROM $table WHERE sesskey = $binary $qkey AND expiry >= " . time();
+ /* Lock code does not work as it needs to hold transaction within whole page, and we don't know if
+ developer has commited elsewhere... :(
+ */
+ #if (ADODB_Session::Lock())
+ # $rs =& $conn->RowLock($table, "$binary sesskey = $qkey AND expiry >= " . time(), $data);
+ #else
+
+ $rs =& $conn->Execute($sql);
+ //ADODB_Session::_dumprs($rs);
+ if ($rs) {
+ if ($rs->EOF) {
+ $v = '';
+ } else {
+ $v = reset($rs->fields);
+ $filter = array_reverse($filter);
+ foreach ($filter as $f) {
+ if (is_object($f)) {
+ $v = $f->read($v, ADODB_Session::_sessionKey());
+ }
+ }
+ $v = rawurldecode($v);
+ }
+
+ $rs->Close();
+
+ ADODB_Session::_crc(strlen($v) . crc32($v));
+ return $v;
+ }
+
+ return '';
+ }
+
+ /*!
+ Write the serialized data to a database.
+
+ If the data has not been modified since the last read(), we do not write.
+ */
+ function write($key, $val)
+ {
+ global $ADODB_SESSION_READONLY;
+
+ if (!empty($ADODB_SESSION_READONLY)) return;
+
+ $clob = ADODB_Session::clob();
+ $conn =& ADODB_Session::_conn();
+ $crc = ADODB_Session::_crc();
+ $data = ADODB_Session::dataFieldName();
+ $debug = ADODB_Session::debug();
+ $driver = ADODB_Session::driver();
+ $expire_notify = ADODB_Session::expireNotify();
+ $filter = ADODB_Session::filter();
+ $lifetime = ADODB_Session::lifetime();
+ $table = ADODB_Session::table();
+
+ if (!$conn) {
+ return false;
+ }
+ $qkey = $conn->qstr($key);
+
+ //assert('$table');
+
+ $expiry = time() + $lifetime;
+
+ $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+ // crc32 optimization since adodb 2.1
+ // now we only update expiry date, thx to sebastian thom in adodb 2.32
+ if ($crc !== false && $crc == (strlen($val) . crc32($val))) {
+ if ($debug) {
+ echo '<p>Session: Only updating date - crc32 not changed</p>';
+ }
+
+ $expirevar = '';
+ if ($expire_notify) {
+ $var = reset($expire_notify);
+ global $$var;
+ if (isset($$var)) {
+ $expirevar = $$var;
+ }
+ }
+
+
+ $sql = "UPDATE $table SET expiry = ".$conn->Param('0').",expireref=".$conn->Param('1')." WHERE $binary sesskey = ".$conn->Param('2')." AND expiry >= ".$conn->Param('3');
+ $rs =& $conn->Execute($sql,array($expiry,$expirevar,$key,time()));
+ return true;
+ }
+ $val = rawurlencode($val);
+ foreach ($filter as $f) {
+ if (is_object($f)) {
+ $val = $f->write($val, ADODB_Session::_sessionKey());
+ }
+ }
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, $data => $val, 'expireref' => '');
+ if ($expire_notify) {
+ $var = reset($expire_notify);
+ global $$var;
+ if (isset($$var)) {
+ $arr['expireref'] = $$var;
+ }
+ }
+
+ if (!$clob) { // no lobs, simply use replace()
+ $arr[$data] = $conn->qstr($val);
+ $rs = $conn->Replace($table, $arr, 'sesskey', $autoQuote = true);
+
+ } else {
+ // what value shall we insert/update for lob row?
+ switch ($driver) {
+ // empty_clob or empty_lob for oracle dbs
+ case 'oracle':
+ case 'oci8':
+ case 'oci8po':
+ case 'oci805':
+ $lob_value = sprintf('empty_%s()', strtolower($clob));
+ break;
+
+ // null for all other
+ default:
+ $lob_value = 'null';
+ break;
+ }
+
+ $conn->StartTrans();
+ $expiryref = $conn->qstr($arr['expireref']);
+ // do we insert or update? => as for sesskey
+ $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = $qkey");
+ if ($rs && reset($rs->fields) > 0) {
+ $sql = "UPDATE $table SET expiry = $expiry, $data = $lob_value, expireref=$expiryref WHERE sesskey = $qkey";
+ } else {
+ $sql = "INSERT INTO $table (expiry, $data, sesskey,expireref) VALUES ($expiry, $lob_value, $qkey,$expiryref)";
+ }
+ if ($rs)$rs->Close();
+
+
+ $err = '';
+ $rs1 =& $conn->Execute($sql);
+ if (!$rs1) $err = $conn->ErrorMsg()."\n";
+
+ $rs2 =& $conn->UpdateBlob($table, $data, $val, " sesskey=$qkey", strtoupper($clob));
+ if (!$rs2) $err .= $conn->ErrorMsg()."\n";
+
+ $rs = ($rs && $rs2) ? true : false;
+ $conn->CompleteTrans();
+ }
+
+ if (!$rs) {
+ ADOConnection::outp('<p>Session Replace: ' . $conn->ErrorMsg() . '</p>', false);
+ return false;
+ } else {
+ // bug in access driver (could be odbc?) means that info is not committed
+ // properly unless select statement executed in Win2000
+ if ($conn->databaseType == 'access') {
+ $sql = "SELECT sesskey FROM $table WHERE $binary sesskey = $qkey";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ if ($rs) {
+ $rs->Close();
+ }
+ }
+ }/*
+ if (ADODB_Session::Lock()) {
+ $conn->CommitTrans();
+ }*/
+ return $rs ? true : false;
+ }
+
+ /*!
+ */
+ function destroy($key) {
+ $conn =& ADODB_Session::_conn();
+ $table = ADODB_Session::table();
+ $expire_notify = ADODB_Session::expireNotify();
+
+ if (!$conn) {
+ return false;
+ }
+
+ //assert('$table');
+
+ $qkey = $conn->quote($key);
+ $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+ if ($expire_notify) {
+ reset($expire_notify);
+ $fn = next($expire_notify);
+ $savem = $conn->SetFetchMode(ADODB_FETCH_NUM);
+ $sql = "SELECT expireref, sesskey FROM $table WHERE $binary sesskey = $qkey";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ $conn->SetFetchMode($savem);
+ if (!$rs) {
+ return false;
+ }
+ if (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ //assert('$ref');
+ //assert('$key');
+ $fn($ref, $key);
+ }
+ $rs->Close();
+ }
+
+ $sql = "DELETE FROM $table WHERE $binary sesskey = $qkey";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+
+ return $rs ? true : false;
+ }
+
+ /*!
+ */
+ function gc($maxlifetime)
+ {
+ $conn =& ADODB_Session::_conn();
+ $debug = ADODB_Session::debug();
+ $expire_notify = ADODB_Session::expireNotify();
+ $optimize = ADODB_Session::optimize();
+ $sync_seconds = ADODB_Session::syncSeconds();
+ $table = ADODB_Session::table();
+
+ if (!$conn) {
+ return false;
+ }
+
+
+ $time = time();
+ $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+ if ($expire_notify) {
+ reset($expire_notify);
+ $fn = next($expire_notify);
+ $savem = $conn->SetFetchMode(ADODB_FETCH_NUM);
+ $sql = "SELECT expireref, sesskey FROM $table WHERE expiry < $time";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ $conn->SetFetchMode($savem);
+ if ($rs) {
+ $conn->StartTrans();
+ $keys = array();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref, $key);
+ $del = $conn->Execute("DELETE FROM $table WHERE sesskey=".$conn->Param('0'),array($key));
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $conn->CompleteTrans();
+ }
+ } else {
+
+ if (1) {
+ $sql = "SELECT sesskey FROM $table WHERE expiry < $time";
+ $arr =& $conn->GetAll($sql);
+ foreach ($arr as $row) {
+ $sql2 = "DELETE FROM $table WHERE sesskey=".$conn->Param('0');
+ $conn->Execute($sql2,array($row[0]));
+ }
+ } else {
+ $sql = "DELETE FROM $table WHERE expiry < $time";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ if ($rs) $rs->Close();
+ }
+ if ($debug) {
+ ADOConnection::outp("<p><b>Garbage Collection</b>: $sql</p>");
+ }
+ }
+
+ // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+ if ($optimize) {
+ $driver = ADODB_Session::driver();
+
+ if (preg_match('/mysql/i', $driver)) {
+ $sql = "OPTIMIZE TABLE $table";
+ }
+ if (preg_match('/postgres/i', $driver)) {
+ $sql = "VACUUM $table";
+ }
+ if (!empty($sql)) {
+ $conn->Execute($sql);
+ }
+ }
+
+ if ($sync_seconds) {
+ $sql = 'SELECT ';
+ if ($conn->dataProvider === 'oci8') {
+ $sql .= "TO_CHAR({$conn->sysTimeStamp}, 'RRRR-MM-DD HH24:MI:SS')";
+ } else {
+ $sql .= $conn->sysTimeStamp;
+ }
+ $sql .= " FROM $table";
+
+ $rs =& $conn->SelectLimit($sql, 1);
+ if ($rs && !$rs->EOF) {
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $conn->UnixTimeStamp($dbts);
+ $t = time();
+
+ if (abs($dbt - $t) >= $sync_seconds) {
+ $msg = __FILE__ .
+ ": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: " .
+ " database=$dbt ($dbts), webserver=$t (diff=". (abs($dbt - $t) / 60) . ' minutes)';
+ error_log($msg);
+ if ($debug) {
+ ADOConnection::outp("<p>$msg</p>");
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+}
+
+ADODB_Session::_init();
+if (empty($ADODB_SESSION_READONLY))
+ register_shutdown_function('session_write_close');
+
+// for backwards compatability only
+function adodb_sess_open($save_path, $session_name, $persist = true) {
+ return ADODB_Session::open($save_path, $session_name, $persist);
+}
+
+// for backwards compatability only
+function adodb_sess_gc($t)
+{
+ return ADODB_Session::gc($t);
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/adodb-session2.php b/lib/adodb/session/adodb-session2.php
new file mode 100644
index 0000000..c5932b6
--- /dev/null
+++ b/lib/adodb/session/adodb-session2.php
@@ -0,0 +1,941 @@
+<?php
+
+
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Contributed by Ross Smith (adodb@netebb.com).
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+
+*/
+
+/*
+
+CREATE Table SCripts
+
+Oracle
+======
+
+CREATE TABLE SESSIONS2
+(
+ SESSKEY VARCHAR2(48 BYTE) NOT NULL,
+ EXPIRY DATE NOT NULL,
+ EXPIREREF VARCHAR2(200 BYTE),
+ CREATED DATE NOT NULL,
+ MODIFIED DATE NOT NULL,
+ SESSDATA CLOB,
+ PRIMARY KEY(SESSKEY)
+);
+
+
+CREATE INDEX SESS2_EXPIRY ON SESSIONS2(EXPIRY);
+CREATE UNIQUE INDEX SESS2_PK ON SESSIONS2(SESSKEY);
+CREATE INDEX SESS2_EXP_REF ON SESSIONS2(EXPIREREF);
+
+
+
+ MySQL
+ =====
+
+CREATE TABLE sessions2(
+ sesskey VARCHAR( 64 ) NOT NULL DEFAULT '',
+ expiry TIMESTAMP NOT NULL ,
+ expireref VARCHAR( 250 ) DEFAULT '',
+ created TIMESTAMP NOT NULL ,
+ modified TIMESTAMP NOT NULL ,
+ sessdata LONGTEXT DEFAULT '',
+ PRIMARY KEY ( sesskey ) ,
+ INDEX sess2_expiry( expiry ),
+ INDEX sess2_expireref( expireref )
+)
+
+
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ require realpath(dirname(__FILE__) . '/../adodb.inc.php');
+}
+
+if (defined('ADODB_SESSION')) return 1;
+
+define('ADODB_SESSION', dirname(__FILE__));
+define('ADODB_SESSION2', ADODB_SESSION);
+
+/*
+ Unserialize session data manually. See http://phplens.com/lens/lensforum/msgs.php?id=9821
+
+ From Kerr Schere, to unserialize session data stored via ADOdb.
+ 1. Pull the session data from the db and loop through it.
+ 2. Inside the loop, you will need to urldecode the data column.
+ 3. After urldecode, run the serialized string through this function:
+
+*/
+function adodb_unserialize( $serialized_string )
+{
+ $variables = array( );
+ $a = preg_split( "/(\w+)\|/", $serialized_string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
+ for( $i = 0; $i < count( $a ); $i = $i+2 ) {
+ $variables[$a[$i]] = unserialize( $a[$i+1] );
+ }
+ return( $variables );
+}
+
+/*
+ Thanks Joe Li. See http://phplens.com/lens/lensforum/msgs.php?id=11487&x=1
+ Since adodb 4.61.
+*/
+function adodb_session_regenerate_id()
+{
+ $conn =& ADODB_Session::_conn();
+ if (!$conn) return false;
+
+ $old_id = session_id();
+ if (function_exists('session_regenerate_id')) {
+ session_regenerate_id();
+ } else {
+ session_id(md5(uniqid(rand(), true)));
+ $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ //@session_start();
+ }
+ $new_id = session_id();
+ $ok =& $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id));
+
+ /* it is possible that the update statement fails due to a collision */
+ if (!$ok) {
+ session_id($old_id);
+ if (empty($ck)) $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ Generate database table for session data
+ @see http://phplens.com/lens/lensforum/msgs.php?id=12280
+ @return 0 if failure, 1 if errors, 2 if successful.
+ @author Markus Staab http://www.public-4u.de
+*/
+function adodb_session_create_table($schemaFile=null,$conn = null)
+{
+ // set default values
+ if ($schemaFile===null) $schemaFile = ADODB_SESSION . '/session_schema2.xml';
+ if ($conn===null) $conn =& ADODB_Session::_conn();
+
+ if (!$conn) return 0;
+
+ $schema = new adoSchema($conn);
+ $schema->ParseSchema($schemaFile);
+ return $schema->ExecuteSchema();
+}
+
+/*!
+ \static
+*/
+class ADODB_Session {
+ /////////////////////
+ // getter/setter methods
+ /////////////////////
+
+ /*
+
+ function Lock($lock=null)
+ {
+ static $_lock = false;
+
+ if (!is_null($lock)) $_lock = $lock;
+ return $lock;
+ }
+ */
+ /*!
+ */
+ function driver($driver = null)
+ {
+ static $_driver = 'mysql';
+ static $set = false;
+
+ if (!is_null($driver)) {
+ $_driver = trim($driver);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_DRIVER'])) {
+ return $GLOBALS['ADODB_SESSION_DRIVER'];
+ }
+ }
+
+ return $_driver;
+ }
+
+ /*!
+ */
+ function host($host = null) {
+ static $_host = 'localhost';
+ static $set = false;
+
+ if (!is_null($host)) {
+ $_host = trim($host);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_CONNECT'])) {
+ return $GLOBALS['ADODB_SESSION_CONNECT'];
+ }
+ }
+
+ return $_host;
+ }
+
+ /*!
+ */
+ function user($user = null)
+ {
+ static $_user = 'root';
+ static $set = false;
+
+ if (!is_null($user)) {
+ $_user = trim($user);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_USER'])) {
+ return $GLOBALS['ADODB_SESSION_USER'];
+ }
+ }
+
+ return $_user;
+ }
+
+ /*!
+ */
+ function password($password = null)
+ {
+ static $_password = '';
+ static $set = false;
+
+ if (!is_null($password)) {
+ $_password = $password;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_PWD'])) {
+ return $GLOBALS['ADODB_SESSION_PWD'];
+ }
+ }
+
+ return $_password;
+ }
+
+ /*!
+ */
+ function database($database = null)
+ {
+ static $_database = '';
+ static $set = false;
+
+ if (!is_null($database)) {
+ $_database = trim($database);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_DB'])) {
+ return $GLOBALS['ADODB_SESSION_DB'];
+ }
+ }
+ return $_database;
+ }
+
+ /*!
+ */
+ function persist($persist = null)
+ {
+ static $_persist = true;
+
+ if (!is_null($persist)) {
+ $_persist = trim($persist);
+ }
+
+ return $_persist;
+ }
+
+ /*!
+ */
+ function lifetime($lifetime = null)
+ {
+ static $_lifetime;
+ static $set = false;
+
+ if (!is_null($lifetime)) {
+ $_lifetime = (int) $lifetime;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESS_LIFE'])) {
+ return $GLOBALS['ADODB_SESS_LIFE'];
+ }
+ }
+ if (!$_lifetime) {
+ $_lifetime = ini_get('session.gc_maxlifetime');
+ if ($_lifetime <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $lifetime</h3>";
+ $_lifetime = 1440;
+ }
+ }
+
+ return $_lifetime;
+ }
+
+ /*!
+ */
+ function debug($debug = null)
+ {
+ static $_debug = false;
+ static $set = false;
+
+ if (!is_null($debug)) {
+ $_debug = (bool) $debug;
+
+ $conn = ADODB_Session::_conn();
+ if ($conn) {
+ $conn->debug = $_debug;
+ }
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESS_DEBUG'])) {
+ return $GLOBALS['ADODB_SESS_DEBUG'];
+ }
+ }
+
+ return $_debug;
+ }
+
+ /*!
+ */
+ function expireNotify($expire_notify = null)
+ {
+ static $_expire_notify;
+ static $set = false;
+
+ if (!is_null($expire_notify)) {
+ $_expire_notify = $expire_notify;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'])) {
+ return $GLOBALS['ADODB_SESSION_EXPIRE_NOTIFY'];
+ }
+ }
+
+ return $_expire_notify;
+ }
+
+ /*!
+ */
+ function table($table = null)
+ {
+ static $_table = 'sessions2';
+ static $set = false;
+
+ if (!is_null($table)) {
+ $_table = trim($table);
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_TBL'])) {
+ return $GLOBALS['ADODB_SESSION_TBL'];
+ }
+ }
+
+ return $_table;
+ }
+
+ /*!
+ */
+ function optimize($optimize = null)
+ {
+ static $_optimize = false;
+ static $set = false;
+
+ if (!is_null($optimize)) {
+ $_optimize = (bool) $optimize;
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (defined('ADODB_SESSION_OPTIMIZE')) {
+ return true;
+ }
+ }
+
+ return $_optimize;
+ }
+
+ /*!
+ */
+ function syncSeconds($sync_seconds = null) {
+ //echo ("<p>WARNING: ADODB_SESSION::syncSeconds is longer used, please remove this function for your code</p>");
+
+ return 0;
+ }
+
+ /*!
+ */
+ function clob($clob = null) {
+ static $_clob = false;
+ static $set = false;
+
+ if (!is_null($clob)) {
+ $_clob = strtolower(trim($clob));
+ $set = true;
+ } elseif (!$set) {
+ // backwards compatibility
+ if (isset($GLOBALS['ADODB_SESSION_USE_LOBS'])) {
+ return $GLOBALS['ADODB_SESSION_USE_LOBS'];
+ }
+ }
+
+ return $_clob;
+ }
+
+ /*!
+ */
+ function dataFieldName($data_field_name = null) {
+ //echo ("<p>WARNING: ADODB_SESSION::dataFieldName() is longer used, please remove this function for your code</p>");
+ return '';
+ }
+
+ /*!
+ */
+ function filter($filter = null) {
+ static $_filter = array();
+
+ if (!is_null($filter)) {
+ if (!is_array($filter)) {
+ $filter = array($filter);
+ }
+ $_filter = $filter;
+ }
+
+ return $_filter;
+ }
+
+ /*!
+ */
+ function encryptionKey($encryption_key = null) {
+ static $_encryption_key = 'CRYPTED ADODB SESSIONS ROCK!';
+
+ if (!is_null($encryption_key)) {
+ $_encryption_key = $encryption_key;
+ }
+
+ return $_encryption_key;
+ }
+
+ /////////////////////
+ // private methods
+ /////////////////////
+
+ /*!
+ */
+ function &_conn($conn=null) {
+ return $GLOBALS['ADODB_SESS_CONN'];
+ }
+
+ /*!
+ */
+ function _crc($crc = null) {
+ static $_crc = false;
+
+ if (!is_null($crc)) {
+ $_crc = $crc;
+ }
+
+ return $_crc;
+ }
+
+ /*!
+ */
+ function _init() {
+ session_module_name('user');
+ session_set_save_handler(
+ array('ADODB_Session', 'open'),
+ array('ADODB_Session', 'close'),
+ array('ADODB_Session', 'read'),
+ array('ADODB_Session', 'write'),
+ array('ADODB_Session', 'destroy'),
+ array('ADODB_Session', 'gc')
+ );
+ }
+
+
+ /*!
+ */
+ function _sessionKey() {
+ // use this function to create the encryption key for crypted sessions
+ // crypt the used key, ADODB_Session::encryptionKey() as key and session_id() as salt
+ return crypt(ADODB_Session::encryptionKey(), session_id());
+ }
+
+ /*!
+ */
+ function _dumprs($rs) {
+ $conn =& ADODB_Session::_conn();
+ $debug = ADODB_Session::debug();
+
+ if (!$conn) {
+ return;
+ }
+
+ if (!$debug) {
+ return;
+ }
+
+ if (!$rs) {
+ echo "<br />\$rs is null or false<br />\n";
+ return;
+ }
+
+ //echo "<br />\nAffected_Rows=",$conn->Affected_Rows(),"<br />\n";
+
+ if (!is_object($rs)) {
+ return;
+ }
+
+ require_once ADODB_SESSION.'/../tohtml.inc.php';
+ rs2html($rs);
+ }
+
+ /////////////////////
+ // public methods
+ /////////////////////
+
+ function config($driver, $host, $user, $password, $database=false,$options=false)
+ {
+ ADODB_Session::driver($driver);
+ ADODB_Session::host($host);
+ ADODB_Session::user($user);
+ ADODB_Session::password($password);
+ ADODB_Session::database($database);
+
+ if ($driver == 'oci8' || $driver == 'oci8po') $options['lob'] = 'CLOB';
+
+ if (isset($options['table'])) ADODB_Session::table($options['table']);
+ if (isset($options['lob'])) ADODB_Session::clob($options['lob']);
+ if (isset($options['debug'])) ADODB_Session::debug($options['debug']);
+ }
+
+ /*!
+ Create the connection to the database.
+
+ If $conn already exists, reuse that connection
+ */
+ function open($save_path, $session_name, $persist = null)
+ {
+ $conn =& ADODB_Session::_conn();
+
+ if ($conn) {
+ return true;
+ }
+
+ $database = ADODB_Session::database();
+ $debug = ADODB_Session::debug();
+ $driver = ADODB_Session::driver();
+ $host = ADODB_Session::host();
+ $password = ADODB_Session::password();
+ $user = ADODB_Session::user();
+
+ if (!is_null($persist)) {
+ ADODB_Session::persist($persist);
+ } else {
+ $persist = ADODB_Session::persist();
+ }
+
+# these can all be defaulted to in php.ini
+# assert('$database');
+# assert('$driver');
+# assert('$host');
+
+ $conn =& ADONewConnection($driver);
+
+ if ($debug) {
+ $conn->debug = true;
+ ADOConnection::outp( " driver=$driver user=$user db=$database ");
+ }
+
+ if ($persist) {
+ switch($persist) {
+ default:
+ case 'P': $ok = $conn->PConnect($host, $user, $password, $database); break;
+ case 'C': $ok = $conn->Connect($host, $user, $password, $database); break;
+ case 'N': $ok = $conn->NConnect($host, $user, $password, $database); break;
+ }
+ } else {
+ $ok = $conn->Connect($host, $user, $password, $database);
+ }
+
+ if ($ok) $GLOBALS['ADODB_SESS_CONN'] =& $conn;
+ else
+ ADOConnection::outp('<p>Session: connection failed</p>', false);
+
+
+ return $ok;
+ }
+
+ /*!
+ Close the connection
+ */
+ function close()
+ {
+/*
+ $conn =& ADODB_Session::_conn();
+ if ($conn) $conn->Close();
+*/
+ return true;
+ }
+
+ /*
+ Slurp in the session variables and return the serialized string
+ */
+ function read($key)
+ {
+ $conn =& ADODB_Session::_conn();
+ $filter = ADODB_Session::filter();
+ $table = ADODB_Session::table();
+
+ if (!$conn) {
+ return '';
+ }
+
+ //assert('$table');
+
+ $qkey = $conn->quote($key);
+ $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+ $sql = "SELECT sessdata FROM $table WHERE sesskey = $binary $qkey AND expiry >= " . $conn->sysTimeStamp;
+ /* Lock code does not work as it needs to hold transaction within whole page, and we don't know if
+ developer has commited elsewhere... :(
+ */
+ #if (ADODB_Session::Lock())
+ # $rs =& $conn->RowLock($table, "$binary sesskey = $qkey AND expiry >= " . time(), sessdata);
+ #else
+
+ $rs =& $conn->Execute($sql);
+ //ADODB_Session::_dumprs($rs);
+ if ($rs) {
+ if ($rs->EOF) {
+ $v = '';
+ } else {
+ $v = reset($rs->fields);
+ $filter = array_reverse($filter);
+ foreach ($filter as $f) {
+ if (is_object($f)) {
+ $v = $f->read($v, ADODB_Session::_sessionKey());
+ }
+ }
+ $v = rawurldecode($v);
+ }
+
+ $rs->Close();
+
+ ADODB_Session::_crc(strlen($v) . crc32($v));
+ return $v;
+ }
+
+ return '';
+ }
+
+ /*!
+ Write the serialized data to a database.
+
+ If the data has not been modified since the last read(), we do not write.
+ */
+ function write($key, $val)
+ {
+ global $ADODB_SESSION_READONLY;
+
+ if (!empty($ADODB_SESSION_READONLY)) return;
+
+ $clob = ADODB_Session::clob();
+ $conn =& ADODB_Session::_conn();
+ $crc = ADODB_Session::_crc();
+ $debug = ADODB_Session::debug();
+ $driver = ADODB_Session::driver();
+ $expire_notify = ADODB_Session::expireNotify();
+ $filter = ADODB_Session::filter();
+ $lifetime = ADODB_Session::lifetime();
+ $table = ADODB_Session::table();
+
+ if (!$conn) {
+ return false;
+ }
+
+ $sysTimeStamp = $conn->sysTimeStamp;
+
+ //assert('$table');
+
+ $expiry = $conn->OffsetDate($lifetime/(24*3600),$sysTimeStamp);
+
+ $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+ // crc32 optimization since adodb 2.1
+ // now we only update expiry date, thx to sebastian thom in adodb 2.32
+ if ($crc !== false && $crc == (strlen($val) . crc32($val))) {
+ if ($debug) {
+ echo '<p>Session: Only updating date - crc32 not changed</p>';
+ }
+
+ $expirevar = '';
+ if ($expire_notify) {
+ $var = reset($expire_notify);
+ global $$var;
+ if (isset($$var)) {
+ $expirevar = $$var;
+ }
+ }
+
+
+ $sql = "UPDATE $table SET expiry = $expiry ,expireref=".$conn->Param('0').", modified = $sysTimeStamp WHERE $binary sesskey = ".$conn->Param('1')." AND expiry >= $sysTimeStamp";
+ $rs =& $conn->Execute($sql,array($expirevar,$key));
+ return true;
+ }
+ $val = rawurlencode($val);
+ foreach ($filter as $f) {
+ if (is_object($f)) {
+ $val = $f->write($val, ADODB_Session::_sessionKey());
+ }
+ }
+
+ $expireref = '';
+ if ($expire_notify) {
+ $var = reset($expire_notify);
+ global $$var;
+ if (isset($$var)) {
+ $expireref = $$var;
+ }
+ }
+
+ if (!$clob) { // no lobs, simply use replace()
+ $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = ".$conn->Param(0),array($key));
+ if ($rs) $rs->Close();
+
+ if ($rs && reset($rs->fields) > 0) {
+ $sql = "UPDATE $table SET expiry=$expiry, sessdata=".$conn->Param(0).", expireref= ".$conn->Param(1).",modified=$sysTimeStamp WHERE sesskey = ".$conn->Param('2');
+
+ } else {
+ $sql = "INSERT INTO $table (expiry, sessdata, expireref, sesskey, created, modified)
+ VALUES ($expiry,".$conn->Param('0').", ". $conn->Param('1').", ".$conn->Param('2').", $sysTimeStamp, $sysTimeStamp)";
+ }
+
+
+ $rs =& $conn->Execute($sql,array($val,$expireref,$key));
+
+ } else {
+ // what value shall we insert/update for lob row?
+ switch ($driver) {
+ // empty_clob or empty_lob for oracle dbs
+ case 'oracle':
+ case 'oci8':
+ case 'oci8po':
+ case 'oci805':
+ $lob_value = sprintf('empty_%s()', strtolower($clob));
+ break;
+
+ // null for all other
+ default:
+ $lob_value = 'null';
+ break;
+ }
+
+ $conn->StartTrans();
+
+ $rs =& $conn->Execute("SELECT COUNT(*) AS cnt FROM $table WHERE $binary sesskey = ".$conn->Param(0),array($key));
+ if ($rs) $rs->Close();
+
+ if ($rs && reset($rs->fields) > 0) {
+ $sql = "UPDATE $table SET expiry=$expiry, sessdata=$lob_value, expireref= ".$conn->Param(0).",modified=$sysTimeStamp WHERE sesskey = ".$conn->Param('1');
+
+ } else {
+ $sql = "INSERT INTO $table (expiry, sessdata, expireref, sesskey, created, modified)
+ VALUES ($expiry,$lob_value, ". $conn->Param('0').", ".$conn->Param('1').", $sysTimeStamp, $sysTimeStamp)";
+ }
+
+ $rs =& $conn->Execute($sql,array($expireref,$key));
+
+ $qkey = $conn->qstr($key);
+ $rs2 =& $conn->UpdateBlob($table, 'sessdata', $val, " sesskey=$qkey", strtoupper($clob));
+ $rs = @$conn->CompleteTrans();
+
+
+ }
+
+ if (!$rs) {
+ ADOConnection::outp('<p>Session Replace: ' . $conn->ErrorMsg() . '</p>', false);
+ return false;
+ } else {
+ // bug in access driver (could be odbc?) means that info is not committed
+ // properly unless select statement executed in Win2000
+ if ($conn->databaseType == 'access') {
+ $sql = "SELECT sesskey FROM $table WHERE $binary sesskey = $qkey";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ if ($rs) {
+ $rs->Close();
+ }
+ }
+ }/*
+ if (ADODB_Session::Lock()) {
+ $conn->CommitTrans();
+ }*/
+ return $rs ? true : false;
+ }
+
+ /*!
+ */
+ function destroy($key) {
+ $conn =& ADODB_Session::_conn();
+ $table = ADODB_Session::table();
+ $expire_notify = ADODB_Session::expireNotify();
+
+ if (!$conn) {
+ return false;
+ }
+
+ //assert('$table');
+
+ $qkey = $conn->quote($key);
+ $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+ if ($expire_notify) {
+ reset($expire_notify);
+ $fn = next($expire_notify);
+ $savem = $conn->SetFetchMode(ADODB_FETCH_NUM);
+ $sql = "SELECT expireref, sesskey FROM $table WHERE $binary sesskey = $qkey";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ $conn->SetFetchMode($savem);
+ if (!$rs) {
+ return false;
+ }
+ if (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ //assert('$ref');
+ //assert('$key');
+ $fn($ref, $key);
+ }
+ $rs->Close();
+ }
+
+ $sql = "DELETE FROM $table WHERE $binary sesskey = $qkey";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ if ($rs) {
+ $rs->Close();
+ }
+
+ return $rs ? true : false;
+ }
+
+ /*!
+ */
+ function gc($maxlifetime)
+ {
+ $conn =& ADODB_Session::_conn();
+ $debug = ADODB_Session::debug();
+ $expire_notify = ADODB_Session::expireNotify();
+ $optimize = ADODB_Session::optimize();
+ $table = ADODB_Session::table();
+
+ if (!$conn) {
+ return false;
+ }
+
+ //assert('$table');
+
+ $time = $conn->sysTimeStamp;
+ $binary = $conn->dataProvider === 'mysql' ? '/*! BINARY */' : '';
+
+ if ($expire_notify) {
+ reset($expire_notify);
+ $fn = next($expire_notify);
+ $savem = $conn->SetFetchMode(ADODB_FETCH_NUM);
+ $sql = "SELECT expireref, sesskey FROM $table WHERE expiry < $time";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ $conn->SetFetchMode($savem);
+ if ($rs) {
+ $conn->StartTrans();
+ $keys = array();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref, $key);
+ $del = $conn->Execute("DELETE FROM $table WHERE sesskey=".$conn->Param('0'),array($key));
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $conn->CompleteTrans();
+ }
+ } else {
+
+ if (0) {
+ $sql = "SELECT sesskey FROM $table WHERE expiry < $time";
+ $arr =& $conn->GetAll($sql);
+ foreach ($arr as $row) {
+ $sql2 = "DELETE FROM $table WHERE sesskey=".$conn->Param('0');
+ $conn->Execute($sql2,array($row[0]));
+ }
+ } else {
+ $sql = "DELETE FROM $table WHERE expiry < $time";
+ $rs =& $conn->Execute($sql);
+ ADODB_Session::_dumprs($rs);
+ if ($rs) $rs->Close();
+ }
+ if ($debug) {
+ ADOConnection::outp("<p><b>Garbage Collection</b>: $sql</p>");
+ }
+ }
+
+ // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+ if ($optimize) {
+ $driver = ADODB_Session::driver();
+
+ if (preg_match('/mysql/i', $driver)) {
+ $sql = "OPTIMIZE TABLE $table";
+ }
+ if (preg_match('/postgres/i', $driver)) {
+ $sql = "VACUUM $table";
+ }
+ if (!empty($sql)) {
+ $conn->Execute($sql);
+ }
+ }
+
+
+ return true;
+ }
+}
+
+ADODB_Session::_init();
+if (empty($ADODB_SESSION_READONLY))
+ register_shutdown_function('session_write_close');
+
+// for backwards compatability only
+function adodb_sess_open($save_path, $session_name, $persist = true) {
+ return ADODB_Session::open($save_path, $session_name, $persist);
+}
+
+// for backwards compatability only
+function adodb_sess_gc($t)
+{
+ return ADODB_Session::gc($t);
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/crypt.inc.php b/lib/adodb/session/crypt.inc.php
new file mode 100644
index 0000000..41cb06a
--- /dev/null
+++ b/lib/adodb/session/crypt.inc.php
@@ -0,0 +1,161 @@
+<?php
+// Session Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com>
+class MD5Crypt{
+ function keyED($txt,$encrypt_key)
+ {
+ $encrypt_key = md5($encrypt_key);
+ $ctr=0;
+ $tmp = "";
+ for ($i=0;$i<strlen($txt);$i++){
+ if ($ctr==strlen($encrypt_key)) $ctr=0;
+ $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1);
+ $ctr++;
+ }
+ return $tmp;
+ }
+
+ function Encrypt($txt,$key)
+ {
+ srand((double)microtime()*1000000);
+ $encrypt_key = md5(rand(0,32000));
+ $ctr=0;
+ $tmp = "";
+ for ($i=0;$i<strlen($txt);$i++)
+ {
+ if ($ctr==strlen($encrypt_key)) $ctr=0;
+ $tmp.= substr($encrypt_key,$ctr,1) .
+ (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1));
+ $ctr++;
+ }
+ return base64_encode($this->keyED($tmp,$key));
+ }
+
+ function Decrypt($txt,$key)
+ {
+ $txt = $this->keyED(base64_decode($txt),$key);
+ $tmp = "";
+ for ($i=0;$i<strlen($txt);$i++){
+ $md5 = substr($txt,$i,1);
+ $i++;
+ $tmp.= (substr($txt,$i,1) ^ $md5);
+ }
+ return $tmp;
+ }
+
+ function RandPass()
+ {
+ $randomPassword = "";
+ srand((double)microtime()*1000000);
+ for($i=0;$i<8;$i++)
+ {
+ $randnumber = rand(48,120);
+
+ while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96))
+ {
+ $randnumber = rand(48,120);
+ }
+
+ $randomPassword .= chr($randnumber);
+ }
+ return $randomPassword;
+ }
+
+}
+
+
+class SHA1Crypt{
+
+ function keyED($txt,$encrypt_key)
+ {
+
+ $encrypt_key = sha1($encrypt_key);
+ $ctr=0;
+ $tmp = "";
+
+ for ($i=0;$i<strlen($txt);$i++){
+ if ($ctr==strlen($encrypt_key)) $ctr=0;
+ $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1);
+ $ctr++;
+ }
+ return $tmp;
+
+ }
+
+
+
+ function Encrypt($txt,$key)
+ {
+
+ srand((double)microtime()*1000000);
+ $encrypt_key = sha1(rand(0,32000));
+ $ctr=0;
+ $tmp = "";
+
+ for ($i=0;$i<strlen($txt);$i++)
+
+ {
+
+ if ($ctr==strlen($encrypt_key)) $ctr=0;
+
+ $tmp.= substr($encrypt_key,$ctr,1) .
+
+ (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1));
+
+ $ctr++;
+
+ }
+
+ return base64_encode($this->keyED($tmp,$key));
+
+ }
+
+
+
+ function Decrypt($txt,$key)
+ {
+
+ $txt = $this->keyED(base64_decode($txt),$key);
+
+ $tmp = "";
+
+ for ($i=0;$i<strlen($txt);$i++){
+
+ $sha1 = substr($txt,$i,1);
+
+ $i++;
+
+ $tmp.= (substr($txt,$i,1) ^ $sha1);
+
+ }
+
+ return $tmp;
+ }
+
+
+
+ function RandPass()
+ {
+ $randomPassword = "";
+ srand((double)microtime()*1000000);
+
+ for($i=0;$i<8;$i++)
+ {
+
+ $randnumber = rand(48,120);
+
+ while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96))
+ {
+ $randnumber = rand(48,120);
+ }
+
+ $randomPassword .= chr($randnumber);
+ }
+
+ return $randomPassword;
+
+ }
+
+
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/session/old/adodb-cryptsession.php b/lib/adodb/session/old/adodb-cryptsession.php
new file mode 100644
index 0000000..40ce283
--- /dev/null
+++ b/lib/adodb/session/old/adodb-cryptsession.php
@@ -0,0 +1,324 @@
+<?php
+/*
+V4.94 23 Jan 2007 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Made table name configurable - by David Johnson djohnson@inpro.net
+ Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com>
+
+ Set tabs to 4 for best viewing.
+
+ Latest version of ADODB is available at http://php.weblogs.com/adodb
+ ======================================================================
+
+ This file provides PHP4 session management using the ADODB database
+wrapper library.
+
+ Example
+ =======
+
+ include('adodb.inc.php');
+ #---------------------------------#
+ include('adodb-cryptsession.php');
+ #---------------------------------#
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+
+ Installation
+ ============
+ 1. Create a new database in MySQL or Access "sessions" like
+so:
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA CLOB,
+ primary key (sesskey)
+ );
+
+ 2. Then define the following parameters. You can either modify
+ this file, or define them before this file is included:
+
+ $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+ $ADODB_SESSION_CONNECT='server to connect to';
+ $ADODB_SESSION_USER ='user';
+ $ADODB_SESSION_PWD ='password';
+ $ADODB_SESSION_DB ='database';
+ $ADODB_SESSION_TBL = 'sessions'
+
+ 3. Recommended is PHP 4.0.2 or later. There are documented
+session bugs in earlier versions of PHP.
+
+*/
+
+
+include_once('crypt.inc.php');
+
+if (!defined('_ADODB_LAYER')) {
+ include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60);
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESS_INSERT,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_TBL;
+
+ //$ADODB_SESS_DEBUG = true;
+
+ /* SET THE FOLLOWING PARAMETERS */
+if (empty($ADODB_SESSION_DRIVER)) {
+ $ADODB_SESSION_DRIVER='mysql';
+ $ADODB_SESSION_CONNECT='localhost';
+ $ADODB_SESSION_USER ='root';
+ $ADODB_SESSION_PWD ='';
+ $ADODB_SESSION_DB ='xphplens_2';
+}
+
+if (empty($ADODB_SESSION_TBL)){
+ $ADODB_SESSION_TBL = 'sessions';
+}
+
+if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+ $ADODB_SESSION_EXPIRE_NOTIFY = false;
+}
+
+function ADODB_Session_Key()
+{
+$ADODB_CRYPT_KEY = 'CRYPTED ADODB SESSIONS ROCK!';
+
+ /* USE THIS FUNCTION TO CREATE THE ENCRYPTION KEY FOR CRYPTED SESSIONS */
+ /* Crypt the used key, $ADODB_CRYPT_KEY as key and session_ID as SALT */
+ return crypt($ADODB_CRYPT_KEY, session_ID());
+}
+
+$ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+if ($ADODB_SESS_LIFE <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";
+ $ADODB_SESS_LIFE=1440;
+}
+
+function adodb_sess_open($save_path, $session_name)
+{
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_DEBUG;
+
+ $ADODB_SESS_INSERT = false;
+
+ if (isset($ADODB_SESS_CONN)) return true;
+
+ $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+ if (!empty($ADODB_SESS_DEBUG)) {
+ $ADODB_SESS_CONN->debug = true;
+ print" conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ";
+ }
+ return $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+
+}
+
+function adodb_sess_close()
+{
+global $ADODB_SESS_CONN;
+
+ if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+ return true;
+}
+
+function adodb_sess_read($key)
+{
+$Crypt = new MD5Crypt;
+global $ADODB_SESS_CONN,$ADODB_SESS_INSERT,$ADODB_SESSION_TBL;
+ $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+ if ($rs) {
+ if ($rs->EOF) {
+ $ADODB_SESS_INSERT = true;
+ $v = '';
+ } else {
+ // Decrypt session data
+ $v = rawurldecode($Crypt->Decrypt(reset($rs->fields), ADODB_Session_Key()));
+ }
+ $rs->Close();
+ return $v;
+ }
+ else $ADODB_SESS_INSERT = true;
+
+ return '';
+}
+
+function adodb_sess_write($key, $val)
+{
+$Crypt = new MD5Crypt;
+ global $ADODB_SESS_INSERT,$ADODB_SESS_CONN, $ADODB_SESS_LIFE, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ $expiry = time() + $ADODB_SESS_LIFE;
+
+ // encrypt session data..
+ $val = $Crypt->Encrypt(rawurlencode($val), ADODB_Session_Key());
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ global $$var;
+ $arr['expireref'] = $$var;
+ }
+ $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,
+ $arr,
+ 'sesskey',$autoQuote = true);
+
+ if (!$rs) {
+ ADOConnection::outp( '
+-- Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'</p>',false);
+ } else {
+ // bug in access driver (could be odbc?) means that info is not commited
+ // properly unless select statement executed in Win2000
+
+ if ($ADODB_SESS_CONN->databaseType == 'access') $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ }
+ return isset($rs);
+}
+
+function adodb_sess_destroy($key)
+{
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ }
+ return $rs ? true : false;
+}
+
+
+function adodb_sess_gc($maxlifetime) {
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY,$ADODB_SESS_DEBUG;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $t = time();
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ //$del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();
+ $ADODB_SESS_CONN->Execute($qry);
+ }
+
+ // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+ if (defined('ADODB_SESSION_OPTIMIZE'))
+ {
+ global $ADODB_SESSION_DRIVER;
+
+ switch( $ADODB_SESSION_DRIVER ) {
+ case 'mysql':
+ case 'mysqlt':
+ $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+ break;
+ case 'postgresql':
+ case 'postgresql7':
+ $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;
+ break;
+ }
+ }
+
+ if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+ else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+
+ $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1);
+ if ($rs && !$rs->EOF) {
+
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+ $t = time();
+ if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+ $msg =
+ __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+ error_log($msg);
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg</p>");
+ }
+ }
+
+ return true;
+}
+
+session_module_name('user');
+session_set_save_handler(
+ "adodb_sess_open",
+ "adodb_sess_close",
+ "adodb_sess_read",
+ "adodb_sess_write",
+ "adodb_sess_destroy",
+ "adodb_sess_gc");
+}
+
+/* TEST SCRIPT -- UNCOMMENT */
+/*
+if (0) {
+
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+}
+*/
+?>
diff --git a/lib/adodb/session/old/adodb-session-clob.php b/lib/adodb/session/old/adodb-session-clob.php
new file mode 100644
index 0000000..788e184
--- /dev/null
+++ b/lib/adodb/session/old/adodb-session-clob.php
@@ -0,0 +1,448 @@
+<?php
+/*
+ V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+ Latest version of ADODB is available at http://php.weblogs.com/adodb
+ ======================================================================
+
+ This file provides PHP4 session management using the ADODB database
+ wrapper library, using Oracle CLOB's to store data. Contributed by achim.gosse@ddd.de.
+
+ Example
+ =======
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ adodb_session_open(false,false,false);
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+
+ Installation
+ ============
+ 1. Create this table in your database (syntax might vary depending on your db):
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA CLOB,
+ primary key (sesskey)
+ );
+
+
+ 2. Then define the following parameters in this file:
+ $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+ $ADODB_SESSION_CONNECT='server to connect to';
+ $ADODB_SESSION_USER ='user';
+ $ADODB_SESSION_PWD ='password';
+ $ADODB_SESSION_DB ='database';
+ $ADODB_SESSION_TBL = 'sessions'
+ $ADODB_SESSION_USE_LOBS = false; (or, if you wanna use CLOBS (= 'CLOB') or ( = 'BLOB')
+
+ 3. Recommended is PHP 4.1.0 or later. There are documented
+ session bugs in earlier versions of PHP.
+
+ 4. If you want to receive notifications when a session expires, then
+ you can tag a session with an EXPIREREF, and before the session
+ record is deleted, we can call a function that will pass the EXPIREREF
+ as the first parameter, and the session key as the second parameter.
+
+ To do this, define a notification function, say NotifyFn:
+
+ function NotifyFn($expireref, $sesskey)
+ {
+ }
+
+ Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY.
+ This is an array with 2 elements, the first being the name of the variable
+ you would like to store in the EXPIREREF field, and the 2nd is the
+ notification function's name.
+
+ In this example, we want to be notified when a user's session
+ has expired, so we store the user id in the global variable $USERID,
+ store this value in the EXPIREREF field:
+
+ $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+
+ Then when the NotifyFn is called, we are passed the $USERID as the first
+ parameter, eg. NotifyFn($userid, $sesskey).
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60);
+
+/****************************************************************************************\
+ Global definitions
+\****************************************************************************************/
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_USE_LOBS,
+ $ADODB_SESSION_TBL;
+
+ if (!isset($ADODB_SESSION_USE_LOBS)) $ADODB_SESSION_USE_LOBS = 'CLOB';
+
+ $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+ if ($ADODB_SESS_LIFE <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";
+ $ADODB_SESS_LIFE=1440;
+ }
+ $ADODB_SESSION_CRC = false;
+ //$ADODB_SESS_DEBUG = true;
+
+ //////////////////////////////////
+ /* SET THE FOLLOWING PARAMETERS */
+ //////////////////////////////////
+
+ if (empty($ADODB_SESSION_DRIVER)) {
+ $ADODB_SESSION_DRIVER='mysql';
+ $ADODB_SESSION_CONNECT='localhost';
+ $ADODB_SESSION_USER ='root';
+ $ADODB_SESSION_PWD ='';
+ $ADODB_SESSION_DB ='xphplens_2';
+ }
+
+ if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+ $ADODB_SESSION_EXPIRE_NOTIFY = false;
+ }
+ // Made table name configurable - by David Johnson djohnson@inpro.net
+ if (empty($ADODB_SESSION_TBL)){
+ $ADODB_SESSION_TBL = 'sessions';
+ }
+
+
+ // defaulting $ADODB_SESSION_USE_LOBS
+ if (!isset($ADODB_SESSION_USE_LOBS) || empty($ADODB_SESSION_USE_LOBS)) {
+ $ADODB_SESSION_USE_LOBS = false;
+ }
+
+ /*
+ $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;
+ $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;
+ $ADODB_SESS['user'] = $ADODB_SESSION_USER;
+ $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;
+ $ADODB_SESS['db'] = $ADODB_SESSION_DB;
+ $ADODB_SESS['life'] = $ADODB_SESS_LIFE;
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+ $ADODB_SESS['table'] = $ADODB_SESS_TBL;
+ */
+
+/****************************************************************************************\
+ Create the connection to the database.
+
+ If $ADODB_SESS_CONN already exists, reuse that connection
+\****************************************************************************************/
+function adodb_sess_open($save_path, $session_name,$persist=true)
+{
+GLOBAL $ADODB_SESS_CONN;
+ if (isset($ADODB_SESS_CONN)) return true;
+
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_DEBUG;
+
+ // cannot use & below - do not know why...
+ $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+ if (!empty($ADODB_SESS_DEBUG)) {
+ $ADODB_SESS_CONN->debug = true;
+ ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");
+ }
+ if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+ else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+
+ if (!$ok) ADOConnection::outp( "
+-- Session: connection failed</p>",false);
+}
+
+/****************************************************************************************\
+ Close the connection
+\****************************************************************************************/
+function adodb_sess_close()
+{
+global $ADODB_SESS_CONN;
+
+ if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+ return true;
+}
+
+/****************************************************************************************\
+ Slurp in the session variables and return the serialized string
+\****************************************************************************************/
+function adodb_sess_read($key)
+{
+global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;
+
+ $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+ if ($rs) {
+ if ($rs->EOF) {
+ $v = '';
+ } else
+ $v = rawurldecode(reset($rs->fields));
+
+ $rs->Close();
+
+ // new optimization adodb 2.1
+ $ADODB_SESSION_CRC = strlen($v).crc32($v);
+
+ return $v;
+ }
+
+ return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com
+}
+
+/****************************************************************************************\
+ Write the serialized data to a database.
+
+ If the data has not been modified since adodb_sess_read(), we do not write.
+\****************************************************************************************/
+function adodb_sess_write($key, $val)
+{
+ global
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESSION_TBL,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_DRIVER, // added
+ $ADODB_SESSION_USE_LOBS; // added
+
+ $expiry = time() + $ADODB_SESS_LIFE;
+
+ // crc32 optimization since adodb 2.1
+ // now we only update expiry date, thx to sebastian thom in adodb 2.32
+ if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {
+ if ($ADODB_SESS_DEBUG) echo "
+-- Session: Only updating date - crc32 not changed</p>";
+ $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ return true;
+ }
+ $val = rawurlencode($val);
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ global $$var;
+ $arr['expireref'] = $$var;
+ }
+
+
+ if ($ADODB_SESSION_USE_LOBS === false) { // no lobs, simply use replace()
+ $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr, 'sesskey',$autoQuote = true);
+ if (!$rs) {
+ $err = $ADODB_SESS_CONN->ErrorMsg();
+ }
+ } else {
+ // what value shall we insert/update for lob row?
+ switch ($ADODB_SESSION_DRIVER) {
+ // empty_clob or empty_lob for oracle dbs
+ case "oracle":
+ case "oci8":
+ case "oci8po":
+ case "oci805":
+ $lob_value = sprintf("empty_%s()", strtolower($ADODB_SESSION_USE_LOBS));
+ break;
+
+ // null for all other
+ default:
+ $lob_value = "null";
+ break;
+ }
+
+ // do we insert or update? => as for sesskey
+ $res = $ADODB_SESS_CONN->Execute("select count(*) as cnt from $ADODB_SESSION_TBL where sesskey = '$key'");
+ if ($res && reset($res->fields) > 0) {
+ $qry = sprintf("update %s set expiry = %d, data = %s where sesskey = '%s'", $ADODB_SESSION_TBL, $expiry, $lob_value, $key);
+ } else {
+ // insert
+ $qry = sprintf("insert into %s (sesskey, expiry, data) values ('%s', %d, %s)", $ADODB_SESSION_TBL, $key, $expiry, $lob_value);
+ }
+
+ $err = "";
+ $rs1 = $ADODB_SESS_CONN->Execute($qry);
+ if (!$rs1) {
+ $err .= $ADODB_SESS_CONN->ErrorMsg()."\n";
+ }
+ $rs2 = $ADODB_SESS_CONN->UpdateBlob($ADODB_SESSION_TBL, 'data', $val, "sesskey='$key'", strtoupper($ADODB_SESSION_USE_LOBS));
+ if (!$rs2) {
+ $err .= $ADODB_SESS_CONN->ErrorMsg()."\n";
+ }
+ $rs = ($rs1 && $rs2) ? true : false;
+ }
+
+ if (!$rs) {
+ ADOConnection::outp( '
+-- Session Replace: '.nl2br($err).'</p>',false);
+ } else {
+ // bug in access driver (could be odbc?) means that info is not commited
+ // properly unless select statement executed in Win2000
+ if ($ADODB_SESS_CONN->databaseType == 'access')
+ $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ }
+ return !empty($rs);
+}
+
+function adodb_sess_destroy($key)
+{
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ }
+ return $rs ? true : false;
+}
+
+function adodb_sess_gc($maxlifetime)
+{
+ global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $t = time();
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ //$ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->CommitTrans();
+
+ }
+ } else {
+ $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time());
+
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- <b>Garbage Collection</b>: $qry</p>");
+ }
+ // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+ if (defined('ADODB_SESSION_OPTIMIZE')) {
+ global $ADODB_SESSION_DRIVER;
+
+ switch( $ADODB_SESSION_DRIVER ) {
+ case 'mysql':
+ case 'mysqlt':
+ $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+ break;
+ case 'postgresql':
+ case 'postgresql7':
+ $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;
+ break;
+ }
+ if (!empty($opt_qry)) {
+ $ADODB_SESS_CONN->Execute($opt_qry);
+ }
+ }
+ if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+ else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+
+ $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1);
+ if ($rs && !$rs->EOF) {
+
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+ $t = time();
+ if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+ $msg =
+ __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+ error_log($msg);
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg</p>");
+ }
+ }
+
+ return true;
+}
+
+session_module_name('user');
+session_set_save_handler(
+ "adodb_sess_open",
+ "adodb_sess_close",
+ "adodb_sess_read",
+ "adodb_sess_write",
+ "adodb_sess_destroy",
+ "adodb_sess_gc");
+}
+
+/* TEST SCRIPT -- UNCOMMENT */
+
+if (0) {
+
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ ADOConnection::outp( "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>",false);
+}
+
+?>
diff --git a/lib/adodb/session/old/adodb-session.php b/lib/adodb/session/old/adodb-session.php
new file mode 100644
index 0000000..6fc9b2f
--- /dev/null
+++ b/lib/adodb/session/old/adodb-session.php
@@ -0,0 +1,439 @@
+<?php
+/*
+V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+ Set tabs to 4 for best viewing.
+
+ Latest version of ADODB is available at http://php.weblogs.com/adodb
+ ======================================================================
+
+ This file provides PHP4 session management using the ADODB database
+wrapper library.
+
+ Example
+ =======
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ adodb_sess_open(false,false,false);
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>";
+
+
+ Installation
+ ============
+ 1. Create this table in your database (syntax might vary depending on your db):
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA text not null,
+ primary key (sesskey)
+ );
+
+ For oracle:
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY DECIMAL(16) not null,
+ EXPIREREF varchar(64),
+ DATA varchar(4000) not null,
+ primary key (sesskey)
+ );
+
+
+ 2. Then define the following parameters. You can either modify
+ this file, or define them before this file is included:
+
+ $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+ $ADODB_SESSION_CONNECT='server to connect to';
+ $ADODB_SESSION_USER ='user';
+ $ADODB_SESSION_PWD ='password';
+ $ADODB_SESSION_DB ='database';
+ $ADODB_SESSION_TBL = 'sessions'
+
+ 3. Recommended is PHP 4.1.0 or later. There are documented
+ session bugs in earlier versions of PHP.
+
+ 4. If you want to receive notifications when a session expires, then
+ you can tag a session with an EXPIREREF, and before the session
+ record is deleted, we can call a function that will pass the EXPIREREF
+ as the first parameter, and the session key as the second parameter.
+
+ To do this, define a notification function, say NotifyFn:
+
+ function NotifyFn($expireref, $sesskey)
+ {
+ }
+
+ Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY.
+ This is an array with 2 elements, the first being the name of the variable
+ you would like to store in the EXPIREREF field, and the 2nd is the
+ notification function's name.
+
+ In this example, we want to be notified when a user's session
+ has expired, so we store the user id in the global variable $USERID,
+ store this value in the EXPIREREF field:
+
+ $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+
+ Then when the NotifyFn is called, we are passed the $USERID as the first
+ parameter, eg. NotifyFn($userid, $sesskey).
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60);
+
+ /*
+ Thanks Joe Li. See http://phplens.com/lens/lensforum/msgs.php?id=11487&x=1
+*/
+function adodb_session_regenerate_id()
+{
+ $conn =& ADODB_Session::_conn();
+ if (!$conn) return false;
+
+ $old_id = session_id();
+ if (function_exists('session_regenerate_id')) {
+ session_regenerate_id();
+ } else {
+ session_id(md5(uniqid(rand(), true)));
+ $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ //@session_start();
+ }
+ $new_id = session_id();
+ $ok =& $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id));
+
+ /* it is possible that the update statement fails due to a collision */
+ if (!$ok) {
+ session_id($old_id);
+ if (empty($ck)) $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************************\
+ Global definitions
+\****************************************************************************************/
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_TBL;
+
+
+ $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+ if ($ADODB_SESS_LIFE <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "<h3>Session Error: PHP.INI setting <i>session.gc_maxlifetime</i>not set: $ADODB_SESS_LIFE</h3>";
+ $ADODB_SESS_LIFE=1440;
+ }
+ $ADODB_SESSION_CRC = false;
+ //$ADODB_SESS_DEBUG = true;
+
+ //////////////////////////////////
+ /* SET THE FOLLOWING PARAMETERS */
+ //////////////////////////////////
+
+ if (empty($ADODB_SESSION_DRIVER)) {
+ $ADODB_SESSION_DRIVER='mysql';
+ $ADODB_SESSION_CONNECT='localhost';
+ $ADODB_SESSION_USER ='root';
+ $ADODB_SESSION_PWD ='';
+ $ADODB_SESSION_DB ='xphplens_2';
+ }
+
+ if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+ $ADODB_SESSION_EXPIRE_NOTIFY = false;
+ }
+ // Made table name configurable - by David Johnson djohnson@inpro.net
+ if (empty($ADODB_SESSION_TBL)){
+ $ADODB_SESSION_TBL = 'sessions';
+ }
+
+ /*
+ $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;
+ $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;
+ $ADODB_SESS['user'] = $ADODB_SESSION_USER;
+ $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;
+ $ADODB_SESS['db'] = $ADODB_SESSION_DB;
+ $ADODB_SESS['life'] = $ADODB_SESS_LIFE;
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+ $ADODB_SESS['table'] = $ADODB_SESS_TBL;
+ */
+
+/****************************************************************************************\
+ Create the connection to the database.
+
+ If $ADODB_SESS_CONN already exists, reuse that connection
+\****************************************************************************************/
+function adodb_sess_open($save_path, $session_name,$persist=true)
+{
+GLOBAL $ADODB_SESS_CONN;
+ if (isset($ADODB_SESS_CONN)) return true;
+
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_DEBUG;
+
+ // cannot use & below - do not know why...
+ $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+ if (!empty($ADODB_SESS_DEBUG)) {
+ $ADODB_SESS_CONN->debug = true;
+ ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");
+ }
+ if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+ else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+
+ if (!$ok) ADOConnection::outp( "
+-- Session: connection failed</p>",false);
+}
+
+/****************************************************************************************\
+ Close the connection
+\****************************************************************************************/
+function adodb_sess_close()
+{
+global $ADODB_SESS_CONN;
+
+ if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+ return true;
+}
+
+/****************************************************************************************\
+ Slurp in the session variables and return the serialized string
+\****************************************************************************************/
+function adodb_sess_read($key)
+{
+global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;
+
+ $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+ if ($rs) {
+ if ($rs->EOF) {
+ $v = '';
+ } else
+ $v = rawurldecode(reset($rs->fields));
+
+ $rs->Close();
+
+ // new optimization adodb 2.1
+ $ADODB_SESSION_CRC = strlen($v).crc32($v);
+
+ return $v;
+ }
+
+ return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com
+}
+
+/****************************************************************************************\
+ Write the serialized data to a database.
+
+ If the data has not been modified since adodb_sess_read(), we do not write.
+\****************************************************************************************/
+function adodb_sess_write($key, $val)
+{
+ global
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESSION_TBL,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_EXPIRE_NOTIFY;
+
+ $expiry = time() + $ADODB_SESS_LIFE;
+
+ // crc32 optimization since adodb 2.1
+ // now we only update expiry date, thx to sebastian thom in adodb 2.32
+ if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {
+ if ($ADODB_SESS_DEBUG) echo "
+-- Session: Only updating date - crc32 not changed</p>";
+ $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ return true;
+ }
+ $val = rawurlencode($val);
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ global $$var;
+ $arr['expireref'] = $$var;
+ }
+ $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr,
+ 'sesskey',$autoQuote = true);
+
+ if (!$rs) {
+ ADOConnection::outp( '
+-- Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'</p>',false);
+ } else {
+ // bug in access driver (could be odbc?) means that info is not commited
+ // properly unless select statement executed in Win2000
+ if ($ADODB_SESS_CONN->databaseType == 'access')
+ $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ }
+ return !empty($rs);
+}
+
+function adodb_sess_destroy($key)
+{
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ }
+ return $rs ? true : false;
+}
+
+function adodb_sess_gc($maxlifetime)
+{
+ global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $t = time();
+ $rs =& $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $ADODB_SESS_CONN->CommitTrans();
+
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();
+ $ADODB_SESS_CONN->Execute($qry);
+
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- <b>Garbage Collection</b>: $qry</p>");
+ }
+ // suggested by Cameron, "GaM3R" <gamr@outworld.cx>
+ if (defined('ADODB_SESSION_OPTIMIZE')) {
+ global $ADODB_SESSION_DRIVER;
+
+ switch( $ADODB_SESSION_DRIVER ) {
+ case 'mysql':
+ case 'mysqlt':
+ $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+ break;
+ case 'postgresql':
+ case 'postgresql7':
+ $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;
+ break;
+ }
+ if (!empty($opt_qry)) {
+ $ADODB_SESS_CONN->Execute($opt_qry);
+ }
+ }
+ if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+ else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+
+ $rs =& $ADODB_SESS_CONN->SelectLimit($sql,1);
+ if ($rs && !$rs->EOF) {
+
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+ $t = time();
+
+ if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+
+ $msg =
+ __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+ error_log($msg);
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg</p>");
+ }
+ }
+
+ return true;
+}
+
+session_module_name('user');
+session_set_save_handler(
+ "adodb_sess_open",
+ "adodb_sess_close",
+ "adodb_sess_read",
+ "adodb_sess_write",
+ "adodb_sess_destroy",
+ "adodb_sess_gc");
+}
+
+/* TEST SCRIPT -- UNCOMMENT */
+
+if (0) {
+
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ ADOConnection::outp( "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}</p>",false);
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/session/old/crypt.inc.php b/lib/adodb/session/old/crypt.inc.php
new file mode 100644
index 0000000..b99bbba
--- /dev/null
+++ b/lib/adodb/session/old/crypt.inc.php
@@ -0,0 +1,64 @@
+<?php
+// Session Encryption by Ari Kuorikoski <ari.kuorikoski@finebyte.com>
+class MD5Crypt{
+ function keyED($txt,$encrypt_key)
+ {
+ $encrypt_key = md5($encrypt_key);
+ $ctr=0;
+ $tmp = "";
+ for ($i=0;$i<strlen($txt);$i++){
+ if ($ctr==strlen($encrypt_key)) $ctr=0;
+ $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1);
+ $ctr++;
+ }
+ return $tmp;
+ }
+
+ function Encrypt($txt,$key)
+ {
+ srand((double)microtime()*1000000);
+ $encrypt_key = md5(rand(0,32000));
+ $ctr=0;
+ $tmp = "";
+ for ($i=0;$i<strlen($txt);$i++)
+ {
+ if ($ctr==strlen($encrypt_key)) $ctr=0;
+ $tmp.= substr($encrypt_key,$ctr,1) .
+ (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1));
+ $ctr++;
+ }
+ return base64_encode($this->keyED($tmp,$key));
+ }
+
+ function Decrypt($txt,$key)
+ {
+ $txt = $this->keyED(base64_decode($txt),$key);
+ $tmp = "";
+ for ($i=0;$i<strlen($txt);$i++){
+ $md5 = substr($txt,$i,1);
+ $i++;
+ $tmp.= (substr($txt,$i,1) ^ $md5);
+ }
+ return $tmp;
+ }
+
+ function RandPass()
+ {
+ $randomPassword = "";
+ srand((double)microtime()*1000000);
+ for($i=0;$i<8;$i++)
+ {
+ $randnumber = rand(48,120);
+
+ while (($randnumber >= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96))
+ {
+ $randnumber = rand(48,120);
+ }
+
+ $randomPassword .= chr($randnumber);
+ }
+ return $randomPassword;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/session/session_schema.xml b/lib/adodb/session/session_schema.xml
new file mode 100644
index 0000000..3c61ff6
--- /dev/null
+++ b/lib/adodb/session/session_schema.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<schema version="0.2">
+ <table name="sessions">
+ <desc>table for ADOdb session-management</desc>
+
+ <field name="SESSKEY" type="C" size="32">
+ <descr>session key</descr>
+ <KEY/>
+ <NOTNULL/>
+ </field>
+
+ <field name="EXPIRY" type="I" size="11">
+ <descr></descr>
+ <NOTNULL/>
+ </field>
+
+ <field name="EXPIREREF" type="C" size="64">
+ <descr></descr>
+ </field>
+
+ <field name="DATA" type="XL">
+ <descr></descr>
+ <NOTNULL/>
+ </field>
+ </table>
+</schema>
diff --git a/lib/adodb/session/session_schema2.xml b/lib/adodb/session/session_schema2.xml
new file mode 100644
index 0000000..22f8daf
--- /dev/null
+++ b/lib/adodb/session/session_schema2.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<schema version="0.3">
+ <table name="sessions2">
+ <desc>table for ADOdb session-management</desc>
+
+ <field name="SESSKEY" type="C" size="64">
+ <descr>session key</descr>
+ <KEY/>
+ <NOTNULL/>
+ </field>
+
+
+
+ <field name="EXPIRY" type="T">
+ <descr></descr>
+ <NOTNULL/>
+ </field>
+
+ <field name="CREATED" type="T">
+ <descr></descr>
+ <NOTNULL/>
+ </field>
+
+ <field name="MODIFIED" type="T">
+ <descr></descr>
+ <NOTNULL/>
+ </field>
+
+ <field name="EXPIREREF" type="C" size="250">
+ <descr></descr>
+ </field>
+
+ <field name="SESSDATA" type="XL">
+ <descr></descr>
+ <NOTNULL/>
+ </field>
+ </table>
+</schema>
diff --git a/lib/adodb/toexport.inc.php b/lib/adodb/toexport.inc.php
new file mode 100644
index 0000000..ba3f37a
--- /dev/null
+++ b/lib/adodb/toexport.inc.php
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * @version V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
+ *
+ * Code to export recordsets in several formats:
+ *
+ * AS VARIABLE
+ * $s = rs2csv($rs); # comma-separated values
+ * $s = rs2tab($rs); # tab delimited
+ *
+ * TO A FILE
+ * $f = fopen($path,'w');
+ * rs2csvfile($rs,$f);
+ * fclose($f);
+ *
+ * TO STDOUT
+ * rs2csvout($rs);
+ */
+
+// returns a recordset as a csv string
+function rs2csv(&$rs,$addtitles=true)
+{
+ return _adodb_export($rs,',',',',false,$addtitles);
+}
+
+// writes recordset to csv file
+function rs2csvfile(&$rs,$fp,$addtitles=true)
+{
+ _adodb_export($rs,',',',',$fp,$addtitles);
+}
+
+// write recordset as csv string to stdout
+function rs2csvout(&$rs,$addtitles=true)
+{
+ $fp = fopen('php://stdout','wb');
+ _adodb_export($rs,',',',',true,$addtitles);
+ fclose($fp);
+}
+
+function rs2tab(&$rs,$addtitles=true)
+{
+ return _adodb_export($rs,"\t",',',false,$addtitles);
+}
+
+// to file pointer
+function rs2tabfile(&$rs,$fp,$addtitles=true)
+{
+ _adodb_export($rs,"\t",',',$fp,$addtitles);
+}
+
+// to stdout
+function rs2tabout(&$rs,$addtitles=true)
+{
+ $fp = fopen('php://stdout','wb');
+ _adodb_export($rs,"\t",' ',true,$addtitles);
+ if ($fp) fclose($fp);
+}
+
+function _adodb_export(&$rs,$sep,$sepreplace,$fp=false,$addtitles=true,$quote = '"',$escquote = '"',$replaceNewLine = ' ')
+{
+ if (!$rs) return '';
+ //----------
+ // CONSTANTS
+ $NEWLINE = "\r\n";
+ $BUFLINES = 100;
+ $escquotequote = $escquote.$quote;
+ $s = '';
+
+ if ($addtitles) {
+ $fieldTypes = $rs->FieldTypesArray();
+ reset($fieldTypes);
+ while(list(,$o) = each($fieldTypes)) {
+
+ $v = $o->name;
+ if ($escquote) $v = str_replace($quote,$escquotequote,$v);
+ $v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
+ $elements[] = $v;
+
+ }
+ $s .= implode($sep, $elements).$NEWLINE;
+ }
+ $hasNumIndex = isset($rs->fields[0]);
+
+ $line = 0;
+ $max = $rs->FieldCount();
+
+ while (!$rs->EOF) {
+ $elements = array();
+ $i = 0;
+
+ if ($hasNumIndex) {
+ for ($j=0; $j < $max; $j++) {
+ $v = $rs->fields[$j];
+ if (!is_object($v)) $v = trim($v);
+ else $v = 'Object';
+ if ($escquote) $v = str_replace($quote,$escquotequote,$v);
+ $v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
+
+ if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";
+ else $elements[] = $v;
+ }
+ } else { // ASSOCIATIVE ARRAY
+ foreach($rs->fields as $v) {
+ if ($escquote) $v = str_replace($quote,$escquotequote,trim($v));
+ $v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
+
+ if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";
+ else $elements[] = $v;
+ }
+ }
+ $s .= implode($sep, $elements).$NEWLINE;
+ $rs->MoveNext();
+ $line += 1;
+ if ($fp && ($line % $BUFLINES) == 0) {
+ if ($fp === true) echo $s;
+ else fwrite($fp,$s);
+ $s = '';
+ }
+ }
+
+ if ($fp) {
+ if ($fp === true) echo $s;
+ else fwrite($fp,$s);
+ $s = '';
+ }
+
+ return $s;
+}
+?> \ No newline at end of file
diff --git a/lib/adodb/tohtml.inc.php b/lib/adodb/tohtml.inc.php
new file mode 100644
index 0000000..b9bef03
--- /dev/null
+++ b/lib/adodb/tohtml.inc.php
@@ -0,0 +1,195 @@
+<?php
+/*
+ V4.93 10 Oct 2006 (c) 2000-2007 John Lim (jlim#natsoft.com.my). All rights reserved.
+ Released under both BSD license and Lesser GPL library license.
+ Whenever there is any discrepancy between the two licenses,
+ the BSD license will take precedence.
+
+ Some pretty-printing by Chris Oxenreider <oxenreid@state.net>
+*/
+
+// specific code for tohtml
+GLOBAL $gSQLMaxRows,$gSQLBlockRows,$ADODB_ROUND;
+
+$ADODB_ROUND=4; // rounding
+$gSQLMaxRows = 1000; // max no of rows to download
+$gSQLBlockRows=20; // max no of rows per table block
+
+// RecordSet to HTML Table
+//------------------------------------------------------------
+// Convert a recordset to a html table. Multiple tables are generated
+// if the number of rows is > $gSQLBlockRows. This is because
+// web browsers normally require the whole table to be downloaded
+// before it can be rendered, so we break the output into several
+// smaller faster rendering tables.
+//
+// $rs: the recordset
+// $ztabhtml: the table tag attributes (optional)
+// $zheaderarray: contains the replacement strings for the headers (optional)
+//
+// USAGE:
+// include('adodb.inc.php');
+// $db = ADONewConnection('mysql');
+// $db->Connect('mysql','userid','password','database');
+// $rs = $db->Execute('select col1,col2,col3 from table');
+// rs2html($rs, 'BORDER=2', array('Title1', 'Title2', 'Title3'));
+// $rs->Close();
+//
+// RETURNS: number of rows displayed
+
+
+function rs2html(&$rs,$ztabhtml=false,$zheaderarray=false,$htmlspecialchars=true,$echo = true)
+{
+$s ='';$rows=0;$docnt = false;
+GLOBAL $gSQLMaxRows,$gSQLBlockRows,$ADODB_ROUND;
+
+ if (!$rs) {
+ printf(ADODB_BAD_RS,'rs2html');
+ return false;
+ }
+
+ if (! $ztabhtml) $ztabhtml = "BORDER='1' WIDTH='98%'";
+ //else $docnt = true;
+ $typearr = array();
+ $ncols = $rs->FieldCount();
+ $hdr = "<TABLE COLS=$ncols $ztabhtml><tr>\n\n";
+ for ($i=0; $i < $ncols; $i++) {
+ $field = $rs->FetchField($i);
+ if ($field) {
+ if ($zheaderarray) $fname = $zheaderarray[$i];
+ else $fname = htmlspecialchars($field->name);
+ $typearr[$i] = $rs->MetaType($field->type,$field->max_length);
+ //print " $field->name $field->type $typearr[$i] ";
+ } else {
+ $fname = 'Field '.($i+1);
+ $typearr[$i] = 'C';
+ }
+ if (strlen($fname)==0) $fname = '&nbsp;';
+ $hdr .= "<TH>$fname</TH>";
+ }
+ $hdr .= "\n</tr>";
+ if ($echo) print $hdr."\n\n";
+ else $html = $hdr;
+
+ // smart algorithm - handles ADODB_FETCH_MODE's correctly by probing...
+ $numoffset = isset($rs->fields[0]) ||isset($rs->fields[1]) || isset($rs->fields[2]);
+ while (!$rs->EOF) {
+
+ $s .= "<TR valign=top>\n";
+
+ for ($i=0; $i < $ncols; $i++) {
+ if ($i===0) $v=($numoffset) ? $rs->fields[0] : reset($rs->fields);
+ else $v = ($numoffset) ? $rs->fields[$i] : next($rs->fields);
+
+ $type = $typearr[$i];
+ switch($type) {
+ case 'D':
+ if (empty($v)) $s .= "<TD> &nbsp; </TD>\n";
+ else if (!strpos($v,':')) {
+ $s .= " <TD>".$rs->UserDate($v,"D d, M Y") ."&nbsp;</TD>\n";
+ }
+ break;
+ case 'T':
+ if (empty($v)) $s .= "<TD> &nbsp; </TD>\n";
+ else $s .= " <TD>".$rs->UserTimeStamp($v,"D d, M Y, h:i:s") ."&nbsp;</TD>\n";
+ break;
+
+ case 'N':
+ if (abs(abs($v) - round($v,0)) < 0.00000001)
+ $v = round($v);
+ else
+ $v = round($v,$ADODB_ROUND);
+ case 'I':
+ $s .= " <TD align=right>".stripslashes((trim($v))) ."&nbsp;</TD>\n";
+
+ break;
+ /*
+ case 'B':
+ if (substr($v,8,2)=="BM" ) $v = substr($v,8);
+ $mtime = substr(str_replace(' ','_',microtime()),2);
+ $tmpname = "tmp/".uniqid($mtime).getmypid();
+ $fd = @fopen($tmpname,'a');
+ @ftruncate($fd,0);
+ @fwrite($fd,$v);
+ @fclose($fd);
+ if (!function_exists ("mime_content_type")) {
+ function mime_content_type ($file) {
+ return exec("file -bi ".escapeshellarg($file));
+ }
+ }
+ $t = mime_content_type($tmpname);
+ $s .= (substr($t,0,5)=="image") ? " <td><img src='$tmpname' alt='$t'></td>\\n" : " <td><a
+ href='$tmpname'>$t</a></td>\\n";
+ break;
+ */
+
+ default:
+ if ($htmlspecialchars) $v = htmlspecialchars(trim($v));
+ $v = trim($v);
+ if (strlen($v) == 0) $v = '&nbsp;';
+ $s .= " <TD>". str_replace("\n",'<br>',stripslashes($v)) ."</TD>\n";
+
+ }
+ } // for
+ $s .= "</TR>\n\n";
+
+ $rows += 1;
+ if ($rows >= $gSQLMaxRows) {
+ $rows = "<p>Truncated at $gSQLMaxRows</p>";
+ break;
+ } // switch
+
+ $rs->MoveNext();
+
+ // additional EOF check to prevent a widow header
+ if (!$rs->EOF && $rows % $gSQLBlockRows == 0) {
+
+ //if (connection_aborted()) break;// not needed as PHP aborts script, unlike ASP
+ if ($echo) print $s . "</TABLE>\n\n";
+ else $html .= $s ."</TABLE>\n\n";
+ $s = $hdr;
+ }
+ } // while
+
+ if ($echo) print $s."</TABLE>\n\n";
+ else $html .= $s."</TABLE>\n\n";
+
+ if ($docnt) if ($echo) print "<H2>".$rows." Rows</H2>";
+
+ return ($echo) ? $rows : $html;
+ }
+
+// pass in 2 dimensional array
+function arr2html(&$arr,$ztabhtml='',$zheaderarray='')
+{
+ if (!$ztabhtml) $ztabhtml = 'BORDER=1';
+
+ $s = "<TABLE $ztabhtml>";//';print_r($arr);
+
+ if ($zheaderarray) {
+ $s .= '<TR>';
+ for ($i=0; $i<sizeof($zheaderarray); $i++) {
+ $s .= " <TH>{$zheaderarray[$i]}</TH>\n";
+ }
+ $s .= "\n</TR>";
+ }
+
+ for ($i=0; $i<sizeof($arr); $i++) {
+ $s .= '<TR>';
+ $a = &$arr[$i];
+ if (is_array($a))
+ for ($j=0; $j<sizeof($a); $j++) {
+ $val = $a[$j];
+ if (empty($val)) $val = '&nbsp;';
+ $s .= " <TD>$val</TD>\n";
+ }
+ else if ($a) {
+ $s .= ' <TD>'.$a."</TD>\n";
+ } else $s .= " <TD>&nbsp;</TD>\n";
+ $s .= "\n</TR>\n";
+ }
+ $s .= '</TABLE>';
+ print $s;
+}
+
+?> \ No newline at end of file
diff --git a/lib/adodb/xmlschema.dtd b/lib/adodb/xmlschema.dtd
new file mode 100644
index 0000000..4a055da
--- /dev/null
+++ b/lib/adodb/xmlschema.dtd
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE adodb_schema [
+<!ELEMENT schema (table*, sql*)>
+<!ATTLIST schema version CDATA #REQUIRED>
+<!ELEMENT table ((field+|DROP), CONSTRAINT*, descr?, index*, data*)>
+<!ELEMENT field ((NOTNULL|KEY|PRIMARY)?, (AUTO|AUTOINCREMENT)?, (DEFAULT|DEFDATE|DEFTIMESTAMP)?,
+NOQUOTE?, CONSTRAINT*, descr?)>
+<!ELEMENT data (row+)>
+<!ELEMENT row (f+)>
+<!ELEMENT f (#CDATA)>
+<!ELEMENT descr (#CDATA)>
+<!ELEMENT NOTNULL EMPTY>
+<!ELEMENT KEY EMPTY>
+<!ELEMENT PRIMARY EMPTY>
+<!ELEMENT AUTO EMPTY>
+<!ELEMENT AUTOINCREMENT EMPTY>
+<!ELEMENT DEFAULT EMPTY>
+<!ELEMENT DEFDATE EMPTY>
+<!ELEMENT DEFTIMESTAMP EMPTY>
+<!ELEMENT NOQUOTE EMPTY>
+<!ELEMENT DROP EMPTY>
+<!ELEMENT CONSTRAINT (#CDATA)>
+<!ATTLIST table name CDATA #REQUIRED platform CDATA #IMPLIED version CDATA #IMPLIED>
+<!ATTLIST field name CDATA #REQUIRED type (C|C2|X|X2|B|D|T|L|I|F|N) #REQUIRED size CDATA #IMPLIED>
+<!ATTLIST data platform CDATA #IMPLIED>
+<!ATTLIST f name CDATA #IMPLIED>
+<!ATTLIST DEFAULT VALUE CDATA #REQUIRED>
+<!ELEMENT index ((col+|DROP), CLUSTERED?, BITMAP?, UNIQUE?, FULLTEXT?, HASH?, descr?)>
+<!ELEMENT col (#CDATA)>
+<!ELEMENT CLUSTERED EMPTY>
+<!ELEMENT BITMAP EMPTY>
+<!ELEMENT UNIQUE EMPTY>
+<!ELEMENT FULLTEXT EMPTY>
+<!ELEMENT HASH EMPTY>
+<!ATTLIST index name CDATA #REQUIRED platform CDATA #IMPLIED>
+<!ELEMENT sql (query+, descr?)>
+<!ELEMENT query (#CDATA)>
+<!ATTLIST sql name CDATA #IMPLIED platform CDATA #IMPLIED, key CDATA, prefixmethod (AUTO|MANUAL|NONE) >
+] > \ No newline at end of file
diff --git a/lib/adodb/xmlschema03.dtd b/lib/adodb/xmlschema03.dtd
new file mode 100644
index 0000000..a7c8864
--- /dev/null
+++ b/lib/adodb/xmlschema03.dtd
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!DOCTYPE adodb_schema [
+<!ELEMENT schema (table*, sql*)>
+<!ATTLIST schema version CDATA #REQUIRED>
+<!ELEMENT table (descr?, (field+|DROP), constraint*, opt*, index*, data*)>
+<!ATTLIST table name CDATA #REQUIRED platform CDATA #IMPLIED version CDATA #IMPLIED>
+<!ELEMENT field (descr?, (NOTNULL|KEY|PRIMARY)?, (AUTO|AUTOINCREMENT)?, (DEFAULT|DEFDATE|DEFTIMESTAMP)?, NOQUOTE?, UNSIGNED?, constraint*, opt*)>
+<!ATTLIST field name CDATA #REQUIRED type (C|C2|X|X2|B|D|T|L|I|F|N) #REQUIRED size CDATA #IMPLIED opts CDATA #IMPLIED>
+<!ELEMENT data (descr?, row+)>
+<!ATTLIST data platform CDATA #IMPLIED>
+<!ELEMENT row (f+)>
+<!ELEMENT f (#CDATA)>
+<!ATTLIST f name CDATA #IMPLIED>
+<!ELEMENT descr (#CDATA)>
+<!ELEMENT NOTNULL EMPTY>
+<!ELEMENT KEY EMPTY>
+<!ELEMENT PRIMARY EMPTY>
+<!ELEMENT AUTO EMPTY>
+<!ELEMENT AUTOINCREMENT EMPTY>
+<!ELEMENT DEFAULT EMPTY>
+<!ATTLIST DEFAULT value CDATA #REQUIRED>
+<!ELEMENT DEFDATE EMPTY>
+<!ELEMENT DEFTIMESTAMP EMPTY>
+<!ELEMENT NOQUOTE EMPTY>
+<!ELEMENT UNSIGNED EMPTY>
+<!ELEMENT DROP EMPTY>
+<!ELEMENT constraint (#CDATA)>
+<!ATTLIST constraint platform CDATA #IMPLIED>
+<!ELEMENT opt (#CDATA)>
+<!ATTLIST opt platform CDATA #IMPLIED>
+<!ELEMENT index ((col+|DROP), CLUSTERED?, BITMAP?, UNIQUE?, FULLTEXT?, HASH?, descr?)>
+<!ATTLIST index name CDATA #REQUIRED platform CDATA #IMPLIED>
+<!ELEMENT col (#CDATA)>
+<!ELEMENT CLUSTERED EMPTY>
+<!ELEMENT BITMAP EMPTY>
+<!ELEMENT UNIQUE EMPTY>
+<!ELEMENT FULLTEXT EMPTY>
+<!ELEMENT HASH EMPTY>
+<!ELEMENT sql (query+, descr?)>
+<!ATTLIST sql name CDATA #IMPLIED platform CDATA #IMPLIED, key CDATA, prefixmethod (AUTO|MANUAL|NONE)>
+<!ELEMENT query (#CDATA)>
+<!ATTLIST query platform CDATA #IMPLIED>
+]> \ No newline at end of file
diff --git a/lib/adodb/xsl/convert-0.1-0.2.xsl b/lib/adodb/xsl/convert-0.1-0.2.xsl
new file mode 100644
index 0000000..6cd9e5b
--- /dev/null
+++ b/lib/adodb/xsl/convert-0.1-0.2.xsl
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+ <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+
+ <!-- Schema -->
+ <xsl:template match="/">
+ <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+
+ <xsl:element name="schema">
+ <xsl:attribute name="version">0.2</xsl:attribute>
+
+ <xsl:apply-templates select="schema/table|schema/sql"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Table -->
+ <xsl:template match="table">
+ <xsl:variable name="table_name" select="@name"/>
+
+ <xsl:element name="table">
+ <xsl:attribute name="name"><xsl:value-of select="$table_name"/></xsl:attribute>
+
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@version) > 0">
+ <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:choose>
+ <xsl:when test="count(DROP) > 0">
+ <xsl:element name="DROP"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="field"/>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:apply-templates select="constraint"/>
+
+ <xsl:apply-templates select="../index[@table=$table_name]"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Field -->
+ <xsl:template match="field">
+ <xsl:element name="field">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+
+ <xsl:if test="string-length(@size) > 0">
+ <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="count(PRIMARY) > 0">
+ <xsl:element name="PRIMARY"/>
+ </xsl:when>
+ <xsl:when test="count(KEY) > 0">
+ <xsl:element name="KEY"/>
+ </xsl:when>
+ <xsl:when test="count(NOTNULL) > 0">
+ <xsl:element name="NOTNULL"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(AUTO) > 0">
+ <xsl:element name="AUTO"/>
+ </xsl:when>
+ <xsl:when test="count(AUTOINCREMENT) > 0">
+ <xsl:element name="AUTOINCREMENT"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(DEFAULT) > 0">
+ <xsl:element name="DEFAULT">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFAULT[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="count(DEFDATE) > 0">
+ <xsl:element name="DEFDATE">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFDATE[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="count(DEFTIMESTAMP) > 0">
+ <xsl:element name="DEFTIMESTAMP">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFTIMESTAMP[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:if test="count(NOQUOTE) > 0">
+ <xsl:element name="NOQUOTE"/>
+ </xsl:if>
+
+ <xsl:apply-templates select="constraint"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Constraint -->
+ <xsl:template match="constraint">
+ <xsl:element name="constraint">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Index -->
+ <xsl:template match="index">
+ <xsl:element name="index">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:if test="count(CLUSTERED) > 0">
+ <xsl:element name="CLUSTERED"/>
+ </xsl:if>
+
+ <xsl:if test="count(BITMAP) > 0">
+ <xsl:element name="BITMAP"/>
+ </xsl:if>
+
+ <xsl:if test="count(UNIQUE) > 0">
+ <xsl:element name="UNIQUE"/>
+ </xsl:if>
+
+ <xsl:if test="count(FULLTEXT) > 0">
+ <xsl:element name="FULLTEXT"/>
+ </xsl:if>
+
+ <xsl:if test="count(HASH) > 0">
+ <xsl:element name="HASH"/>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="count(DROP) > 0">
+ <xsl:element name="DROP"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="col"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Index Column -->
+ <xsl:template match="col">
+ <xsl:element name="col">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- SQL QuerySet -->
+ <xsl:template match="sql">
+ <xsl:element name="sql">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@key) > 0">
+ <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@prefixmethod) > 0">
+ <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+ <xsl:apply-templates select="query"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Query -->
+ <xsl:template match="query">
+ <xsl:element name="query">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Description -->
+ <xsl:template match="descr">
+ <xsl:element name="descr">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet> \ No newline at end of file
diff --git a/lib/adodb/xsl/convert-0.1-0.3.xsl b/lib/adodb/xsl/convert-0.1-0.3.xsl
new file mode 100644
index 0000000..381aa4f
--- /dev/null
+++ b/lib/adodb/xsl/convert-0.1-0.3.xsl
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+ <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+
+ <!-- Schema -->
+ <xsl:template match="/">
+ <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+
+ <xsl:element name="schema">
+ <xsl:attribute name="version">0.3</xsl:attribute>
+
+ <xsl:apply-templates select="schema/table|schema/sql"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Table -->
+ <xsl:template match="table">
+ <xsl:variable name="table_name" select="@name"/>
+
+ <xsl:element name="table">
+ <xsl:attribute name="name"><xsl:value-of select="$table_name"/></xsl:attribute>
+
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@version) > 0">
+ <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:choose>
+ <xsl:when test="count(DROP) > 0">
+ <xsl:element name="DROP"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="field"/>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:apply-templates select="constraint"/>
+
+ <xsl:apply-templates select="../index[@table=$table_name]"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Field -->
+ <xsl:template match="field">
+ <xsl:element name="field">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+
+ <xsl:if test="string-length(@size) > 0">
+ <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="string-length(@opts) = 0"/>
+ <xsl:when test="@opts = 'UNSIGNED'">
+ <xsl:element name="UNSIGNED"/>
+ </xsl:when>
+ <xsl:when test="contains(@opts,'UNSIGNED')">
+ <xsl:attribute name="opts">
+ <xsl:value-of select="concat(substring-before(@opts,'UNSIGNED'),substring-after(@opts,'UNSIGNED'))"/>
+ </xsl:attribute>
+ <xsl:element name="UNSIGNED"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="opts"><xsl:value-of select="@opts"/></xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(PRIMARY) > 0">
+ <xsl:element name="PRIMARY"/>
+ </xsl:when>
+ <xsl:when test="count(KEY) > 0">
+ <xsl:element name="KEY"/>
+ </xsl:when>
+ <xsl:when test="count(NOTNULL) > 0">
+ <xsl:element name="NOTNULL"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(AUTO) > 0">
+ <xsl:element name="AUTO"/>
+ </xsl:when>
+ <xsl:when test="count(AUTOINCREMENT) > 0">
+ <xsl:element name="AUTOINCREMENT"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(DEFAULT) > 0">
+ <xsl:element name="DEFAULT">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFAULT[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="count(DEFDATE) > 0">
+ <xsl:element name="DEFDATE">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFDATE[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="count(DEFTIMESTAMP) > 0">
+ <xsl:element name="DEFTIMESTAMP">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFTIMESTAMP[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:if test="count(NOQUOTE) > 0">
+ <xsl:element name="NOQUOTE"/>
+ </xsl:if>
+
+ <xsl:apply-templates select="constraint"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Constraint -->
+ <xsl:template match="constraint">
+ <xsl:element name="constraint">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Index -->
+ <xsl:template match="index">
+ <xsl:element name="index">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:if test="count(CLUSTERED) > 0">
+ <xsl:element name="CLUSTERED"/>
+ </xsl:if>
+
+ <xsl:if test="count(BITMAP) > 0">
+ <xsl:element name="BITMAP"/>
+ </xsl:if>
+
+ <xsl:if test="count(UNIQUE) > 0">
+ <xsl:element name="UNIQUE"/>
+ </xsl:if>
+
+ <xsl:if test="count(FULLTEXT) > 0">
+ <xsl:element name="FULLTEXT"/>
+ </xsl:if>
+
+ <xsl:if test="count(HASH) > 0">
+ <xsl:element name="HASH"/>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="count(DROP) > 0">
+ <xsl:element name="DROP"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="col"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Index Column -->
+ <xsl:template match="col">
+ <xsl:element name="col">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- SQL QuerySet -->
+ <xsl:template match="sql">
+ <xsl:element name="sql">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@key) > 0">
+ <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@prefixmethod) > 0">
+ <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+ <xsl:apply-templates select="query"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Query -->
+ <xsl:template match="query">
+ <xsl:element name="query">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Description -->
+ <xsl:template match="descr">
+ <xsl:element name="descr">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet> \ No newline at end of file
diff --git a/lib/adodb/xsl/convert-0.2-0.1.xsl b/lib/adodb/xsl/convert-0.2-0.1.xsl
new file mode 100644
index 0000000..61841b4
--- /dev/null
+++ b/lib/adodb/xsl/convert-0.2-0.1.xsl
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+ <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+
+ <!-- Schema -->
+ <xsl:template match="/">
+ <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+
+ <xsl:element name="schema">
+ <xsl:attribute name="version">0.1</xsl:attribute>
+
+ <xsl:apply-templates select="schema/table|schema/sql"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Table -->
+ <xsl:template match="table">
+ <xsl:variable name="table_name" select="@name"/>
+
+ <xsl:element name="table">
+ <xsl:attribute name="name"><xsl:value-of select="$table_name"/></xsl:attribute>
+
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@version) > 0">
+ <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:choose>
+ <xsl:when test="count(DROP) > 0">
+ <xsl:element name="DROP"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="field"/>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:apply-templates select="constraint"/>
+
+ </xsl:element>
+
+ <xsl:apply-templates select="index"/>
+ </xsl:template>
+
+ <!-- Field -->
+ <xsl:template match="field">
+ <xsl:element name="field">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+
+ <xsl:if test="string-length(@size) > 0">
+ <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="count(PRIMARY) > 0">
+ <xsl:element name="PRIMARY"/>
+ </xsl:when>
+ <xsl:when test="count(KEY) > 0">
+ <xsl:element name="KEY"/>
+ </xsl:when>
+ <xsl:when test="count(NOTNULL) > 0">
+ <xsl:element name="NOTNULL"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(AUTO) > 0">
+ <xsl:element name="AUTO"/>
+ </xsl:when>
+ <xsl:when test="count(AUTOINCREMENT) > 0">
+ <xsl:element name="AUTOINCREMENT"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(DEFAULT) > 0">
+ <xsl:element name="DEFAULT">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFAULT[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="count(DEFDATE) > 0">
+ <xsl:element name="DEFDATE">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFDATE[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="count(DEFTIMESTAMP) > 0">
+ <xsl:element name="DEFDTIMESTAMP">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFTIMESTAMP[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:if test="count(NOQUOTE) > 0">
+ <xsl:element name="NOQUOTE"/>
+ </xsl:if>
+
+ <xsl:apply-templates select="constraint"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Constraint -->
+ <xsl:template match="constraint">
+ <xsl:element name="constraint">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Index -->
+ <xsl:template match="index">
+ <xsl:element name="index">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+ <xsl:attribute name="table"><xsl:value-of select="../@name"/></xsl:attribute>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:if test="count(CLUSTERED) > 0">
+ <xsl:element name="CLUSTERED"/>
+ </xsl:if>
+
+ <xsl:if test="count(BITMAP) > 0">
+ <xsl:element name="BITMAP"/>
+ </xsl:if>
+
+ <xsl:if test="count(UNIQUE) > 0">
+ <xsl:element name="UNIQUE"/>
+ </xsl:if>
+
+ <xsl:if test="count(FULLTEXT) > 0">
+ <xsl:element name="FULLTEXT"/>
+ </xsl:if>
+
+ <xsl:if test="count(HASH) > 0">
+ <xsl:element name="HASH"/>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="count(DROP) > 0">
+ <xsl:element name="DROP"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="col"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Index Column -->
+ <xsl:template match="col">
+ <xsl:element name="col">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- SQL QuerySet -->
+ <xsl:template match="sql">
+ <xsl:element name="sql">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@key) > 0">
+ <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@prefixmethod) > 0">
+ <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+ <xsl:apply-templates select="query"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Query -->
+ <xsl:template match="query">
+ <xsl:element name="query">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Description -->
+ <xsl:template match="descr">
+ <xsl:element name="descr">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet> \ No newline at end of file
diff --git a/lib/adodb/xsl/convert-0.2-0.3.xsl b/lib/adodb/xsl/convert-0.2-0.3.xsl
new file mode 100644
index 0000000..26bd9e9
--- /dev/null
+++ b/lib/adodb/xsl/convert-0.2-0.3.xsl
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+ <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+
+ <!-- Schema -->
+ <xsl:template match="/">
+ <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+
+ <xsl:element name="schema">
+ <xsl:attribute name="version">0.3</xsl:attribute>
+
+ <xsl:apply-templates select="schema/table|schema/sql"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Table -->
+ <xsl:template match="table">
+ <xsl:element name="table">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@version) > 0">
+ <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:choose>
+ <xsl:when test="count(DROP) > 0">
+ <xsl:element name="DROP"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="field"/>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:apply-templates select="constraint"/>
+
+ <xsl:apply-templates select="opt"/>
+
+ <xsl:apply-templates select="index"/>
+
+ <xsl:apply-templates select="data"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Field -->
+ <xsl:template match="field">
+ <xsl:element name="field">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+ <xsl:attribute name="type"><xsl:value-of select="@type"/></xsl:attribute>
+
+ <xsl:if test="string-length(@size) > 0">
+ <xsl:attribute name="size"><xsl:value-of select="@size"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="string-length(@opts) = 0">
+ <xsl:if test="count(UNSIGNED) > 0">
+ <xsl:element name="UNSIGNED"/>
+ </xsl:if>
+ </xsl:when>
+ <xsl:when test="@opts = 'UNSIGNED'">
+ <xsl:element name="UNSIGNED"/>
+ </xsl:when>
+ <xsl:when test="contains(@opts,'UNSIGNED')">
+ <xsl:attribute name="opts">
+ <xsl:value-of select="concat(substring-before(@opts,'UNSIGNED'),substring-after(@opts,'UNSIGNED'))"/>
+ </xsl:attribute>
+ <xsl:element name="UNSIGNED"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="opts"><xsl:value-of select="@opts"/></xsl:attribute>
+ <xsl:if test="count(UNSIGNED) > 0">
+ <xsl:element name="UNSIGNED"/>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:choose>
+ <xsl:when test="count(PRIMARY) > 0">
+ <xsl:element name="PRIMARY"/>
+ </xsl:when>
+ <xsl:when test="count(KEY) > 0">
+ <xsl:element name="KEY"/>
+ </xsl:when>
+ <xsl:when test="count(NOTNULL) > 0">
+ <xsl:element name="NOTNULL"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(AUTO) > 0">
+ <xsl:element name="AUTO"/>
+ </xsl:when>
+ <xsl:when test="count(AUTOINCREMENT) > 0">
+ <xsl:element name="AUTOINCREMENT"/>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:choose>
+ <xsl:when test="count(DEFAULT) > 0">
+ <xsl:element name="DEFAULT">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFAULT[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="count(DEFDATE) > 0">
+ <xsl:element name="DEFDATE">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFDATE[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ <xsl:when test="count(DEFTIMESTAMP) > 0">
+ <xsl:element name="DEFTIMESTAMP">
+ <xsl:attribute name="value">
+ <xsl:value-of select="DEFTIMESTAMP[1]/@value"/>
+ </xsl:attribute>
+ </xsl:element>
+ </xsl:when>
+ </xsl:choose>
+
+ <xsl:if test="count(NOQUOTE) > 0">
+ <xsl:element name="NOQUOTE"/>
+ </xsl:if>
+
+ <xsl:apply-templates select="constraint"/>
+
+ <xsl:apply-templates select="opt"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Constraint -->
+ <xsl:template match="constraint">
+ <xsl:element name="constraint">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Opt -->
+ <xsl:template match="opt">
+ <xsl:element name="opt">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Index -->
+ <xsl:template match="index">
+ <xsl:element name="index">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:if test="count(CLUSTERED) > 0">
+ <xsl:element name="CLUSTERED"/>
+ </xsl:if>
+
+ <xsl:if test="count(BITMAP) > 0">
+ <xsl:element name="BITMAP"/>
+ </xsl:if>
+
+ <xsl:if test="count(UNIQUE) > 0">
+ <xsl:element name="UNIQUE"/>
+ </xsl:if>
+
+ <xsl:if test="count(FULLTEXT) > 0">
+ <xsl:element name="FULLTEXT"/>
+ </xsl:if>
+
+ <xsl:if test="count(HASH) > 0">
+ <xsl:element name="HASH"/>
+ </xsl:if>
+
+ <xsl:choose>
+ <xsl:when test="count(DROP) > 0">
+ <xsl:element name="DROP"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="col"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Index Column -->
+ <xsl:template match="col">
+ <xsl:element name="col">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- SQL QuerySet -->
+ <xsl:template match="sql">
+ <xsl:element name="sql">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@key) > 0">
+ <xsl:attribute name="key"><xsl:value-of select="@key"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@prefixmethod) > 0">
+ <xsl:attribute name="prefixmethod"><xsl:value-of select="@prefixmethod"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:apply-templates select="query"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Query -->
+ <xsl:template match="query">
+ <xsl:element name="query">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Description -->
+ <xsl:template match="descr">
+ <xsl:element name="descr">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Data -->
+ <xsl:template match="data">
+ <xsl:element name="data">
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:apply-templates select="row"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Data Row -->
+ <xsl:template match="row">
+ <xsl:element name="row">
+ <xsl:apply-templates select="f"/>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Data Field -->
+ <xsl:template match="f">
+ <xsl:element name="f">
+ <xsl:if test="string-length(@name) > 0">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet> \ No newline at end of file
diff --git a/lib/adodb/xsl/remove-0.2.xsl b/lib/adodb/xsl/remove-0.2.xsl
new file mode 100644
index 0000000..9b10a52
--- /dev/null
+++ b/lib/adodb/xsl/remove-0.2.xsl
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+ <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+
+ <!-- Schema -->
+ <xsl:template match="/">
+ <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+
+ <xsl:comment>
+Uninstallation Schema
+</xsl:comment>
+
+ <xsl:element name="schema">
+ <xsl:attribute name="version">0.2</xsl:attribute>
+
+ <xsl:apply-templates select="schema/table">
+ <xsl:sort select="position()" data-type="number" order="descending"/>
+ </xsl:apply-templates>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Table -->
+ <xsl:template match="table">
+ <xsl:if test="count(DROP) = 0">
+ <xsl:element name="table">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@version) > 0">
+ <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:element name="DROP"/>
+ </xsl:element>
+ </xsl:if>
+ </xsl:template>
+
+ <!-- Description -->
+ <xsl:template match="descr">
+ <xsl:element name="descr">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet> \ No newline at end of file
diff --git a/lib/adodb/xsl/remove-0.3.xsl b/lib/adodb/xsl/remove-0.3.xsl
new file mode 100644
index 0000000..768e092
--- /dev/null
+++ b/lib/adodb/xsl/remove-0.3.xsl
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+>
+ <xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
+
+ <!-- Schema -->
+ <xsl:template match="/">
+ <xsl:comment>
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+</xsl:comment>
+
+ <xsl:comment>
+Uninstallation Schema
+</xsl:comment>
+
+ <xsl:element name="schema">
+ <xsl:attribute name="version">0.3</xsl:attribute>
+
+ <xsl:apply-templates select="schema/table">
+ <xsl:sort select="position()" data-type="number" order="descending"/>
+ </xsl:apply-templates>
+ </xsl:element>
+ </xsl:template>
+
+ <!-- Table -->
+ <xsl:template match="table">
+ <xsl:if test="count(DROP) = 0">
+ <xsl:element name="table">
+ <xsl:attribute name="name"><xsl:value-of select="@name"/></xsl:attribute>
+
+ <xsl:if test="string-length(@platform) > 0">
+ <xsl:attribute name="platform"><xsl:value-of select="@platform"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:if test="string-length(@version) > 0">
+ <xsl:attribute name="version"><xsl:value-of select="@version"/></xsl:attribute>
+ </xsl:if>
+
+ <xsl:apply-templates select="descr[1]"/>
+
+ <xsl:element name="DROP"/>
+ </xsl:element>
+ </xsl:if>
+ </xsl:template>
+
+ <!-- Description -->
+ <xsl:template match="descr">
+ <xsl:element name="descr">
+ <xsl:value-of select="normalize-space(text())"/>
+ </xsl:element>
+ </xsl:template>
+</xsl:stylesheet> \ No newline at end of file
diff --git a/lib/smarty b/lib/smarty
new file mode 120000
index 0000000..da523dc
--- /dev/null
+++ b/lib/smarty
@@ -0,0 +1 @@
+smarty-2.6.8/ \ No newline at end of file
diff --git a/lib/smarty-2.6.8/Config_File.class.php b/lib/smarty-2.6.8/Config_File.class.php
new file mode 100644
index 0000000..3d7c1b4
--- /dev/null
+++ b/lib/smarty-2.6.8/Config_File.class.php
@@ -0,0 +1,389 @@
+<?php
+
+/**
+ * Config_File class.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * @link http://smarty.php.net/
+ * @version 2.6.18
+ * @copyright Copyright: 2001-2005 New Digital Group, Inc.
+ * @author Andrei Zmievski <andrei@php.net>
+ * @access public
+ * @package Smarty
+ */
+
+/* $Id: Config_File.class.php,v 1.88 2007/03/06 10:40:06 messju Exp $ */
+
+/**
+ * Config file reading class
+ * @package Smarty
+ */
+class Config_File {
+ /**#@+
+ * Options
+ * @var boolean
+ */
+ /**
+ * Controls whether variables with the same name overwrite each other.
+ */
+ var $overwrite = true;
+
+ /**
+ * Controls whether config values of on/true/yes and off/false/no get
+ * converted to boolean values automatically.
+ */
+ var $booleanize = true;
+
+ /**
+ * Controls whether hidden config sections/vars are read from the file.
+ */
+ var $read_hidden = true;
+
+ /**
+ * Controls whether or not to fix mac or dos formatted newlines.
+ * If set to true, \r or \r\n will be changed to \n.
+ */
+ var $fix_newlines = true;
+ /**#@-*/
+
+ /** @access private */
+ var $_config_path = "";
+ var $_config_data = array();
+ /**#@-*/
+
+ /**
+ * Constructs a new config file class.
+ *
+ * @param string $config_path (optional) path to the config files
+ */
+ function Config_File($config_path = NULL)
+ {
+ if (isset($config_path))
+ $this->set_path($config_path);
+ }
+
+
+ /**
+ * Set the path where configuration files can be found.
+ *
+ * @param string $config_path path to the config files
+ */
+ function set_path($config_path)
+ {
+ if (!empty($config_path)) {
+ if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) {
+ $this->_trigger_error_msg("Bad config file path '$config_path'");
+ return;
+ }
+ if(substr($config_path, -1) != DIRECTORY_SEPARATOR) {
+ $config_path .= DIRECTORY_SEPARATOR;
+ }
+
+ $this->_config_path = $config_path;
+ }
+ }
+
+
+ /**
+ * Retrieves config info based on the file, section, and variable name.
+ *
+ * @param string $file_name config file to get info for
+ * @param string $section_name (optional) section to get info for
+ * @param string $var_name (optional) variable to get info for
+ * @return string|array a value or array of values
+ */
+ function get($file_name, $section_name = NULL, $var_name = NULL)
+ {
+ if (empty($file_name)) {
+ $this->_trigger_error_msg('Empty config file name');
+ return;
+ } else {
+ $file_name = $this->_config_path . $file_name;
+ if (!isset($this->_config_data[$file_name]))
+ $this->load_file($file_name, false);
+ }
+
+ if (!empty($var_name)) {
+ if (empty($section_name)) {
+ return $this->_config_data[$file_name]["vars"][$var_name];
+ } else {
+ if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]))
+ return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name];
+ else
+ return array();
+ }
+ } else {
+ if (empty($section_name)) {
+ return (array)$this->_config_data[$file_name]["vars"];
+ } else {
+ if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"]))
+ return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"];
+ else
+ return array();
+ }
+ }
+ }
+
+
+ /**
+ * Retrieves config info based on the key.
+ *
+ * @param $file_name string config key (filename/section/var)
+ * @return string|array same as get()
+ * @uses get() retrieves information from config file and returns it
+ */
+ function &get_key($config_key)
+ {
+ list($file_name, $section_name, $var_name) = explode('/', $config_key, 3);
+ $result = &$this->get($file_name, $section_name, $var_name);
+ return $result;
+ }
+
+ /**
+ * Get all loaded config file names.
+ *
+ * @return array an array of loaded config file names
+ */
+ function get_file_names()
+ {
+ return array_keys($this->_config_data);
+ }
+
+
+ /**
+ * Get all section names from a loaded file.
+ *
+ * @param string $file_name config file to get section names from
+ * @return array an array of section names from the specified file
+ */
+ function get_section_names($file_name)
+ {
+ $file_name = $this->_config_path . $file_name;
+ if (!isset($this->_config_data[$file_name])) {
+ $this->_trigger_error_msg("Unknown config file '$file_name'");
+ return;
+ }
+
+ return array_keys($this->_config_data[$file_name]["sections"]);
+ }
+
+
+ /**
+ * Get all global or section variable names.
+ *
+ * @param string $file_name config file to get info for
+ * @param string $section_name (optional) section to get info for
+ * @return array an array of variables names from the specified file/section
+ */
+ function get_var_names($file_name, $section = NULL)
+ {
+ if (empty($file_name)) {
+ $this->_trigger_error_msg('Empty config file name');
+ return;
+ } else if (!isset($this->_config_data[$file_name])) {
+ $this->_trigger_error_msg("Unknown config file '$file_name'");
+ return;
+ }
+
+ if (empty($section))
+ return array_keys($this->_config_data[$file_name]["vars"]);
+ else
+ return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]);
+ }
+
+
+ /**
+ * Clear loaded config data for a certain file or all files.
+ *
+ * @param string $file_name file to clear config data for
+ */
+ function clear($file_name = NULL)
+ {
+ if ($file_name === NULL)
+ $this->_config_data = array();
+ else if (isset($this->_config_data[$file_name]))
+ $this->_config_data[$file_name] = array();
+ }
+
+
+ /**
+ * Load a configuration file manually.
+ *
+ * @param string $file_name file name to load
+ * @param boolean $prepend_path whether current config path should be
+ * prepended to the filename
+ */
+ function load_file($file_name, $prepend_path = true)
+ {
+ if ($prepend_path && $this->_config_path != "")
+ $config_file = $this->_config_path . $file_name;
+ else
+ $config_file = $file_name;
+
+ ini_set('track_errors', true);
+ $fp = @fopen($config_file, "r");
+ if (!is_resource($fp)) {
+ $this->_trigger_error_msg("Could not open config file '$config_file'");
+ return false;
+ }
+
+ $contents = ($size = filesize($config_file)) ? fread($fp, $size) : '';
+ fclose($fp);
+
+ $this->_config_data[$config_file] = $this->parse_contents($contents);
+ return true;
+ }
+
+ /**
+ * Store the contents of a file manually.
+ *
+ * @param string $config_file file name of the related contents
+ * @param string $contents the file-contents to parse
+ */
+ function set_file_contents($config_file, $contents)
+ {
+ $this->_config_data[$config_file] = $this->parse_contents($contents);
+ return true;
+ }
+
+ /**
+ * parse the source of a configuration file manually.
+ *
+ * @param string $contents the file-contents to parse
+ */
+ function parse_contents($contents)
+ {
+ if($this->fix_newlines) {
+ // fix mac/dos formatted newlines
+ $contents = preg_replace('!\r\n?!', "\n", $contents);
+ }
+
+ $config_data = array();
+ $config_data['sections'] = array();
+ $config_data['vars'] = array();
+
+ /* reference to fill with data */
+ $vars =& $config_data['vars'];
+
+ /* parse file line by line */
+ preg_match_all('!^.*\r?\n?!m', $contents, $match);
+ $lines = $match[0];
+ for ($i=0, $count=count($lines); $i<$count; $i++) {
+ $line = $lines[$i];
+ if (empty($line)) continue;
+
+ if ( substr($line, 0, 1) == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) {
+ /* section found */
+ if (substr($match[1], 0, 1) == '.') {
+ /* hidden section */
+ if ($this->read_hidden) {
+ $section_name = substr($match[1], 1);
+ } else {
+ /* break reference to $vars to ignore hidden section */
+ unset($vars);
+ $vars = array();
+ continue;
+ }
+ } else {
+ $section_name = $match[1];
+ }
+ if (!isset($config_data['sections'][$section_name]))
+ $config_data['sections'][$section_name] = array('vars' => array());
+ $vars =& $config_data['sections'][$section_name]['vars'];
+ continue;
+ }
+
+ if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) {
+ /* variable found */
+ $var_name = rtrim($match[1]);
+ if (strpos($match[2], '"""') === 0) {
+ /* handle multiline-value */
+ $lines[$i] = substr($match[2], 3);
+ $var_value = '';
+ while ($i<$count) {
+ if (($pos = strpos($lines[$i], '"""')) === false) {
+ $var_value .= $lines[$i++];
+ } else {
+ /* end of multiline-value */
+ $var_value .= substr($lines[$i], 0, $pos);
+ break;
+ }
+ }
+ $booleanize = false;
+
+ } else {
+ /* handle simple value */
+ $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2]));
+ $booleanize = $this->booleanize;
+
+ }
+ $this->_set_config_var($vars, $var_name, $var_value, $booleanize);
+ }
+ /* else unparsable line / means it is a comment / means ignore it */
+ }
+ return $config_data;
+ }
+
+ /**#@+ @access private */
+ /**
+ * @param array &$container
+ * @param string $var_name
+ * @param mixed $var_value
+ * @param boolean $booleanize determines whether $var_value is converted to
+ * to true/false
+ */
+ function _set_config_var(&$container, $var_name, $var_value, $booleanize)
+ {
+ if (substr($var_name, 0, 1) == '.') {
+ if (!$this->read_hidden)
+ return;
+ else
+ $var_name = substr($var_name, 1);
+ }
+
+ if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) {
+ $this->_trigger_error_msg("Bad variable name '$var_name'");
+ return;
+ }
+
+ if ($booleanize) {
+ if (preg_match("/^(on|true|yes)$/i", $var_value))
+ $var_value = true;
+ else if (preg_match("/^(off|false|no)$/i", $var_value))
+ $var_value = false;
+ }
+
+ if (!isset($container[$var_name]) || $this->overwrite)
+ $container[$var_name] = $var_value;
+ else {
+ settype($container[$var_name], 'array');
+ $container[$var_name][] = $var_value;
+ }
+ }
+
+ /**
+ * @uses trigger_error() creates a PHP warning/error
+ * @param string $error_msg
+ * @param integer $error_type one of
+ */
+ function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING)
+ {
+ trigger_error("Config_File error: $error_msg", $error_type);
+ }
+ /**#@-*/
+}
+
+?>
diff --git a/lib/smarty-2.6.8/Smarty.class.php b/lib/smarty-2.6.8/Smarty.class.php
new file mode 100644
index 0000000..f05e0da
--- /dev/null
+++ b/lib/smarty-2.6.8/Smarty.class.php
@@ -0,0 +1,1944 @@
+<?php
+
+/**
+ * Project: Smarty: the PHP compiling template engine
+ * File: Smarty.class.php
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For questions, help, comments, discussion, etc., please join the
+ * Smarty mailing list. Send a blank e-mail to
+ * smarty-general-subscribe@lists.php.net
+ *
+ * @link http://smarty.php.net/
+ * @copyright 2001-2005 New Digital Group, Inc.
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author Andrei Zmievski <andrei@php.net>
+ * @package Smarty
+ * @version 2.6.18
+ */
+
+/* $Id: Smarty.class.php,v 1.528 2007/03/06 10:40:06 messju Exp $ */
+
+/**
+ * DIR_SEP isn't used anymore, but third party apps might
+ */
+if(!defined('DIR_SEP')) {
+ define('DIR_SEP', DIRECTORY_SEPARATOR);
+}
+
+/**
+ * set SMARTY_DIR to absolute path to Smarty library files.
+ * if not defined, include_path will be used. Sets SMARTY_DIR only if user
+ * application has not already defined it.
+ */
+
+if (!defined('SMARTY_DIR')) {
+ define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR);
+}
+
+if (!defined('SMARTY_CORE_DIR')) {
+ define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR);
+}
+
+define('SMARTY_PHP_PASSTHRU', 0);
+define('SMARTY_PHP_QUOTE', 1);
+define('SMARTY_PHP_REMOVE', 2);
+define('SMARTY_PHP_ALLOW', 3);
+
+/**
+ * @package Smarty
+ */
+class Smarty
+{
+ /**#@+
+ * Smarty Configuration Section
+ */
+
+ /**
+ * The name of the directory where templates are located.
+ *
+ * @var string
+ */
+ var $template_dir = 'templates';
+
+ /**
+ * The directory where compiled templates are located.
+ *
+ * @var string
+ */
+ var $compile_dir = 'templates_c';
+
+ /**
+ * The directory where config files are located.
+ *
+ * @var string
+ */
+ var $config_dir = 'configs';
+
+ /**
+ * An array of directories searched for plugins.
+ *
+ * @var array
+ */
+ var $plugins_dir = array('plugins');
+
+ /**
+ * If debugging is enabled, a debug console window will display
+ * when the page loads (make sure your browser allows unrequested
+ * popup windows)
+ *
+ * @var boolean
+ */
+ var $debugging = false;
+
+ /**
+ * When set, smarty does uses this value as error_reporting-level.
+ *
+ * @var boolean
+ */
+ var $error_reporting = null;
+
+ /**
+ * This is the path to the debug console template. If not set,
+ * the default one will be used.
+ *
+ * @var string
+ */
+ var $debug_tpl = '';
+
+ /**
+ * This determines if debugging is enable-able from the browser.
+ * <ul>
+ * <li>NONE => no debugging control allowed</li>
+ * <li>URL => enable debugging when SMARTY_DEBUG is found in the URL.</li>
+ * </ul>
+ * @link http://www.foo.dom/index.php?SMARTY_DEBUG
+ * @var string
+ */
+ var $debugging_ctrl = 'NONE';
+
+ /**
+ * This tells Smarty whether to check for recompiling or not. Recompiling
+ * does not need to happen unless a template or config file is changed.
+ * Typically you enable this during development, and disable for
+ * production.
+ *
+ * @var boolean
+ */
+ var $compile_check = true;
+
+ /**
+ * This forces templates to compile every time. Useful for development
+ * or debugging.
+ *
+ * @var boolean
+ */
+ var $force_compile = false;
+
+ /**
+ * This enables template caching.
+ * <ul>
+ * <li>0 = no caching</li>
+ * <li>1 = use class cache_lifetime value</li>
+ * <li>2 = use cache_lifetime in cache file</li>
+ * </ul>
+ * @var integer
+ */
+ var $caching = 0;
+
+ /**
+ * The name of the directory for cache files.
+ *
+ * @var string
+ */
+ var $cache_dir = 'cache';
+
+ /**
+ * This is the number of seconds cached content will persist.
+ * <ul>
+ * <li>0 = always regenerate cache</li>
+ * <li>-1 = never expires</li>
+ * </ul>
+ *
+ * @var integer
+ */
+ var $cache_lifetime = 3600;
+
+ /**
+ * Only used when $caching is enabled. If true, then If-Modified-Since headers
+ * are respected with cached content, and appropriate HTTP headers are sent.
+ * This way repeated hits to a cached page do not send the entire page to the
+ * client every time.
+ *
+ * @var boolean
+ */
+ var $cache_modified_check = false;
+
+ /**
+ * This determines how Smarty handles "<?php ... ?>" tags in templates.
+ * possible values:
+ * <ul>
+ * <li>SMARTY_PHP_PASSTHRU -> print tags as plain text</li>
+ * <li>SMARTY_PHP_QUOTE -> escape tags as entities</li>
+ * <li>SMARTY_PHP_REMOVE -> remove php tags</li>
+ * <li>SMARTY_PHP_ALLOW -> execute php tags</li>
+ * </ul>
+ *
+ * @var integer
+ */
+ var $php_handling = SMARTY_PHP_PASSTHRU;
+
+ /**
+ * This enables template security. When enabled, many things are restricted
+ * in the templates that normally would go unchecked. This is useful when
+ * untrusted parties are editing templates and you want a reasonable level
+ * of security. (no direct execution of PHP in templates for example)
+ *
+ * @var boolean
+ */
+ var $security = false;
+
+ /**
+ * This is the list of template directories that are considered secure. This
+ * is used only if {@link $security} is enabled. One directory per array
+ * element. {@link $template_dir} is in this list implicitly.
+ *
+ * @var array
+ */
+ var $secure_dir = array();
+
+ /**
+ * These are the security settings for Smarty. They are used only when
+ * {@link $security} is enabled.
+ *
+ * @var array
+ */
+ var $security_settings = array(
+ 'PHP_HANDLING' => false,
+ 'IF_FUNCS' => array('array', 'list',
+ 'isset', 'empty',
+ 'count', 'sizeof',
+ 'in_array', 'is_array',
+ 'true', 'false', 'null'),
+ 'INCLUDE_ANY' => false,
+ 'PHP_TAGS' => false,
+ 'MODIFIER_FUNCS' => array('count'),
+ 'ALLOW_CONSTANTS' => false
+ );
+
+ /**
+ * This is an array of directories where trusted php scripts reside.
+ * {@link $security} is disabled during their inclusion/execution.
+ *
+ * @var array
+ */
+ var $trusted_dir = array();
+
+ /**
+ * The left delimiter used for the template tags.
+ *
+ * @var string
+ */
+ var $left_delimiter = '{';
+
+ /**
+ * The right delimiter used for the template tags.
+ *
+ * @var string
+ */
+ var $right_delimiter = '}';
+
+ /**
+ * The order in which request variables are registered, similar to
+ * variables_order in php.ini E = Environment, G = GET, P = POST,
+ * C = Cookies, S = Server
+ *
+ * @var string
+ */
+ var $request_vars_order = 'EGPCS';
+
+ /**
+ * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false)
+ * are uses as request-vars or $_*[]-vars. note: if
+ * request_use_auto_globals is true, then $request_vars_order has
+ * no effect, but the php-ini-value "gpc_order"
+ *
+ * @var boolean
+ */
+ var $request_use_auto_globals = true;
+
+ /**
+ * Set this if you want different sets of compiled files for the same
+ * templates. This is useful for things like different languages.
+ * Instead of creating separate sets of templates per language, you
+ * set different compile_ids like 'en' and 'de'.
+ *
+ * @var string
+ */
+ var $compile_id = null;
+
+ /**
+ * This tells Smarty whether or not to use sub dirs in the cache/ and
+ * templates_c/ directories. sub directories better organized, but
+ * may not work well with PHP safe mode enabled.
+ *
+ * @var boolean
+ *
+ */
+ var $use_sub_dirs = false;
+
+ /**
+ * This is a list of the modifiers to apply to all template variables.
+ * Put each modifier in a separate array element in the order you want
+ * them applied. example: <code>array('escape:"htmlall"');</code>
+ *
+ * @var array
+ */
+ var $default_modifiers = array();
+
+ /**
+ * This is the resource type to be used when not specified
+ * at the beginning of the resource path. examples:
+ * $smarty->display('file:index.tpl');
+ * $smarty->display('db:index.tpl');
+ * $smarty->display('index.tpl'); // will use default resource type
+ * {include file="file:index.tpl"}
+ * {include file="db:index.tpl"}
+ * {include file="index.tpl"} {* will use default resource type *}
+ *
+ * @var array
+ */
+ var $default_resource_type = 'file';
+
+ /**
+ * The function used for cache file handling. If not set, built-in caching is used.
+ *
+ * @var null|string function name
+ */
+ var $cache_handler_func = null;
+
+ /**
+ * This indicates which filters are automatically loaded into Smarty.
+ *
+ * @var array array of filter names
+ */
+ var $autoload_filters = array();
+
+ /**#@+
+ * @var boolean
+ */
+ /**
+ * This tells if config file vars of the same name overwrite each other or not.
+ * if disabled, same name variables are accumulated in an array.
+ */
+ var $config_overwrite = true;
+
+ /**
+ * This tells whether or not to automatically booleanize config file variables.
+ * If enabled, then the strings "on", "true", and "yes" are treated as boolean
+ * true, and "off", "false" and "no" are treated as boolean false.
+ */
+ var $config_booleanize = true;
+
+ /**
+ * This tells whether hidden sections [.foobar] are readable from the
+ * tempalates or not. Normally you would never allow this since that is
+ * the point behind hidden sections: the application can access them, but
+ * the templates cannot.
+ */
+ var $config_read_hidden = false;
+
+ /**
+ * This tells whether or not automatically fix newlines in config files.
+ * It basically converts \r (mac) or \r\n (dos) to \n
+ */
+ var $config_fix_newlines = true;
+ /**#@-*/
+
+ /**
+ * If a template cannot be found, this PHP function will be executed.
+ * Useful for creating templates on-the-fly or other special action.
+ *
+ * @var string function name
+ */
+ var $default_template_handler_func = '';
+
+ /**
+ * The file that contains the compiler class. This can a full
+ * pathname, or relative to the php_include path.
+ *
+ * @var string
+ */
+ var $compiler_file = 'Smarty_Compiler.class.php';
+
+ /**
+ * The class used for compiling templates.
+ *
+ * @var string
+ */
+ var $compiler_class = 'Smarty_Compiler';
+
+ /**
+ * The class used to load config vars.
+ *
+ * @var string
+ */
+ var $config_class = 'Config_File';
+
+/**#@+
+ * END Smarty Configuration Section
+ * There should be no need to touch anything below this line.
+ * @access private
+ */
+ /**
+ * where assigned template vars are kept
+ *
+ * @var array
+ */
+ var $_tpl_vars = array();
+
+ /**
+ * stores run-time $smarty.* vars
+ *
+ * @var null|array
+ */
+ var $_smarty_vars = null;
+
+ /**
+ * keeps track of sections
+ *
+ * @var array
+ */
+ var $_sections = array();
+
+ /**
+ * keeps track of foreach blocks
+ *
+ * @var array
+ */
+ var $_foreach = array();
+
+ /**
+ * keeps track of tag hierarchy
+ *
+ * @var array
+ */
+ var $_tag_stack = array();
+
+ /**
+ * configuration object
+ *
+ * @var Config_file
+ */
+ var $_conf_obj = null;
+
+ /**
+ * loaded configuration settings
+ *
+ * @var array
+ */
+ var $_config = array(array('vars' => array(), 'files' => array()));
+
+ /**
+ * md5 checksum of the string 'Smarty'
+ *
+ * @var string
+ */
+ var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f';
+
+ /**
+ * Smarty version number
+ *
+ * @var string
+ */
+ var $_version = '2.6.18';
+
+ /**
+ * current template inclusion depth
+ *
+ * @var integer
+ */
+ var $_inclusion_depth = 0;
+
+ /**
+ * for different compiled templates
+ *
+ * @var string
+ */
+ var $_compile_id = null;
+
+ /**
+ * text in URL to enable debug mode
+ *
+ * @var string
+ */
+ var $_smarty_debug_id = 'SMARTY_DEBUG';
+
+ /**
+ * debugging information for debug console
+ *
+ * @var array
+ */
+ var $_smarty_debug_info = array();
+
+ /**
+ * info that makes up a cache file
+ *
+ * @var array
+ */
+ var $_cache_info = array();
+
+ /**
+ * default file permissions
+ *
+ * @var integer
+ */
+ var $_file_perms = 0644;
+
+ /**
+ * default dir permissions
+ *
+ * @var integer
+ */
+ var $_dir_perms = 0771;
+
+ /**
+ * registered objects
+ *
+ * @var array
+ */
+ var $_reg_objects = array();
+
+ /**
+ * table keeping track of plugins
+ *
+ * @var array
+ */
+ var $_plugins = array(
+ 'modifier' => array(),
+ 'function' => array(),
+ 'block' => array(),
+ 'compiler' => array(),
+ 'prefilter' => array(),
+ 'postfilter' => array(),
+ 'outputfilter' => array(),
+ 'resource' => array(),
+ 'insert' => array());
+
+
+ /**
+ * cache serials
+ *
+ * @var array
+ */
+ var $_cache_serials = array();
+
+ /**
+ * name of optional cache include file
+ *
+ * @var string
+ */
+ var $_cache_include = null;
+
+ /**
+ * indicate if the current code is used in a compiled
+ * include
+ *
+ * @var string
+ */
+ var $_cache_including = false;
+
+ /**#@-*/
+ /**
+ * The class constructor.
+ */
+ function Smarty()
+ {
+ $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME']
+ : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']);
+ }
+
+ /**
+ * assigns values to template variables
+ *
+ * @param array|string $tpl_var the template variable name(s)
+ * @param mixed $value the value to assign
+ */
+ function assign($tpl_var, $value = null)
+ {
+ if (is_array($tpl_var)){
+ foreach ($tpl_var as $key => $val) {
+ if ($key != '') {
+ $this->_tpl_vars[$key] = $val;
+ }
+ }
+ } else {
+ if ($tpl_var != '')
+ $this->_tpl_vars[$tpl_var] = $value;
+ }
+ }
+
+ /**
+ * assigns values to template variables by reference
+ *
+ * @param string $tpl_var the template variable name
+ * @param mixed $value the referenced value to assign
+ */
+ function assign_by_ref($tpl_var, &$value)
+ {
+ if ($tpl_var != '')
+ $this->_tpl_vars[$tpl_var] = &$value;
+ }
+
+ /**
+ * appends values to template variables
+ *
+ * @param array|string $tpl_var the template variable name(s)
+ * @param mixed $value the value to append
+ */
+ function append($tpl_var, $value=null, $merge=false)
+ {
+ if (is_array($tpl_var)) {
+ // $tpl_var is an array, ignore $value
+ foreach ($tpl_var as $_key => $_val) {
+ if ($_key != '') {
+ if(!@is_array($this->_tpl_vars[$_key])) {
+ settype($this->_tpl_vars[$_key],'array');
+ }
+ if($merge && is_array($_val)) {
+ foreach($_val as $_mkey => $_mval) {
+ $this->_tpl_vars[$_key][$_mkey] = $_mval;
+ }
+ } else {
+ $this->_tpl_vars[$_key][] = $_val;
+ }
+ }
+ }
+ } else {
+ if ($tpl_var != '' && isset($value)) {
+ if(!@is_array($this->_tpl_vars[$tpl_var])) {
+ settype($this->_tpl_vars[$tpl_var],'array');
+ }
+ if($merge && is_array($value)) {
+ foreach($value as $_mkey => $_mval) {
+ $this->_tpl_vars[$tpl_var][$_mkey] = $_mval;
+ }
+ } else {
+ $this->_tpl_vars[$tpl_var][] = $value;
+ }
+ }
+ }
+ }
+
+ /**
+ * appends values to template variables by reference
+ *
+ * @param string $tpl_var the template variable name
+ * @param mixed $value the referenced value to append
+ */
+ function append_by_ref($tpl_var, &$value, $merge=false)
+ {
+ if ($tpl_var != '' && isset($value)) {
+ if(!@is_array($this->_tpl_vars[$tpl_var])) {
+ settype($this->_tpl_vars[$tpl_var],'array');
+ }
+ if ($merge && is_array($value)) {
+ foreach($value as $_key => $_val) {
+ $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key];
+ }
+ } else {
+ $this->_tpl_vars[$tpl_var][] = &$value;
+ }
+ }
+ }
+
+
+ /**
+ * clear the given assigned template variable.
+ *
+ * @param string $tpl_var the template variable to clear
+ */
+ function clear_assign($tpl_var)
+ {
+ if (is_array($tpl_var))
+ foreach ($tpl_var as $curr_var)
+ unset($this->_tpl_vars[$curr_var]);
+ else
+ unset($this->_tpl_vars[$tpl_var]);
+ }
+
+
+ /**
+ * Registers custom function to be used in templates
+ *
+ * @param string $function the name of the template function
+ * @param string $function_impl the name of the PHP function to register
+ */
+ function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null)
+ {
+ $this->_plugins['function'][$function] =
+ array($function_impl, null, null, false, $cacheable, $cache_attrs);
+
+ }
+
+ /**
+ * Unregisters custom function
+ *
+ * @param string $function name of template function
+ */
+ function unregister_function($function)
+ {
+ unset($this->_plugins['function'][$function]);
+ }
+
+ /**
+ * Registers object to be used in templates
+ *
+ * @param string $object name of template object
+ * @param object &$object_impl the referenced PHP object to register
+ * @param null|array $allowed list of allowed methods (empty = all)
+ * @param boolean $smarty_args smarty argument format, else traditional
+ * @param null|array $block_functs list of methods that are block format
+ */
+ function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array())
+ {
+ settype($allowed, 'array');
+ settype($smarty_args, 'boolean');
+ $this->_reg_objects[$object] =
+ array(&$object_impl, $allowed, $smarty_args, $block_methods);
+ }
+
+ /**
+ * Unregisters object
+ *
+ * @param string $object name of template object
+ */
+ function unregister_object($object)
+ {
+ unset($this->_reg_objects[$object]);
+ }
+
+
+ /**
+ * Registers block function to be used in templates
+ *
+ * @param string $block name of template block
+ * @param string $block_impl PHP function to register
+ */
+ function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null)
+ {
+ $this->_plugins['block'][$block] =
+ array($block_impl, null, null, false, $cacheable, $cache_attrs);
+ }
+
+ /**
+ * Unregisters block function
+ *
+ * @param string $block name of template function
+ */
+ function unregister_block($block)
+ {
+ unset($this->_plugins['block'][$block]);
+ }
+
+ /**
+ * Registers compiler function
+ *
+ * @param string $function name of template function
+ * @param string $function_impl name of PHP function to register
+ */
+ function register_compiler_function($function, $function_impl, $cacheable=true)
+ {
+ $this->_plugins['compiler'][$function] =
+ array($function_impl, null, null, false, $cacheable);
+ }
+
+ /**
+ * Unregisters compiler function
+ *
+ * @param string $function name of template function
+ */
+ function unregister_compiler_function($function)
+ {
+ unset($this->_plugins['compiler'][$function]);
+ }
+
+ /**
+ * Registers modifier to be used in templates
+ *
+ * @param string $modifier name of template modifier
+ * @param string $modifier_impl name of PHP function to register
+ */
+ function register_modifier($modifier, $modifier_impl)
+ {
+ $this->_plugins['modifier'][$modifier] =
+ array($modifier_impl, null, null, false);
+ }
+
+ /**
+ * Unregisters modifier
+ *
+ * @param string $modifier name of template modifier
+ */
+ function unregister_modifier($modifier)
+ {
+ unset($this->_plugins['modifier'][$modifier]);
+ }
+
+ /**
+ * Registers a resource to fetch a template
+ *
+ * @param string $type name of resource
+ * @param array $functions array of functions to handle resource
+ */
+ function register_resource($type, $functions)
+ {
+ if (count($functions)==4) {
+ $this->_plugins['resource'][$type] =
+ array($functions, false);
+
+ } elseif (count($functions)==5) {
+ $this->_plugins['resource'][$type] =
+ array(array(array(&$functions[0], $functions[1])
+ ,array(&$functions[0], $functions[2])
+ ,array(&$functions[0], $functions[3])
+ ,array(&$functions[0], $functions[4]))
+ ,false);
+
+ } else {
+ $this->trigger_error("malformed function-list for '$type' in register_resource");
+
+ }
+ }
+
+ /**
+ * Unregisters a resource
+ *
+ * @param string $type name of resource
+ */
+ function unregister_resource($type)
+ {
+ unset($this->_plugins['resource'][$type]);
+ }
+
+ /**
+ * Registers a prefilter function to apply
+ * to a template before compiling
+ *
+ * @param string $function name of PHP function to register
+ */
+ function register_prefilter($function)
+ {
+ $_name = (is_array($function)) ? $function[1] : $function;
+ $this->_plugins['prefilter'][$_name]
+ = array($function, null, null, false);
+ }
+
+ /**
+ * Unregisters a prefilter function
+ *
+ * @param string $function name of PHP function
+ */
+ function unregister_prefilter($function)
+ {
+ unset($this->_plugins['prefilter'][$function]);
+ }
+
+ /**
+ * Registers a postfilter function to apply
+ * to a compiled template after compilation
+ *
+ * @param string $function name of PHP function to register
+ */
+ function register_postfilter($function)
+ {
+ $_name = (is_array($function)) ? $function[1] : $function;
+ $this->_plugins['postfilter'][$_name]
+ = array($function, null, null, false);
+ }
+
+ /**
+ * Unregisters a postfilter function
+ *
+ * @param string $function name of PHP function
+ */
+ function unregister_postfilter($function)
+ {
+ unset($this->_plugins['postfilter'][$function]);
+ }
+
+ /**
+ * Registers an output filter function to apply
+ * to a template output
+ *
+ * @param string $function name of PHP function
+ */
+ function register_outputfilter($function)
+ {
+ $_name = (is_array($function)) ? $function[1] : $function;
+ $this->_plugins['outputfilter'][$_name]
+ = array($function, null, null, false);
+ }
+
+ /**
+ * Unregisters an outputfilter function
+ *
+ * @param string $function name of PHP function
+ */
+ function unregister_outputfilter($function)
+ {
+ unset($this->_plugins['outputfilter'][$function]);
+ }
+
+ /**
+ * load a filter of specified type and name
+ *
+ * @param string $type filter type
+ * @param string $name filter name
+ */
+ function load_filter($type, $name)
+ {
+ switch ($type) {
+ case 'output':
+ $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false)));
+ require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
+ smarty_core_load_plugins($_params, $this);
+ break;
+
+ case 'pre':
+ case 'post':
+ if (!isset($this->_plugins[$type . 'filter'][$name]))
+ $this->_plugins[$type . 'filter'][$name] = false;
+ break;
+ }
+ }
+
+ /**
+ * clear cached content for the given template and cache id
+ *
+ * @param string $tpl_file name of template file
+ * @param string $cache_id name of cache_id
+ * @param string $compile_id name of compile_id
+ * @param string $exp_time expiration time
+ * @return boolean
+ */
+ function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null)
+ {
+
+ if (!isset($compile_id))
+ $compile_id = $this->compile_id;
+
+ if (!isset($tpl_file))
+ $compile_id = null;
+
+ $_auto_id = $this->_get_auto_id($cache_id, $compile_id);
+
+ if (!empty($this->cache_handler_func)) {
+ return call_user_func_array($this->cache_handler_func,
+ array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time));
+ } else {
+ $_params = array('auto_base' => $this->cache_dir,
+ 'auto_source' => $tpl_file,
+ 'auto_id' => $_auto_id,
+ 'exp_time' => $exp_time);
+ require_once(SMARTY_CORE_DIR . 'core.rm_auto.php');
+ return smarty_core_rm_auto($_params, $this);
+ }
+
+ }
+
+
+ /**
+ * clear the entire contents of cache (all templates)
+ *
+ * @param string $exp_time expire time
+ * @return boolean results of {@link smarty_core_rm_auto()}
+ */
+ function clear_all_cache($exp_time = null)
+ {
+ return $this->clear_cache(null, null, null, $exp_time);
+ }
+
+
+ /**
+ * test to see if valid cache exists for this template
+ *
+ * @param string $tpl_file name of template file
+ * @param string $cache_id
+ * @param string $compile_id
+ * @return string|false results of {@link _read_cache_file()}
+ */
+ function is_cached($tpl_file, $cache_id = null, $compile_id = null)
+ {
+ if (!$this->caching)
+ return false;
+
+ if (!isset($compile_id))
+ $compile_id = $this->compile_id;
+
+ $_params = array(
+ 'tpl_file' => $tpl_file,
+ 'cache_id' => $cache_id,
+ 'compile_id' => $compile_id
+ );
+ require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');
+ return smarty_core_read_cache_file($_params, $this);
+ }
+
+
+ /**
+ * clear all the assigned template variables.
+ *
+ */
+ function clear_all_assign()
+ {
+ $this->_tpl_vars = array();
+ }
+
+ /**
+ * clears compiled version of specified template resource,
+ * or all compiled template files if one is not specified.
+ * This function is for advanced use only, not normally needed.
+ *
+ * @param string $tpl_file
+ * @param string $compile_id
+ * @param string $exp_time
+ * @return boolean results of {@link smarty_core_rm_auto()}
+ */
+ function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null)
+ {
+ if (!isset($compile_id)) {
+ $compile_id = $this->compile_id;
+ }
+ $_params = array('auto_base' => $this->compile_dir,
+ 'auto_source' => $tpl_file,
+ 'auto_id' => $compile_id,
+ 'exp_time' => $exp_time,
+ 'extensions' => array('.inc', '.php'));
+ require_once(SMARTY_CORE_DIR . 'core.rm_auto.php');
+ return smarty_core_rm_auto($_params, $this);
+ }
+
+ /**
+ * Checks whether requested template exists.
+ *
+ * @param string $tpl_file
+ * @return boolean
+ */
+ function template_exists($tpl_file)
+ {
+ $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false);
+ return $this->_fetch_resource_info($_params);
+ }
+
+ /**
+ * Returns an array containing template variables
+ *
+ * @param string $name
+ * @param string $type
+ * @return array
+ */
+ function &get_template_vars($name=null)
+ {
+ if(!isset($name)) {
+ return $this->_tpl_vars;
+ } elseif(isset($this->_tpl_vars[$name])) {
+ return $this->_tpl_vars[$name];
+ } else {
+ // var non-existant, return valid reference
+ $_tmp = null;
+ return $_tmp;
+ }
+ }
+
+ /**
+ * Returns an array containing config variables
+ *
+ * @param string $name
+ * @param string $type
+ * @return array
+ */
+ function &get_config_vars($name=null)
+ {
+ if(!isset($name) && is_array($this->_config[0])) {
+ return $this->_config[0]['vars'];
+ } else if(isset($this->_config[0]['vars'][$name])) {
+ return $this->_config[0]['vars'][$name];
+ } else {
+ // var non-existant, return valid reference
+ $_tmp = null;
+ return $_tmp;
+ }
+ }
+
+ /**
+ * trigger Smarty error
+ *
+ * @param string $error_msg
+ * @param integer $error_type
+ */
+ function trigger_error($error_msg, $error_type = E_USER_WARNING)
+ {
+ trigger_error("Smarty error: $error_msg", $error_type);
+ }
+
+
+ /**
+ * executes & displays the template results
+ *
+ * @param string $resource_name
+ * @param string $cache_id
+ * @param string $compile_id
+ */
+ function display($resource_name, $cache_id = null, $compile_id = null)
+ {
+ $this->fetch($resource_name, $cache_id, $compile_id, true);
+ }
+
+ /**
+ * executes & returns or displays the template results
+ *
+ * @param string $resource_name
+ * @param string $cache_id
+ * @param string $compile_id
+ * @param boolean $display
+ */
+ function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false)
+ {
+ static $_cache_info = array();
+
+ $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting)
+ ? $this->error_reporting : error_reporting() & ~E_NOTICE);
+
+ if (!$this->debugging && $this->debugging_ctrl == 'URL') {
+ $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'];
+ if (@strstr($_query_string, $this->_smarty_debug_id)) {
+ if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) {
+ // enable debugging for this browser session
+ @setcookie('SMARTY_DEBUG', true);
+ $this->debugging = true;
+ } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) {
+ // disable debugging for this browser session
+ @setcookie('SMARTY_DEBUG', false);
+ $this->debugging = false;
+ } else {
+ // enable debugging for this page
+ $this->debugging = true;
+ }
+ } else {
+ $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']);
+ }
+ }
+
+ if ($this->debugging) {
+ // capture time for debugging info
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $_debug_start_time = smarty_core_get_microtime($_params, $this);
+ $this->_smarty_debug_info[] = array('type' => 'template',
+ 'filename' => $resource_name,
+ 'depth' => 0);
+ $_included_tpls_idx = count($this->_smarty_debug_info) - 1;
+ }
+
+ if (!isset($compile_id)) {
+ $compile_id = $this->compile_id;
+ }
+
+ $this->_compile_id = $compile_id;
+ $this->_inclusion_depth = 0;
+
+ if ($this->caching) {
+ // save old cache_info, initialize cache_info
+ array_push($_cache_info, $this->_cache_info);
+ $this->_cache_info = array();
+ $_params = array(
+ 'tpl_file' => $resource_name,
+ 'cache_id' => $cache_id,
+ 'compile_id' => $compile_id,
+ 'results' => null
+ );
+ require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');
+ if (smarty_core_read_cache_file($_params, $this)) {
+ $_smarty_results = $_params['results'];
+ if (!empty($this->_cache_info['insert_tags'])) {
+ $_params = array('plugins' => $this->_cache_info['insert_tags']);
+ require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
+ smarty_core_load_plugins($_params, $this);
+ $_params = array('results' => $_smarty_results);
+ require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');
+ $_smarty_results = smarty_core_process_cached_inserts($_params, $this);
+ }
+ if (!empty($this->_cache_info['cache_serials'])) {
+ $_params = array('results' => $_smarty_results);
+ require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php');
+ $_smarty_results = smarty_core_process_compiled_include($_params, $this);
+ }
+
+
+ if ($display) {
+ if ($this->debugging)
+ {
+ // capture time for debugging info
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time;
+ require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');
+ $_smarty_results .= smarty_core_display_debug_console($_params, $this);
+ }
+ if ($this->cache_modified_check) {
+ $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
+ $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3);
+ $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT';
+ if (@count($this->_cache_info['insert_tags']) == 0
+ && !$this->_cache_serials
+ && $_gmt_mtime == $_last_modified_date) {
+ if (php_sapi_name()=='cgi')
+ header('Status: 304 Not Modified');
+ else
+ header('HTTP/1.1 304 Not Modified');
+
+ } else {
+ header('Last-Modified: '.$_gmt_mtime);
+ echo $_smarty_results;
+ }
+ } else {
+ echo $_smarty_results;
+ }
+ error_reporting($_smarty_old_error_level);
+ // restore initial cache_info
+ $this->_cache_info = array_pop($_cache_info);
+ return true;
+ } else {
+ error_reporting($_smarty_old_error_level);
+ // restore initial cache_info
+ $this->_cache_info = array_pop($_cache_info);
+ return $_smarty_results;
+ }
+ } else {
+ $this->_cache_info['template'][$resource_name] = true;
+ if ($this->cache_modified_check && $display) {
+ header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');
+ }
+ }
+ }
+
+ // load filters that are marked as autoload
+ if (count($this->autoload_filters)) {
+ foreach ($this->autoload_filters as $_filter_type => $_filters) {
+ foreach ($_filters as $_filter) {
+ $this->load_filter($_filter_type, $_filter);
+ }
+ }
+ }
+
+ $_smarty_compile_path = $this->_get_compile_path($resource_name);
+
+ // if we just need to display the results, don't perform output
+ // buffering - for speed
+ $_cache_including = $this->_cache_including;
+ $this->_cache_including = false;
+ if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) {
+ if ($this->_is_compiled($resource_name, $_smarty_compile_path)
+ || $this->_compile_resource($resource_name, $_smarty_compile_path))
+ {
+ include($_smarty_compile_path);
+ }
+ } else {
+ ob_start();
+ if ($this->_is_compiled($resource_name, $_smarty_compile_path)
+ || $this->_compile_resource($resource_name, $_smarty_compile_path))
+ {
+ include($_smarty_compile_path);
+ }
+ $_smarty_results = ob_get_contents();
+ ob_end_clean();
+
+ foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) {
+ $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this));
+ }
+ }
+
+ if ($this->caching) {
+ $_params = array('tpl_file' => $resource_name,
+ 'cache_id' => $cache_id,
+ 'compile_id' => $compile_id,
+ 'results' => $_smarty_results);
+ require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php');
+ smarty_core_write_cache_file($_params, $this);
+ require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');
+ $_smarty_results = smarty_core_process_cached_inserts($_params, $this);
+
+ if ($this->_cache_serials) {
+ // strip nocache-tags from output
+ $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s'
+ ,''
+ ,$_smarty_results);
+ }
+ // restore initial cache_info
+ $this->_cache_info = array_pop($_cache_info);
+ }
+ $this->_cache_including = $_cache_including;
+
+ if ($display) {
+ if (isset($_smarty_results)) { echo $_smarty_results; }
+ if ($this->debugging) {
+ // capture time for debugging info
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time);
+ require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');
+ echo smarty_core_display_debug_console($_params, $this);
+ }
+ error_reporting($_smarty_old_error_level);
+ return;
+ } else {
+ error_reporting($_smarty_old_error_level);
+ if (isset($_smarty_results)) { return $_smarty_results; }
+ }
+ }
+
+ /**
+ * load configuration values
+ *
+ * @param string $file
+ * @param string $section
+ * @param string $scope
+ */
+ function config_load($file, $section = null, $scope = 'global')
+ {
+ require_once($this->_get_plugin_filepath('function', 'config_load'));
+ smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this);
+ }
+
+ /**
+ * return a reference to a registered object
+ *
+ * @param string $name
+ * @return object
+ */
+ function &get_registered_object($name) {
+ if (!isset($this->_reg_objects[$name]))
+ $this->_trigger_fatal_error("'$name' is not a registered object");
+
+ if (!is_object($this->_reg_objects[$name][0]))
+ $this->_trigger_fatal_error("registered '$name' is not an object");
+
+ return $this->_reg_objects[$name][0];
+ }
+
+ /**
+ * clear configuration values
+ *
+ * @param string $var
+ */
+ function clear_config($var = null)
+ {
+ if(!isset($var)) {
+ // clear all values
+ $this->_config = array(array('vars' => array(),
+ 'files' => array()));
+ } else {
+ unset($this->_config[0]['vars'][$var]);
+ }
+ }
+
+ /**
+ * get filepath of requested plugin
+ *
+ * @param string $type
+ * @param string $name
+ * @return string|false
+ */
+ function _get_plugin_filepath($type, $name)
+ {
+ $_params = array('type' => $type, 'name' => $name);
+ require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php');
+ return smarty_core_assemble_plugin_filepath($_params, $this);
+ }
+
+ /**
+ * test if resource needs compiling
+ *
+ * @param string $resource_name
+ * @param string $compile_path
+ * @return boolean
+ */
+ function _is_compiled($resource_name, $compile_path)
+ {
+ if (!$this->force_compile && file_exists($compile_path)) {
+ if (!$this->compile_check) {
+ // no need to check compiled file
+ return true;
+ } else {
+ // get file source and timestamp
+ $_params = array('resource_name' => $resource_name, 'get_source'=>false);
+ if (!$this->_fetch_resource_info($_params)) {
+ return false;
+ }
+ if ($_params['resource_timestamp'] <= filemtime($compile_path)) {
+ // template not expired, no recompile
+ return true;
+ } else {
+ // compile template
+ return false;
+ }
+ }
+ } else {
+ // compiled template does not exist, or forced compile
+ return false;
+ }
+ }
+
+ /**
+ * compile the template
+ *
+ * @param string $resource_name
+ * @param string $compile_path
+ * @return boolean
+ */
+ function _compile_resource($resource_name, $compile_path)
+ {
+
+ $_params = array('resource_name' => $resource_name);
+ if (!$this->_fetch_resource_info($_params)) {
+ return false;
+ }
+
+ $_source_content = $_params['source_content'];
+ $_cache_include = substr($compile_path, 0, -4).'.inc';
+
+ if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) {
+ // if a _cache_serial was set, we also have to write an include-file:
+ if ($this->_cache_include_info) {
+ require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php');
+ smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this);
+ }
+
+ $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content);
+ require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php');
+ smarty_core_write_compiled_resource($_params, $this);
+
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * compile the given source
+ *
+ * @param string $resource_name
+ * @param string $source_content
+ * @param string $compiled_content
+ * @return boolean
+ */
+ function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null)
+ {
+ if (file_exists(SMARTY_DIR . $this->compiler_file)) {
+ require_once(SMARTY_DIR . $this->compiler_file);
+ } else {
+ // use include_path
+ require_once($this->compiler_file);
+ }
+
+
+ $smarty_compiler = new $this->compiler_class;
+
+ $smarty_compiler->template_dir = $this->template_dir;
+ $smarty_compiler->compile_dir = $this->compile_dir;
+ $smarty_compiler->plugins_dir = $this->plugins_dir;
+ $smarty_compiler->config_dir = $this->config_dir;
+ $smarty_compiler->force_compile = $this->force_compile;
+ $smarty_compiler->caching = $this->caching;
+ $smarty_compiler->php_handling = $this->php_handling;
+ $smarty_compiler->left_delimiter = $this->left_delimiter;
+ $smarty_compiler->right_delimiter = $this->right_delimiter;
+ $smarty_compiler->_version = $this->_version;
+ $smarty_compiler->security = $this->security;
+ $smarty_compiler->secure_dir = $this->secure_dir;
+ $smarty_compiler->security_settings = $this->security_settings;
+ $smarty_compiler->trusted_dir = $this->trusted_dir;
+ $smarty_compiler->use_sub_dirs = $this->use_sub_dirs;
+ $smarty_compiler->_reg_objects = &$this->_reg_objects;
+ $smarty_compiler->_plugins = &$this->_plugins;
+ $smarty_compiler->_tpl_vars = &$this->_tpl_vars;
+ $smarty_compiler->default_modifiers = $this->default_modifiers;
+ $smarty_compiler->compile_id = $this->_compile_id;
+ $smarty_compiler->_config = $this->_config;
+ $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals;
+
+ if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) {
+ $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path];
+ }
+ $smarty_compiler->_cache_include = $cache_include_path;
+
+
+ $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content);
+
+ if ($smarty_compiler->_cache_serial) {
+ $this->_cache_include_info = array(
+ 'cache_serial'=>$smarty_compiler->_cache_serial
+ ,'plugins_code'=>$smarty_compiler->_plugins_code
+ ,'include_file_path' => $cache_include_path);
+
+ } else {
+ $this->_cache_include_info = null;
+
+ }
+
+ return $_results;
+ }
+
+ /**
+ * Get the compile path for this resource
+ *
+ * @param string $resource_name
+ * @return string results of {@link _get_auto_filename()}
+ */
+ function _get_compile_path($resource_name)
+ {
+ return $this->_get_auto_filename($this->compile_dir, $resource_name,
+ $this->_compile_id) . '.php';
+ }
+
+ /**
+ * fetch the template info. Gets timestamp, and source
+ * if get_source is true
+ *
+ * sets $source_content to the source of the template, and
+ * $resource_timestamp to its time stamp
+ * @param string $resource_name
+ * @param string $source_content
+ * @param integer $resource_timestamp
+ * @param boolean $get_source
+ * @param boolean $quiet
+ * @return boolean
+ */
+
+ function _fetch_resource_info(&$params)
+ {
+ if(!isset($params['get_source'])) { $params['get_source'] = true; }
+ if(!isset($params['quiet'])) { $params['quiet'] = false; }
+
+ $_return = false;
+ $_params = array('resource_name' => $params['resource_name']) ;
+ if (isset($params['resource_base_path']))
+ $_params['resource_base_path'] = $params['resource_base_path'];
+ else
+ $_params['resource_base_path'] = $this->template_dir;
+
+ if ($this->_parse_resource_name($_params)) {
+ $_resource_type = $_params['resource_type'];
+ $_resource_name = $_params['resource_name'];
+ switch ($_resource_type) {
+ case 'file':
+ if ($params['get_source']) {
+ $params['source_content'] = $this->_read_file($_resource_name);
+ }
+ $params['resource_timestamp'] = filemtime($_resource_name);
+ $_return = is_file($_resource_name);
+ break;
+
+ default:
+ // call resource functions to fetch the template source and timestamp
+ if ($params['get_source']) {
+ $_source_return = isset($this->_plugins['resource'][$_resource_type]) &&
+ call_user_func_array($this->_plugins['resource'][$_resource_type][0][0],
+ array($_resource_name, &$params['source_content'], &$this));
+ } else {
+ $_source_return = true;
+ }
+
+ $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) &&
+ call_user_func_array($this->_plugins['resource'][$_resource_type][0][1],
+ array($_resource_name, &$params['resource_timestamp'], &$this));
+
+ $_return = $_source_return && $_timestamp_return;
+ break;
+ }
+ }
+
+ if (!$_return) {
+ // see if we can get a template with the default template handler
+ if (!empty($this->default_template_handler_func)) {
+ if (!is_callable($this->default_template_handler_func)) {
+ $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist.");
+ } else {
+ $_return = call_user_func_array(
+ $this->default_template_handler_func,
+ array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this));
+ }
+ }
+ }
+
+ if (!$_return) {
+ if (!$params['quiet']) {
+ $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"');
+ }
+ } else if ($_return && $this->security) {
+ require_once(SMARTY_CORE_DIR . 'core.is_secure.php');
+ if (!smarty_core_is_secure($_params, $this)) {
+ if (!$params['quiet'])
+ $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed');
+ $params['source_content'] = null;
+ $params['resource_timestamp'] = null;
+ return false;
+ }
+ }
+ return $_return;
+ }
+
+
+ /**
+ * parse out the type and name from the resource
+ *
+ * @param string $resource_base_path
+ * @param string $resource_name
+ * @param string $resource_type
+ * @param string $resource_name
+ * @return boolean
+ */
+
+ function _parse_resource_name(&$params)
+ {
+
+ // split tpl_path by the first colon
+ $_resource_name_parts = explode(':', $params['resource_name'], 2);
+
+ if (count($_resource_name_parts) == 1) {
+ // no resource type given
+ $params['resource_type'] = $this->default_resource_type;
+ $params['resource_name'] = $_resource_name_parts[0];
+ } else {
+ if(strlen($_resource_name_parts[0]) == 1) {
+ // 1 char is not resource type, but part of filepath
+ $params['resource_type'] = $this->default_resource_type;
+ $params['resource_name'] = $params['resource_name'];
+ } else {
+ $params['resource_type'] = $_resource_name_parts[0];
+ $params['resource_name'] = $_resource_name_parts[1];
+ }
+ }
+
+ if ($params['resource_type'] == 'file') {
+ if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) {
+ // relative pathname to $params['resource_base_path']
+ // use the first directory where the file is found
+ foreach ((array)$params['resource_base_path'] as $_curr_path) {
+ $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name'];
+ if (file_exists($_fullpath) && is_file($_fullpath)) {
+ $params['resource_name'] = $_fullpath;
+ return true;
+ }
+ // didn't find the file, try include_path
+ $_params = array('file_path' => $_fullpath);
+ require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');
+ if(smarty_core_get_include_path($_params, $this)) {
+ $params['resource_name'] = $_params['new_file_path'];
+ return true;
+ }
+ }
+ return false;
+ } else {
+ /* absolute path */
+ return file_exists($params['resource_name']);
+ }
+ } elseif (empty($this->_plugins['resource'][$params['resource_type']])) {
+ $_params = array('type' => $params['resource_type']);
+ require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php');
+ smarty_core_load_resource_plugin($_params, $this);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Handle modifiers
+ *
+ * @param string|null $modifier_name
+ * @param array|null $map_array
+ * @return string result of modifiers
+ */
+ function _run_mod_handler()
+ {
+ $_args = func_get_args();
+ list($_modifier_name, $_map_array) = array_splice($_args, 0, 2);
+ list($_func_name, $_tpl_file, $_tpl_line) =
+ $this->_plugins['modifier'][$_modifier_name];
+
+ $_var = $_args[0];
+ foreach ($_var as $_key => $_val) {
+ $_args[0] = $_val;
+ $_var[$_key] = call_user_func_array($_func_name, $_args);
+ }
+ return $_var;
+ }
+
+ /**
+ * Remove starting and ending quotes from the string
+ *
+ * @param string $string
+ * @return string
+ */
+ function _dequote($string)
+ {
+ if ((substr($string, 0, 1) == "'" || substr($string, 0, 1) == '"') &&
+ substr($string, -1) == substr($string, 0, 1))
+ return substr($string, 1, -1);
+ else
+ return $string;
+ }
+
+
+ /**
+ * read in a file
+ *
+ * @param string $filename
+ * @return string
+ */
+ function _read_file($filename)
+ {
+ if ( file_exists($filename) && ($fd = @fopen($filename, 'rb')) ) {
+ $contents = '';
+ while (!feof($fd)) {
+ $contents .= fread($fd, 8192);
+ }
+ fclose($fd);
+ return $contents;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * get a concrete filename for automagically created content
+ *
+ * @param string $auto_base
+ * @param string $auto_source
+ * @param string $auto_id
+ * @return string
+ * @staticvar string|null
+ * @staticvar string|null
+ */
+ function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null)
+ {
+ $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^';
+ $_return = $auto_base . DIRECTORY_SEPARATOR;
+
+ if(isset($auto_id)) {
+ // make auto_id safe for directory names
+ $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id)));
+ // split into separate directories
+ $_return .= $auto_id . $_compile_dir_sep;
+ }
+
+ if(isset($auto_source)) {
+ // make source name safe for filename
+ $_filename = urlencode(basename($auto_source));
+ $_crc32 = sprintf('%08X', crc32($auto_source));
+ // prepend %% to avoid name conflicts with
+ // with $params['auto_id'] names
+ $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep .
+ substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32;
+ $_return .= '%%' . $_crc32 . '%%' . $_filename;
+ }
+
+ return $_return;
+ }
+
+ /**
+ * unlink a file, possibly using expiration time
+ *
+ * @param string $resource
+ * @param integer $exp_time
+ */
+ function _unlink($resource, $exp_time = null)
+ {
+ if(isset($exp_time)) {
+ if(time() - @filemtime($resource) >= $exp_time) {
+ return @unlink($resource);
+ }
+ } else {
+ return @unlink($resource);
+ }
+ }
+
+ /**
+ * returns an auto_id for auto-file-functions
+ *
+ * @param string $cache_id
+ * @param string $compile_id
+ * @return string|null
+ */
+ function _get_auto_id($cache_id=null, $compile_id=null) {
+ if (isset($cache_id))
+ return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id;
+ elseif(isset($compile_id))
+ return $compile_id;
+ else
+ return null;
+ }
+
+ /**
+ * trigger Smarty plugin error
+ *
+ * @param string $error_msg
+ * @param string $tpl_file
+ * @param integer $tpl_line
+ * @param string $file
+ * @param integer $line
+ * @param integer $error_type
+ */
+ function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null,
+ $file = null, $line = null, $error_type = E_USER_ERROR)
+ {
+ if(isset($file) && isset($line)) {
+ $info = ' ('.basename($file).", line $line)";
+ } else {
+ $info = '';
+ }
+ if (isset($tpl_line) && isset($tpl_file)) {
+ $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type);
+ } else {
+ $this->trigger_error($error_msg . $info, $error_type);
+ }
+ }
+
+
+ /**
+ * callback function for preg_replace, to call a non-cacheable block
+ * @return string
+ */
+ function _process_compiled_include_callback($match) {
+ $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3];
+ ob_start();
+ $_func($this);
+ $_ret = ob_get_contents();
+ ob_end_clean();
+ return $_ret;
+ }
+
+
+ /**
+ * called for included templates
+ *
+ * @param string $_smarty_include_tpl_file
+ * @param string $_smarty_include_vars
+ */
+
+ // $_smarty_include_tpl_file, $_smarty_include_vars
+
+ function _smarty_include($params)
+ {
+ if ($this->debugging) {
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $debug_start_time = smarty_core_get_microtime($_params, $this);
+ $this->_smarty_debug_info[] = array('type' => 'template',
+ 'filename' => $params['smarty_include_tpl_file'],
+ 'depth' => ++$this->_inclusion_depth);
+ $included_tpls_idx = count($this->_smarty_debug_info) - 1;
+ }
+
+ $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']);
+
+ // config vars are treated as local, so push a copy of the
+ // current ones onto the front of the stack
+ array_unshift($this->_config, $this->_config[0]);
+
+ $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']);
+
+
+ if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path)
+ || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path))
+ {
+ include($_smarty_compile_path);
+ }
+
+ // pop the local vars off the front of the stack
+ array_shift($this->_config);
+
+ $this->_inclusion_depth--;
+
+ if ($this->debugging) {
+ // capture time for debugging info
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time;
+ }
+
+ if ($this->caching) {
+ $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true;
+ }
+ }
+
+
+ /**
+ * get or set an array of cached attributes for function that is
+ * not cacheable
+ * @return array
+ */
+ function &_smarty_cache_attrs($cache_serial, $count) {
+ $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count];
+
+ if ($this->_cache_including) {
+ /* return next set of cache_attrs */
+ $_return = current($_cache_attrs);
+ next($_cache_attrs);
+ return $_return;
+
+ } else {
+ /* add a reference to a new set of cache_attrs */
+ $_cache_attrs[] = array();
+ return $_cache_attrs[count($_cache_attrs)-1];
+
+ }
+
+ }
+
+
+ /**
+ * wrapper for include() retaining $this
+ * @return mixed
+ */
+ function _include($filename, $once=false, $params=null)
+ {
+ if ($once) {
+ return include_once($filename);
+ } else {
+ return include($filename);
+ }
+ }
+
+
+ /**
+ * wrapper for eval() retaining $this
+ * @return mixed
+ */
+ function _eval($code, $params=null)
+ {
+ return eval($code);
+ }
+ /**#@-*/
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/Smarty_Compiler.class.php b/lib/smarty-2.6.8/Smarty_Compiler.class.php
new file mode 100644
index 0000000..f54cc21
--- /dev/null
+++ b/lib/smarty-2.6.8/Smarty_Compiler.class.php
@@ -0,0 +1,2327 @@
+<?php
+
+/**
+ * Project: Smarty: the PHP compiling template engine
+ * File: Smarty_Compiler.class.php
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * @link http://smarty.php.net/
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author Andrei Zmievski <andrei@php.net>
+ * @version 2.6.18
+ * @copyright 2001-2005 New Digital Group, Inc.
+ * @package Smarty
+ */
+
+/* $Id: Smarty_Compiler.class.php,v 1.395 2007/03/06 10:40:06 messju Exp $ */
+
+/**
+ * Template compiling class
+ * @package Smarty
+ */
+class Smarty_Compiler extends Smarty {
+
+ // internal vars
+ /**#@+
+ * @access private
+ */
+ var $_folded_blocks = array(); // keeps folded template blocks
+ var $_current_file = null; // the current template being compiled
+ var $_current_line_no = 1; // line number for error messages
+ var $_capture_stack = array(); // keeps track of nested capture buffers
+ var $_plugin_info = array(); // keeps track of plugins to load
+ var $_init_smarty_vars = false;
+ var $_permitted_tokens = array('true','false','yes','no','on','off','null');
+ var $_db_qstr_regexp = null; // regexps are setup in the constructor
+ var $_si_qstr_regexp = null;
+ var $_qstr_regexp = null;
+ var $_func_regexp = null;
+ var $_reg_obj_regexp = null;
+ var $_var_bracket_regexp = null;
+ var $_num_const_regexp = null;
+ var $_dvar_guts_regexp = null;
+ var $_dvar_regexp = null;
+ var $_cvar_regexp = null;
+ var $_svar_regexp = null;
+ var $_avar_regexp = null;
+ var $_mod_regexp = null;
+ var $_var_regexp = null;
+ var $_parenth_param_regexp = null;
+ var $_func_call_regexp = null;
+ var $_obj_ext_regexp = null;
+ var $_obj_start_regexp = null;
+ var $_obj_params_regexp = null;
+ var $_obj_call_regexp = null;
+ var $_cacheable_state = 0;
+ var $_cache_attrs_count = 0;
+ var $_nocache_count = 0;
+ var $_cache_serial = null;
+ var $_cache_include = null;
+
+ var $_strip_depth = 0;
+ var $_additional_newline = "\n";
+
+ /**#@-*/
+ /**
+ * The class constructor.
+ */
+ function Smarty_Compiler()
+ {
+ // matches double quoted strings:
+ // "foobar"
+ // "foo\"bar"
+ $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
+
+ // matches single quoted strings:
+ // 'foobar'
+ // 'foo\'bar'
+ $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
+
+ // matches single or double quoted strings
+ $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
+
+ // matches bracket portion of vars
+ // [0]
+ // [foo]
+ // [$bar]
+ $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
+
+ // matches numerical constants
+ // 30
+ // -12
+ // 13.22
+ $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)';
+
+ // matches $ vars (not objects):
+ // $foo
+ // $foo.bar
+ // $foo.bar.foobar
+ // $foo[0]
+ // $foo[$bar]
+ // $foo[5][blah]
+ // $foo[5].bar[$foobar][4]
+ $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))';
+ $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]';
+ $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
+ . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';
+ $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
+
+ // matches config vars:
+ // #foo#
+ // #foobar123_foo#
+ $this->_cvar_regexp = '\#\w+\#';
+
+ // matches section vars:
+ // %foo.bar%
+ $this->_svar_regexp = '\%\w+\.\w+\%';
+
+ // matches all valid variables (no quotes, no modifiers)
+ $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'
+ . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';
+
+ // matches valid variable syntax:
+ // $foo
+ // $foo
+ // #foo#
+ // #foo#
+ // "text"
+ // "text"
+ $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')';
+
+ // matches valid object call (one level of object nesting allowed in parameters):
+ // $foo->bar
+ // $foo->bar()
+ // $foo->bar("text")
+ // $foo->bar($foo, $bar, "text")
+ // $foo->bar($foo, "foo")
+ // $foo->bar->foo()
+ // $foo->bar->foo->bar()
+ // $foo->bar($foo->bar)
+ // $foo->bar($foo->bar())
+ // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar))
+ $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
+ $this->_obj_restricted_param_regexp = '(?:'
+ . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')'
+ . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)';
+ $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
+ . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)';
+ $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp
+ . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)';
+ $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
+ $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)';
+
+ // matches valid modifier syntax:
+ // |foo
+ // |@foo
+ // |foo:"bar"
+ // |foo:$bar
+ // |foo:"bar":$foobar
+ // |foo|bar
+ // |foo:$foo->bar
+ $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|'
+ . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
+
+ // matches valid function name:
+ // foo123
+ // _foo_bar
+ $this->_func_regexp = '[a-zA-Z_]\w*';
+
+ // matches valid registered object:
+ // foo->bar
+ $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*';
+
+ // matches valid parameter values:
+ // true
+ // $foo
+ // $foo|bar
+ // #foo#
+ // #foo#|bar
+ // "text"
+ // "text"|bar
+ // $foo->bar
+ $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|'
+ . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)';
+
+ // matches valid parenthesised function parameters:
+ //
+ // "text"
+ // $foo, $bar, "text"
+ // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
+ $this->_parenth_param_regexp = '(?:\((?:\w+|'
+ . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
+ . $this->_param_regexp . ')))*)?\))';
+
+ // matches valid function call:
+ // foo()
+ // foo_bar($foo)
+ // _foo_bar($foo,"bar")
+ // foo123($foo,$foo->bar(),"foo")
+ $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:'
+ . $this->_parenth_param_regexp . '))';
+ }
+
+ /**
+ * compile a resource
+ *
+ * sets $compiled_content to the compiled source
+ * @param string $resource_name
+ * @param string $source_content
+ * @param string $compiled_content
+ * @return true
+ */
+ function _compile_file($resource_name, $source_content, &$compiled_content)
+ {
+
+ if ($this->security) {
+ // do not allow php syntax to be executed unless specified
+ if ($this->php_handling == SMARTY_PHP_ALLOW &&
+ !$this->security_settings['PHP_HANDLING']) {
+ $this->php_handling = SMARTY_PHP_PASSTHRU;
+ }
+ }
+
+ $this->_load_filters();
+
+ $this->_current_file = $resource_name;
+ $this->_current_line_no = 1;
+ $ldq = preg_quote($this->left_delimiter, '~');
+ $rdq = preg_quote($this->right_delimiter, '~');
+
+ // run template source through prefilter functions
+ if (count($this->_plugins['prefilter']) > 0) {
+ foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
+ if ($prefilter === false) continue;
+ if ($prefilter[3] || is_callable($prefilter[0])) {
+ $source_content = call_user_func_array($prefilter[0],
+ array($source_content, &$this));
+ $this->_plugins['prefilter'][$filter_name][3] = true;
+ } else {
+ $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented");
+ }
+ }
+ }
+
+ /* fetch all special blocks */
+ $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s";
+
+ preg_match_all($search, $source_content, $match, PREG_SET_ORDER);
+ $this->_folded_blocks = $match;
+ reset($this->_folded_blocks);
+
+ /* replace special blocks by "{php}" */
+ $source_content = preg_replace($search.'e', "'"
+ . $this->_quote_replace($this->left_delimiter) . 'php'
+ . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'"
+ . $this->_quote_replace($this->right_delimiter)
+ . "'"
+ , $source_content);
+
+ /* Gather all template tags. */
+ preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match);
+ $template_tags = $_match[1];
+ /* Split content by template tags to obtain non-template content. */
+ $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content);
+
+ /* loop through text blocks */
+ for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
+ /* match anything resembling php tags */
+ if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) {
+ /* replace tags with placeholders to prevent recursive replacements */
+ $sp_match[1] = array_unique($sp_match[1]);
+ usort($sp_match[1], '_smarty_sort_length');
+ for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
+ $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]);
+ }
+ /* process each one */
+ for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
+ if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
+ /* echo php contents */
+ $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
+ } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
+ /* quote php tags */
+ $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]);
+ } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
+ /* remove php tags */
+ $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);
+ } else {
+ /* SMARTY_PHP_ALLOW, but echo non php starting tags */
+ $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
+ $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
+ }
+ }
+ }
+ }
+
+ /* Compile the template tags into PHP code. */
+ $compiled_tags = array();
+ for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {
+ $this->_current_line_no += substr_count($text_blocks[$i], "\n");
+ $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
+ $this->_current_line_no += substr_count($template_tags[$i], "\n");
+ }
+ if (count($this->_tag_stack)>0) {
+ list($_open_tag, $_line_no) = end($this->_tag_stack);
+ $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__);
+ return;
+ }
+
+ /* Reformat $text_blocks between 'strip' and '/strip' tags,
+ removing spaces, tabs and newlines. */
+ $strip = false;
+ for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
+ if ($compiled_tags[$i] == '{strip}') {
+ $compiled_tags[$i] = '';
+ $strip = true;
+ /* remove leading whitespaces */
+ $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]);
+ }
+ if ($strip) {
+ /* strip all $text_blocks before the next '/strip' */
+ for ($j = $i + 1; $j < $for_max; $j++) {
+ /* remove leading and trailing whitespaces of each line */
+ $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]);
+ if ($compiled_tags[$j] == '{/strip}') {
+ /* remove trailing whitespaces from the last text_block */
+ $text_blocks[$j] = rtrim($text_blocks[$j]);
+ }
+ $text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>";
+ if ($compiled_tags[$j] == '{/strip}') {
+ $compiled_tags[$j] = "\n"; /* slurped by php, but necessary
+ if a newline is following the closing strip-tag */
+ $strip = false;
+ $i = $j;
+ break;
+ }
+ }
+ }
+ }
+ $compiled_content = '';
+
+ $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%';
+
+ /* Interleave the compiled contents and text blocks to get the final result. */
+ for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
+ if ($compiled_tags[$i] == '') {
+ // tag result empty, remove first newline from following text block
+ $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]);
+ }
+ // replace legit PHP tags with placeholder
+ $text_blocks[$i] = str_replace('<?', $tag_guard, $text_blocks[$i]);
+ $compiled_tags[$i] = str_replace('<?', $tag_guard, $compiled_tags[$i]);
+
+ $compiled_content .= $text_blocks[$i] . $compiled_tags[$i];
+ }
+ $compiled_content .= str_replace('<?', $tag_guard, $text_blocks[$i]);
+
+ // escape php tags created by interleaving
+ $compiled_content = str_replace('<?', "<?php echo '<?' ?>\n", $compiled_content);
+ $compiled_content = preg_replace("~(?<!')language\s*=\s*[\"\']?\s*php\s*[\"\']?~", "<?php echo 'language=php' ?>\n", $compiled_content);
+
+ // recover legit tags
+ $compiled_content = str_replace($tag_guard, '<?', $compiled_content);
+
+ // remove \n from the end of the file, if any
+ if (strlen($compiled_content) && (substr($compiled_content, -1) == "\n") ) {
+ $compiled_content = substr($compiled_content, 0, -1);
+ }
+
+ if (!empty($this->_cache_serial)) {
+ $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content;
+ }
+
+ // run compiled template through postfilter functions
+ if (count($this->_plugins['postfilter']) > 0) {
+ foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
+ if ($postfilter === false) continue;
+ if ($postfilter[3] || is_callable($postfilter[0])) {
+ $compiled_content = call_user_func_array($postfilter[0],
+ array($compiled_content, &$this));
+ $this->_plugins['postfilter'][$filter_name][3] = true;
+ } else {
+ $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented");
+ }
+ }
+ }
+
+ // put header at the top of the compiled template
+ $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
+ $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n";
+
+ /* Emit code to load needed plugins. */
+ $this->_plugins_code = '';
+ if (count($this->_plugin_info)) {
+ $_plugins_params = "array('plugins' => array(";
+ foreach ($this->_plugin_info as $plugin_type => $plugins) {
+ foreach ($plugins as $plugin_name => $plugin_info) {
+ $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], ";
+ $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';
+ }
+ }
+ $_plugins_params .= '))';
+ $plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
+ $template_header .= $plugins_code;
+ $this->_plugin_info = array();
+ $this->_plugins_code = $plugins_code;
+ }
+
+ if ($this->_init_smarty_vars) {
+ $template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
+ $this->_init_smarty_vars = false;
+ }
+
+ $compiled_content = $template_header . $compiled_content;
+ return true;
+ }
+
+ /**
+ * Compile a template tag
+ *
+ * @param string $template_tag
+ * @return string
+ */
+ function _compile_tag($template_tag)
+ {
+ /* Matched comment. */
+ if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*')
+ return '';
+
+ /* Split tag into two three parts: command, command modifiers and the arguments. */
+ if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp
+ . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))
+ (?:\s+(.*))?$
+ ~xs', $template_tag, $match)) {
+ $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ $tag_command = $match[1];
+ $tag_modifier = isset($match[2]) ? $match[2] : null;
+ $tag_args = isset($match[3]) ? $match[3] : null;
+
+ if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) {
+ /* tag name is a variable or object */
+ $_return = $this->_parse_var_props($tag_command . $tag_modifier);
+ return "<?php echo $_return; ?>" . $this->_additional_newline;
+ }
+
+ /* If the tag name is a registered object, we process it. */
+ if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) {
+ return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);
+ }
+
+ switch ($tag_command) {
+ case 'include':
+ return $this->_compile_include_tag($tag_args);
+
+ case 'include_php':
+ return $this->_compile_include_php_tag($tag_args);
+
+ case 'if':
+ $this->_push_tag('if');
+ return $this->_compile_if_tag($tag_args);
+
+ case 'else':
+ list($_open_tag) = end($this->_tag_stack);
+ if ($_open_tag != 'if' && $_open_tag != 'elseif')
+ $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);
+ else
+ $this->_push_tag('else');
+ return '<?php else: ?>';
+
+ case 'elseif':
+ list($_open_tag) = end($this->_tag_stack);
+ if ($_open_tag != 'if' && $_open_tag != 'elseif')
+ $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
+ if ($_open_tag == 'if')
+ $this->_push_tag('elseif');
+ return $this->_compile_if_tag($tag_args, true);
+
+ case '/if':
+ $this->_pop_tag('if');
+ return '<?php endif; ?>';
+
+ case 'capture':
+ return $this->_compile_capture_tag(true, $tag_args);
+
+ case '/capture':
+ return $this->_compile_capture_tag(false);
+
+ case 'ldelim':
+ return $this->left_delimiter;
+
+ case 'rdelim':
+ return $this->right_delimiter;
+
+ case 'section':
+ $this->_push_tag('section');
+ return $this->_compile_section_start($tag_args);
+
+ case 'sectionelse':
+ $this->_push_tag('sectionelse');
+ return "<?php endfor; else: ?>";
+ break;
+
+ case '/section':
+ $_open_tag = $this->_pop_tag('section');
+ if ($_open_tag == 'sectionelse')
+ return "<?php endif; ?>";
+ else
+ return "<?php endfor; endif; ?>";
+
+ case 'foreach':
+ $this->_push_tag('foreach');
+ return $this->_compile_foreach_start($tag_args);
+ break;
+
+ case 'foreachelse':
+ $this->_push_tag('foreachelse');
+ return "<?php endforeach; else: ?>";
+
+ case '/foreach':
+ $_open_tag = $this->_pop_tag('foreach');
+ if ($_open_tag == 'foreachelse')
+ return "<?php endif; unset(\$_from); ?>";
+ else
+ return "<?php endforeach; endif; unset(\$_from); ?>";
+ break;
+
+ case 'strip':
+ case '/strip':
+ if (substr($tag_command, 0, 1)=='/') {
+ $this->_pop_tag('strip');
+ if (--$this->_strip_depth==0) { /* outermost closing {/strip} */
+ $this->_additional_newline = "\n";
+ return '{' . $tag_command . '}';
+ }
+ } else {
+ $this->_push_tag('strip');
+ if ($this->_strip_depth++==0) { /* outermost opening {strip} */
+ $this->_additional_newline = "";
+ return '{' . $tag_command . '}';
+ }
+ }
+ return '';
+
+ case 'php':
+ /* handle folded tags replaced by {php} */
+ list(, $block) = each($this->_folded_blocks);
+ $this->_current_line_no += substr_count($block[0], "\n");
+ /* the number of matched elements in the regexp in _compile_file()
+ determins the type of folded tag that was found */
+ switch (count($block)) {
+ case 2: /* comment */
+ return '';
+
+ case 3: /* literal */
+ return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline;
+
+ case 4: /* php */
+ if ($this->security && !$this->security_settings['PHP_TAGS']) {
+ $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__);
+ return;
+ }
+ return '<?php ' . $block[3] .' ?>';
+ }
+ break;
+
+ case 'insert':
+ return $this->_compile_insert_tag($tag_args);
+
+ default:
+ if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
+ return $output;
+ } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
+ return $output;
+ } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {
+ return $output;
+ } else {
+ $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ }
+ }
+
+
+ /**
+ * compile the custom compiler tag
+ *
+ * sets $output to the compiled custom compiler tag
+ * @param string $tag_command
+ * @param string $tag_args
+ * @param string $output
+ * @return boolean
+ */
+ function _compile_compiler_tag($tag_command, $tag_args, &$output)
+ {
+ $found = false;
+ $have_function = true;
+
+ /*
+ * First we check if the compiler function has already been registered
+ * or loaded from a plugin file.
+ */
+ if (isset($this->_plugins['compiler'][$tag_command])) {
+ $found = true;
+ $plugin_func = $this->_plugins['compiler'][$tag_command][0];
+ if (!is_callable($plugin_func)) {
+ $message = "compiler function '$tag_command' is not implemented";
+ $have_function = false;
+ }
+ }
+ /*
+ * Otherwise we need to load plugin file and look for the function
+ * inside it.
+ */
+ else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) {
+ $found = true;
+
+ include_once $plugin_file;
+
+ $plugin_func = 'smarty_compiler_' . $tag_command;
+ if (!is_callable($plugin_func)) {
+ $message = "plugin function $plugin_func() not found in $plugin_file\n";
+ $have_function = false;
+ } else {
+ $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true);
+ }
+ }
+
+ /*
+ * True return value means that we either found a plugin or a
+ * dynamically registered function. False means that we didn't and the
+ * compiler should now emit code to load custom function plugin for this
+ * tag.
+ */
+ if ($found) {
+ if ($have_function) {
+ $output = call_user_func_array($plugin_func, array($tag_args, &$this));
+ if($output != '') {
+ $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command)
+ . $output
+ . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>';
+ }
+ } else {
+ $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * compile block function tag
+ *
+ * sets $output to compiled block function tag
+ * @param string $tag_command
+ * @param string $tag_args
+ * @param string $tag_modifier
+ * @param string $output
+ * @return boolean
+ */
+ function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output)
+ {
+ if (substr($tag_command, 0, 1) == '/') {
+ $start_tag = false;
+ $tag_command = substr($tag_command, 1);
+ } else
+ $start_tag = true;
+
+ $found = false;
+ $have_function = true;
+
+ /*
+ * First we check if the block function has already been registered
+ * or loaded from a plugin file.
+ */
+ if (isset($this->_plugins['block'][$tag_command])) {
+ $found = true;
+ $plugin_func = $this->_plugins['block'][$tag_command][0];
+ if (!is_callable($plugin_func)) {
+ $message = "block function '$tag_command' is not implemented";
+ $have_function = false;
+ }
+ }
+ /*
+ * Otherwise we need to load plugin file and look for the function
+ * inside it.
+ */
+ else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) {
+ $found = true;
+
+ include_once $plugin_file;
+
+ $plugin_func = 'smarty_block_' . $tag_command;
+ if (!function_exists($plugin_func)) {
+ $message = "plugin function $plugin_func() not found in $plugin_file\n";
+ $have_function = false;
+ } else {
+ $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);
+
+ }
+ }
+
+ if (!$found) {
+ return false;
+ } else if (!$have_function) {
+ $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
+ return true;
+ }
+
+ /*
+ * Even though we've located the plugin function, compilation
+ * happens only once, so the plugin will still need to be loaded
+ * at runtime for future requests.
+ */
+ $this->_add_plugin('block', $tag_command);
+
+ if ($start_tag)
+ $this->_push_tag($tag_command);
+ else
+ $this->_pop_tag($tag_command);
+
+ if ($start_tag) {
+ $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command);
+ $attrs = $this->_parse_attrs($tag_args);
+ $_cache_attrs='';
+ $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs);
+ $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); ';
+ $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);';
+ $output .= 'while ($_block_repeat) { ob_start(); ?>';
+ } else {
+ $output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); ';
+ $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)';
+ if ($tag_modifier != '') {
+ $this->_parse_modifiers($_out_tag_text, $tag_modifier);
+ }
+ $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } ';
+ $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>';
+ }
+
+ return true;
+ }
+
+
+ /**
+ * compile custom function tag
+ *
+ * @param string $tag_command
+ * @param string $tag_args
+ * @param string $tag_modifier
+ * @return string
+ */
+ function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output)
+ {
+ $found = false;
+ $have_function = true;
+
+ /*
+ * First we check if the custom function has already been registered
+ * or loaded from a plugin file.
+ */
+ if (isset($this->_plugins['function'][$tag_command])) {
+ $found = true;
+ $plugin_func = $this->_plugins['function'][$tag_command][0];
+ if (!is_callable($plugin_func)) {
+ $message = "custom function '$tag_command' is not implemented";
+ $have_function = false;
+ }
+ }
+ /*
+ * Otherwise we need to load plugin file and look for the function
+ * inside it.
+ */
+ else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) {
+ $found = true;
+
+ include_once $plugin_file;
+
+ $plugin_func = 'smarty_function_' . $tag_command;
+ if (!function_exists($plugin_func)) {
+ $message = "plugin function $plugin_func() not found in $plugin_file\n";
+ $have_function = false;
+ } else {
+ $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true);
+
+ }
+ }
+
+ if (!$found) {
+ return false;
+ } else if (!$have_function) {
+ $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
+ return true;
+ }
+
+ /* declare plugin to be loaded on display of the template that
+ we compile right now */
+ $this->_add_plugin('function', $tag_command);
+
+ $_cacheable_state = $this->_push_cacheable_state('function', $tag_command);
+ $attrs = $this->_parse_attrs($tag_args);
+ $_cache_attrs = '';
+ $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs);
+
+ $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)";
+ if($tag_modifier != '') {
+ $this->_parse_modifiers($output, $tag_modifier);
+ }
+
+ if($output != '') {
+ $output = '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';'
+ . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline;
+ }
+
+ return true;
+ }
+
+ /**
+ * compile a registered object tag
+ *
+ * @param string $tag_command
+ * @param array $attrs
+ * @param string $tag_modifier
+ * @return string
+ */
+ function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier)
+ {
+ if (substr($tag_command, 0, 1) == '/') {
+ $start_tag = false;
+ $tag_command = substr($tag_command, 1);
+ } else {
+ $start_tag = true;
+ }
+
+ list($object, $obj_comp) = explode('->', $tag_command);
+
+ $arg_list = array();
+ if(count($attrs)) {
+ $_assign_var = false;
+ foreach ($attrs as $arg_name => $arg_value) {
+ if($arg_name == 'assign') {
+ $_assign_var = $arg_value;
+ unset($attrs['assign']);
+ continue;
+ }
+ if (is_bool($arg_value))
+ $arg_value = $arg_value ? 'true' : 'false';
+ $arg_list[] = "'$arg_name' => $arg_value";
+ }
+ }
+
+ if($this->_reg_objects[$object][2]) {
+ // smarty object argument format
+ $args = "array(".implode(',', (array)$arg_list)."), \$this";
+ } else {
+ // traditional argument format
+ $args = implode(',', array_values($attrs));
+ if (empty($args)) {
+ $args = 'null';
+ }
+ }
+
+ $prefix = '';
+ $postfix = '';
+ $newline = '';
+ if(!is_object($this->_reg_objects[$object][0])) {
+ $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
+ } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) {
+ $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
+ } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) {
+ // method
+ if(in_array($obj_comp, $this->_reg_objects[$object][3])) {
+ // block method
+ if ($start_tag) {
+ $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); ";
+ $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); ";
+ $prefix .= "while (\$_block_repeat) { ob_start();";
+ $return = null;
+ $postfix = '';
+ } else {
+ $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;";
+ $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)";
+ $postfix = "} array_pop(\$this->_tag_stack);";
+ }
+ } else {
+ // non-block method
+ $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)";
+ }
+ } else {
+ // property
+ $return = "\$this->_reg_objects['$object'][0]->$obj_comp";
+ }
+
+ if($return != null) {
+ if($tag_modifier != '') {
+ $this->_parse_modifiers($return, $tag_modifier);
+ }
+
+ if(!empty($_assign_var)) {
+ $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);";
+ } else {
+ $output = 'echo ' . $return . ';';
+ $newline = $this->_additional_newline;
+ }
+ } else {
+ $output = '';
+ }
+
+ return '<?php ' . $prefix . $output . $postfix . "?>" . $newline;
+ }
+
+ /**
+ * Compile {insert ...} tag
+ *
+ * @param string $tag_args
+ * @return string
+ */
+ function _compile_insert_tag($tag_args)
+ {
+ $attrs = $this->_parse_attrs($tag_args);
+ $name = $this->_dequote($attrs['name']);
+
+ if (empty($name)) {
+ return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ if (!preg_match('~^\w+$~', $name)) {
+ return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ if (!empty($attrs['script'])) {
+ $delayed_loading = true;
+ } else {
+ $delayed_loading = false;
+ }
+
+ foreach ($attrs as $arg_name => $arg_value) {
+ if (is_bool($arg_value))
+ $arg_value = $arg_value ? 'true' : 'false';
+ $arg_list[] = "'$arg_name' => $arg_value";
+ }
+
+ $this->_add_plugin('insert', $name, $delayed_loading);
+
+ $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))";
+
+ return "<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline;
+ }
+
+ /**
+ * Compile {include ...} tag
+ *
+ * @param string $tag_args
+ * @return string
+ */
+ function _compile_include_tag($tag_args)
+ {
+ $attrs = $this->_parse_attrs($tag_args);
+ $arg_list = array();
+
+ if (empty($attrs['file'])) {
+ $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ foreach ($attrs as $arg_name => $arg_value) {
+ if ($arg_name == 'file') {
+ $include_file = $arg_value;
+ continue;
+ } else if ($arg_name == 'assign') {
+ $assign_var = $arg_value;
+ continue;
+ }
+ if (is_bool($arg_value))
+ $arg_value = $arg_value ? 'true' : 'false';
+ $arg_list[] = "'$arg_name' => $arg_value";
+ }
+
+ $output = '<?php ';
+
+ if (isset($assign_var)) {
+ $output .= "ob_start();\n";
+ }
+
+ $output .=
+ "\$_smarty_tpl_vars = \$this->_tpl_vars;\n";
+
+
+ $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
+ $output .= "\$this->_smarty_include($_params);\n" .
+ "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
+ "unset(\$_smarty_tpl_vars);\n";
+
+ if (isset($assign_var)) {
+ $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
+ }
+
+ $output .= ' ?>';
+
+ return $output;
+
+ }
+
+ /**
+ * Compile {include ...} tag
+ *
+ * @param string $tag_args
+ * @return string
+ */
+ function _compile_include_php_tag($tag_args)
+ {
+ $attrs = $this->_parse_attrs($tag_args);
+
+ if (empty($attrs['file'])) {
+ $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']);
+ $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true';
+
+ $arg_list = array();
+ foreach($attrs as $arg_name => $arg_value) {
+ if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') {
+ if(is_bool($arg_value))
+ $arg_value = $arg_value ? 'true' : 'false';
+ $arg_list[] = "'$arg_name' => $arg_value";
+ }
+ }
+
+ $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))";
+
+ return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
+ }
+
+
+ /**
+ * Compile {section ...} tag
+ *
+ * @param string $tag_args
+ * @return string
+ */
+ function _compile_section_start($tag_args)
+ {
+ $attrs = $this->_parse_attrs($tag_args);
+ $arg_list = array();
+
+ $output = '<?php ';
+ $section_name = $attrs['name'];
+ if (empty($section_name)) {
+ $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ $output .= "unset(\$this->_sections[$section_name]);\n";
+ $section_props = "\$this->_sections[$section_name]";
+
+ foreach ($attrs as $attr_name => $attr_value) {
+ switch ($attr_name) {
+ case 'loop':
+ $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n";
+ break;
+
+ case 'show':
+ if (is_bool($attr_value))
+ $show_attr_value = $attr_value ? 'true' : 'false';
+ else
+ $show_attr_value = "(bool)$attr_value";
+ $output .= "{$section_props}['show'] = $show_attr_value;\n";
+ break;
+
+ case 'name':
+ $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
+ break;
+
+ case 'max':
+ case 'start':
+ $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n";
+ break;
+
+ case 'step':
+ $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n";
+ break;
+
+ default:
+ $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__);
+ break;
+ }
+ }
+
+ if (!isset($attrs['show']))
+ $output .= "{$section_props}['show'] = true;\n";
+
+ if (!isset($attrs['loop']))
+ $output .= "{$section_props}['loop'] = 1;\n";
+
+ if (!isset($attrs['max']))
+ $output .= "{$section_props}['max'] = {$section_props}['loop'];\n";
+ else
+ $output .= "if ({$section_props}['max'] < 0)\n" .
+ " {$section_props}['max'] = {$section_props}['loop'];\n";
+
+ if (!isset($attrs['step']))
+ $output .= "{$section_props}['step'] = 1;\n";
+
+ if (!isset($attrs['start']))
+ $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n";
+ else {
+ $output .= "if ({$section_props}['start'] < 0)\n" .
+ " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" .
+ "else\n" .
+ " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n";
+ }
+
+ $output .= "if ({$section_props}['show']) {\n";
+ if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) {
+ $output .= " {$section_props}['total'] = {$section_props}['loop'];\n";
+ } else {
+ $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n";
+ }
+ $output .= " if ({$section_props}['total'] == 0)\n" .
+ " {$section_props}['show'] = false;\n" .
+ "} else\n" .
+ " {$section_props}['total'] = 0;\n";
+
+ $output .= "if ({$section_props}['show']):\n";
+ $output .= "
+ for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;
+ {$section_props}['iteration'] <= {$section_props}['total'];
+ {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n";
+ $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n";
+ $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n";
+ $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n";
+ $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n";
+ $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n";
+
+ $output .= "?>";
+
+ return $output;
+ }
+
+
+ /**
+ * Compile {foreach ...} tag.
+ *
+ * @param string $tag_args
+ * @return string
+ */
+ function _compile_foreach_start($tag_args)
+ {
+ $attrs = $this->_parse_attrs($tag_args);
+ $arg_list = array();
+
+ if (empty($attrs['from'])) {
+ return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
+ }
+ $from = $attrs['from'];
+
+ if (empty($attrs['item'])) {
+ return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
+ }
+ $item = $this->_dequote($attrs['item']);
+ if (!preg_match('~^\w+$~', $item)) {
+ return $this->_syntax_error("'foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ if (isset($attrs['key'])) {
+ $key = $this->_dequote($attrs['key']);
+ if (!preg_match('~^\w+$~', $key)) {
+ return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
+ }
+ $key_part = "\$this->_tpl_vars['$key'] => ";
+ } else {
+ $key = null;
+ $key_part = '';
+ }
+
+ if (isset($attrs['name'])) {
+ $name = $attrs['name'];
+ } else {
+ $name = null;
+ }
+
+ $output = '<?php ';
+ $output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }";
+ if (isset($name)) {
+ $foreach_props = "\$this->_foreach[$name]";
+ $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n";
+ $output .= "if ({$foreach_props}['total'] > 0):\n";
+ $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
+ $output .= " {$foreach_props}['iteration']++;\n";
+ } else {
+ $output .= "if (count(\$_from)):\n";
+ $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
+ }
+ $output .= '?>';
+
+ return $output;
+ }
+
+
+ /**
+ * Compile {capture} .. {/capture} tags
+ *
+ * @param boolean $start true if this is the {capture} tag
+ * @param string $tag_args
+ * @return string
+ */
+
+ function _compile_capture_tag($start, $tag_args = '')
+ {
+ $attrs = $this->_parse_attrs($tag_args);
+
+ if ($start) {
+ if (isset($attrs['name']))
+ $buffer = $attrs['name'];
+ else
+ $buffer = "'default'";
+
+ if (isset($attrs['assign']))
+ $assign = $attrs['assign'];
+ else
+ $assign = null;
+ $output = "<?php ob_start(); ?>";
+ $this->_capture_stack[] = array($buffer, $assign);
+ } else {
+ list($buffer, $assign) = array_pop($this->_capture_stack);
+ $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ";
+ if (isset($assign)) {
+ $output .= " \$this->assign($assign, ob_get_contents());";
+ }
+ $output .= "ob_end_clean(); ?>";
+ }
+
+ return $output;
+ }
+
+ /**
+ * Compile {if ...} tag
+ *
+ * @param string $tag_args
+ * @param boolean $elseif if true, uses elseif instead of if
+ * @return string
+ */
+ function _compile_if_tag($tag_args, $elseif = false)
+ {
+
+ /* Tokenize args for 'if' tag. */
+ preg_match_all('~(?>
+ ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call
+ ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string
+ \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token
+ \b\w+\b | # valid word token
+ \S+ # anything else
+ )~x', $tag_args, $match);
+
+ $tokens = $match[0];
+
+ if(empty($tokens)) {
+ $_error_msg = $elseif ? "'elseif'" : "'if'";
+ $_error_msg .= ' statement requires arguments';
+ $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+
+ // make sure we have balanced parenthesis
+ $token_count = array_count_values($tokens);
+ if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
+ $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ $is_arg_stack = array();
+
+ for ($i = 0; $i < count($tokens); $i++) {
+
+ $token = &$tokens[$i];
+
+ switch (strtolower($token)) {
+ case '!':
+ case '%':
+ case '!==':
+ case '==':
+ case '===':
+ case '>':
+ case '<':
+ case '!=':
+ case '<>':
+ case '<<':
+ case '>>':
+ case '<=':
+ case '>=':
+ case '&&':
+ case '||':
+ case '|':
+ case '^':
+ case '&':
+ case '~':
+ case ')':
+ case ',':
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '@':
+ break;
+
+ case 'eq':
+ $token = '==';
+ break;
+
+ case 'ne':
+ case 'neq':
+ $token = '!=';
+ break;
+
+ case 'lt':
+ $token = '<';
+ break;
+
+ case 'le':
+ case 'lte':
+ $token = '<=';
+ break;
+
+ case 'gt':
+ $token = '>';
+ break;
+
+ case 'ge':
+ case 'gte':
+ $token = '>=';
+ break;
+
+ case 'and':
+ $token = '&&';
+ break;
+
+ case 'or':
+ $token = '||';
+ break;
+
+ case 'not':
+ $token = '!';
+ break;
+
+ case 'mod':
+ $token = '%';
+ break;
+
+ case '(':
+ array_push($is_arg_stack, $i);
+ break;
+
+ case 'is':
+ /* If last token was a ')', we operate on the parenthesized
+ expression. The start of the expression is on the stack.
+ Otherwise, we operate on the last encountered token. */
+ if ($tokens[$i-1] == ')')
+ $is_arg_start = array_pop($is_arg_stack);
+ else
+ $is_arg_start = $i-1;
+ /* Construct the argument for 'is' expression, so it knows
+ what to operate on. */
+ $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
+
+ /* Pass all tokens from next one until the end to the
+ 'is' expression parsing function. The function will
+ return modified tokens, where the first one is the result
+ of the 'is' expression and the rest are the tokens it
+ didn't touch. */
+ $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
+
+ /* Replace the old tokens with the new ones. */
+ array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
+
+ /* Adjust argument start so that it won't change from the
+ current position for the next iteration. */
+ $i = $is_arg_start;
+ break;
+
+ default:
+ if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) {
+ // function call
+ if($this->security &&
+ !in_array($token, $this->security_settings['IF_FUNCS'])) {
+ $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
+ }
+ } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') {
+ // variable function call
+ $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
+ } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) {
+ // object or variable
+ $token = $this->_parse_var_props($token);
+ } elseif(is_numeric($token)) {
+ // number, skip it
+ } else {
+ $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__);
+ }
+ break;
+ }
+ }
+
+ if ($elseif)
+ return '<?php elseif ('.implode(' ', $tokens).'): ?>';
+ else
+ return '<?php if ('.implode(' ', $tokens).'): ?>';
+ }
+
+
+ function _compile_arg_list($type, $name, $attrs, &$cache_code) {
+ $arg_list = array();
+
+ if (isset($type) && isset($name)
+ && isset($this->_plugins[$type])
+ && isset($this->_plugins[$type][$name])
+ && empty($this->_plugins[$type][$name][4])
+ && is_array($this->_plugins[$type][$name][5])
+ ) {
+ /* we have a list of parameters that should be cached */
+ $_cache_attrs = $this->_plugins[$type][$name][5];
+ $_count = $this->_cache_attrs_count++;
+ $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');";
+
+ } else {
+ /* no parameters are cached */
+ $_cache_attrs = null;
+ }
+
+ foreach ($attrs as $arg_name => $arg_value) {
+ if (is_bool($arg_value))
+ $arg_value = $arg_value ? 'true' : 'false';
+ if (is_null($arg_value))
+ $arg_value = 'null';
+ if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) {
+ $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)";
+ } else {
+ $arg_list[] = "'$arg_name' => $arg_value";
+ }
+ }
+ return $arg_list;
+ }
+
+ /**
+ * Parse is expression
+ *
+ * @param string $is_arg
+ * @param array $tokens
+ * @return array
+ */
+ function _parse_is_expr($is_arg, $tokens)
+ {
+ $expr_end = 0;
+ $negate_expr = false;
+
+ if (($first_token = array_shift($tokens)) == 'not') {
+ $negate_expr = true;
+ $expr_type = array_shift($tokens);
+ } else
+ $expr_type = $first_token;
+
+ switch ($expr_type) {
+ case 'even':
+ if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
+ $expr_end++;
+ $expr_arg = $tokens[$expr_end++];
+ $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
+ } else
+ $expr = "!(1 & $is_arg)";
+ break;
+
+ case 'odd':
+ if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
+ $expr_end++;
+ $expr_arg = $tokens[$expr_end++];
+ $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
+ } else
+ $expr = "(1 & $is_arg)";
+ break;
+
+ case 'div':
+ if (@$tokens[$expr_end] == 'by') {
+ $expr_end++;
+ $expr_arg = $tokens[$expr_end++];
+ $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")";
+ } else {
+ $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__);
+ }
+ break;
+
+ default:
+ $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__);
+ break;
+ }
+
+ if ($negate_expr) {
+ $expr = "!($expr)";
+ }
+
+ array_splice($tokens, 0, $expr_end, $expr);
+
+ return $tokens;
+ }
+
+
+ /**
+ * Parse attribute string
+ *
+ * @param string $tag_args
+ * @return array
+ */
+ function _parse_attrs($tag_args)
+ {
+
+ /* Tokenize tag attributes. */
+ preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+)
+ )+ |
+ [=]
+ ~x', $tag_args, $match);
+ $tokens = $match[0];
+
+ $attrs = array();
+ /* Parse state:
+ 0 - expecting attribute name
+ 1 - expecting '='
+ 2 - expecting attribute value (not '=') */
+ $state = 0;
+
+ foreach ($tokens as $token) {
+ switch ($state) {
+ case 0:
+ /* If the token is a valid identifier, we set attribute name
+ and go to state 1. */
+ if (preg_match('~^\w+$~', $token)) {
+ $attr_name = $token;
+ $state = 1;
+ } else
+ $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
+ break;
+
+ case 1:
+ /* If the token is '=', then we go to state 2. */
+ if ($token == '=') {
+ $state = 2;
+ } else
+ $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
+ break;
+
+ case 2:
+ /* If token is not '=', we set the attribute value and go to
+ state 0. */
+ if ($token != '=') {
+ /* We booleanize the token if it's a non-quoted possible
+ boolean value. */
+ if (preg_match('~^(on|yes|true)$~', $token)) {
+ $token = 'true';
+ } else if (preg_match('~^(off|no|false)$~', $token)) {
+ $token = 'false';
+ } else if ($token == 'null') {
+ $token = 'null';
+ } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) {
+ /* treat integer literally */
+ } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) {
+ /* treat as a string, double-quote it escaping quotes */
+ $token = '"'.addslashes($token).'"';
+ }
+
+ $attrs[$attr_name] = $token;
+ $state = 0;
+ } else
+ $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
+ break;
+ }
+ $last_token = $token;
+ }
+
+ if($state != 0) {
+ if($state == 1) {
+ $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
+ } else {
+ $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
+ }
+ }
+
+ $this->_parse_vars_props($attrs);
+
+ return $attrs;
+ }
+
+ /**
+ * compile multiple variables and section properties tokens into
+ * PHP code
+ *
+ * @param array $tokens
+ */
+ function _parse_vars_props(&$tokens)
+ {
+ foreach($tokens as $key => $val) {
+ $tokens[$key] = $this->_parse_var_props($val);
+ }
+ }
+
+ /**
+ * compile single variable and section properties token into
+ * PHP code
+ *
+ * @param string $val
+ * @param string $tag_attrs
+ * @return string
+ */
+ function _parse_var_props($val)
+ {
+ $val = trim($val);
+
+ if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) {
+ // $ variable or object
+ $return = $this->_parse_var($match[1]);
+ $modifiers = $match[2];
+ if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) {
+ $_default_mod_string = implode('|',(array)$this->default_modifiers);
+ $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;
+ }
+ $this->_parse_modifiers($return, $modifiers);
+ return $return;
+ } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+ // double quoted text
+ preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
+ $return = $this->_expand_quoted_text($match[1]);
+ if($match[2] != '') {
+ $this->_parse_modifiers($return, $match[2]);
+ }
+ return $return;
+ }
+ elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+ // numerical constant
+ preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
+ if($match[2] != '') {
+ $this->_parse_modifiers($match[1], $match[2]);
+ return $match[1];
+ }
+ }
+ elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+ // single quoted text
+ preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
+ if($match[2] != '') {
+ $this->_parse_modifiers($match[1], $match[2]);
+ return $match[1];
+ }
+ }
+ elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+ // config var
+ return $this->_parse_conf_var($val);
+ }
+ elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+ // section var
+ return $this->_parse_section_prop($val);
+ }
+ elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) {
+ // literal string
+ return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"');
+ }
+ return $val;
+ }
+
+ /**
+ * expand quoted text with embedded variables
+ *
+ * @param string $var_expr
+ * @return string
+ */
+ function _expand_quoted_text($var_expr)
+ {
+ // if contains unescaped $, expand it
+ if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) {
+ $_match = $_match[0];
+ $_replace = array();
+ foreach($_match as $_var) {
+ $_replace[$_var] = '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."';
+ }
+ $var_expr = strtr($var_expr, $_replace);
+ $_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr);
+ } else {
+ $_return = $var_expr;
+ }
+ // replace double quoted literal string with single quotes
+ $_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return);
+ return $_return;
+ }
+
+ /**
+ * parse variable expression into PHP code
+ *
+ * @param string $var_expr
+ * @param string $output
+ * @return string
+ */
+ function _parse_var($var_expr)
+ {
+ $_has_math = false;
+ $_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
+
+ if(count($_math_vars) > 1) {
+ $_first_var = "";
+ $_complete_var = "";
+ $_output = "";
+ // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter)
+ foreach($_math_vars as $_k => $_math_var) {
+ $_math_var = $_math_vars[$_k];
+
+ if(!empty($_math_var) || is_numeric($_math_var)) {
+ // hit a math operator, so process the stuff which came before it
+ if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) {
+ $_has_math = true;
+ if(!empty($_complete_var) || is_numeric($_complete_var)) {
+ $_output .= $this->_parse_var($_complete_var);
+ }
+
+ // just output the math operator to php
+ $_output .= $_math_var;
+
+ if(empty($_first_var))
+ $_first_var = $_complete_var;
+
+ $_complete_var = "";
+ } else {
+ $_complete_var .= $_math_var;
+ }
+ }
+ }
+ if($_has_math) {
+ if(!empty($_complete_var) || is_numeric($_complete_var))
+ $_output .= $this->_parse_var($_complete_var);
+
+ // get the modifiers working (only the last var from math + modifier is left)
+ $var_expr = $_complete_var;
+ }
+ }
+
+ // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit)
+ if(is_numeric(substr($var_expr, 0, 1)))
+ $_var_ref = $var_expr;
+ else
+ $_var_ref = substr($var_expr, 1);
+
+ if(!$_has_math) {
+
+ // get [foo] and .foo and ->foo and (...) pieces
+ preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match);
+
+ $_indexes = $match[0];
+ $_var_name = array_shift($_indexes);
+
+ /* Handle $smarty.* variable references as a special case. */
+ if ($_var_name == 'smarty') {
+ /*
+ * If the reference could be compiled, use the compiled output;
+ * otherwise, fall back on the $smarty variable generated at
+ * run-time.
+ */
+ if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) {
+ $_output = $smarty_ref;
+ } else {
+ $_var_name = substr(array_shift($_indexes), 1);
+ $_output = "\$this->_smarty_vars['$_var_name']";
+ }
+ } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) {
+ // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers
+ if(count($_indexes) > 0)
+ {
+ $_var_name .= implode("", $_indexes);
+ $_indexes = array();
+ }
+ $_output = $_var_name;
+ } else {
+ $_output = "\$this->_tpl_vars['$_var_name']";
+ }
+
+ foreach ($_indexes as $_index) {
+ if (substr($_index, 0, 1) == '[') {
+ $_index = substr($_index, 1, -1);
+ if (is_numeric($_index)) {
+ $_output .= "[$_index]";
+ } elseif (substr($_index, 0, 1) == '$') {
+ if (strpos($_index, '.') !== false) {
+ $_output .= '[' . $this->_parse_var($_index) . ']';
+ } else {
+ $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]";
+ }
+ } else {
+ $_var_parts = explode('.', $_index);
+ $_var_section = $_var_parts[0];
+ $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index';
+ $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]";
+ }
+ } else if (substr($_index, 0, 1) == '.') {
+ if (substr($_index, 1, 1) == '$')
+ $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]";
+ else
+ $_output .= "['" . substr($_index, 1) . "']";
+ } else if (substr($_index,0,2) == '->') {
+ if(substr($_index,2,2) == '__') {
+ $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);
+ } elseif($this->security && substr($_index, 2, 1) == '_') {
+ $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
+ } elseif (substr($_index, 2, 1) == '$') {
+ if ($this->security) {
+ $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
+ } else {
+ $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}';
+ }
+ } else {
+ $_output .= $_index;
+ }
+ } elseif (substr($_index, 0, 1) == '(') {
+ $_index = $this->_parse_parenth_args($_index);
+ $_output .= $_index;
+ } else {
+ $_output .= $_index;
+ }
+ }
+ }
+
+ return $_output;
+ }
+
+ /**
+ * parse arguments in function call parenthesis
+ *
+ * @param string $parenth_args
+ * @return string
+ */
+ function _parse_parenth_args($parenth_args)
+ {
+ preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match);
+ $orig_vals = $match = $match[0];
+ $this->_parse_vars_props($match);
+ $replace = array();
+ for ($i = 0, $count = count($match); $i < $count; $i++) {
+ $replace[$orig_vals[$i]] = $match[$i];
+ }
+ return strtr($parenth_args, $replace);
+ }
+
+ /**
+ * parse configuration variable expression into PHP code
+ *
+ * @param string $conf_var_expr
+ */
+ function _parse_conf_var($conf_var_expr)
+ {
+ $parts = explode('|', $conf_var_expr, 2);
+ $var_ref = $parts[0];
+ $modifiers = isset($parts[1]) ? $parts[1] : '';
+
+ $var_name = substr($var_ref, 1, -1);
+
+ $output = "\$this->_config[0]['vars']['$var_name']";
+
+ $this->_parse_modifiers($output, $modifiers);
+
+ return $output;
+ }
+
+ /**
+ * parse section property expression into PHP code
+ *
+ * @param string $section_prop_expr
+ * @return string
+ */
+ function _parse_section_prop($section_prop_expr)
+ {
+ $parts = explode('|', $section_prop_expr, 2);
+ $var_ref = $parts[0];
+ $modifiers = isset($parts[1]) ? $parts[1] : '';
+
+ preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
+ $section_name = $match[1];
+ $prop_name = $match[2];
+
+ $output = "\$this->_sections['$section_name']['$prop_name']";
+
+ $this->_parse_modifiers($output, $modifiers);
+
+ return $output;
+ }
+
+
+ /**
+ * parse modifier chain into PHP code
+ *
+ * sets $output to parsed modified chain
+ * @param string $output
+ * @param string $modifier_string
+ */
+ function _parse_modifiers(&$output, $modifier_string)
+ {
+ preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match);
+ list(, $_modifiers, $modifier_arg_strings) = $_match;
+
+ for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {
+ $_modifier_name = $_modifiers[$_i];
+
+ if($_modifier_name == 'smarty') {
+ // skip smarty modifier
+ continue;
+ }
+
+ preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match);
+ $_modifier_args = $_match[1];
+
+ if (substr($_modifier_name, 0, 1) == '@') {
+ $_map_array = false;
+ $_modifier_name = substr($_modifier_name, 1);
+ } else {
+ $_map_array = true;
+ }
+
+ if (empty($this->_plugins['modifier'][$_modifier_name])
+ && !$this->_get_plugin_filepath('modifier', $_modifier_name)
+ && function_exists($_modifier_name)) {
+ if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) {
+ $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
+ } else {
+ $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false);
+ }
+ }
+ $this->_add_plugin('modifier', $_modifier_name);
+
+ $this->_parse_vars_props($_modifier_args);
+
+ if($_modifier_name == 'default') {
+ // supress notifications of default modifier vars and args
+ if(substr($output, 0, 1) == '$') {
+ $output = '@' . $output;
+ }
+ if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') {
+ $_modifier_args[0] = '@' . $_modifier_args[0];
+ }
+ }
+ if (count($_modifier_args) > 0)
+ $_modifier_args = ', '.implode(', ', $_modifier_args);
+ else
+ $_modifier_args = '';
+
+ if ($_map_array) {
+ $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))";
+
+ } else {
+
+ $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)";
+
+ }
+ }
+ }
+
+
+ /**
+ * add plugin
+ *
+ * @param string $type
+ * @param string $name
+ * @param boolean? $delayed_loading
+ */
+ function _add_plugin($type, $name, $delayed_loading = null)
+ {
+ if (!isset($this->_plugin_info[$type])) {
+ $this->_plugin_info[$type] = array();
+ }
+ if (!isset($this->_plugin_info[$type][$name])) {
+ $this->_plugin_info[$type][$name] = array($this->_current_file,
+ $this->_current_line_no,
+ $delayed_loading);
+ }
+ }
+
+
+ /**
+ * Compiles references of type $smarty.foo
+ *
+ * @param string $indexes
+ * @return string
+ */
+ function _compile_smarty_ref(&$indexes)
+ {
+ /* Extract the reference name. */
+ $_ref = substr($indexes[0], 1);
+ foreach($indexes as $_index_no=>$_index) {
+ if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) {
+ $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
+ }
+ }
+
+ switch ($_ref) {
+ case 'now':
+ $compiled_ref = 'time()';
+ $_max_index = 1;
+ break;
+
+ case 'foreach':
+ array_shift($indexes);
+ $_var = $this->_parse_var_props(substr($indexes[0], 1));
+ $_propname = substr($indexes[1], 1);
+ $_max_index = 1;
+ switch ($_propname) {
+ case 'index':
+ array_shift($indexes);
+ $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)";
+ break;
+
+ case 'first':
+ array_shift($indexes);
+ $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)";
+ break;
+
+ case 'last':
+ array_shift($indexes);
+ $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])";
+ break;
+
+ case 'show':
+ array_shift($indexes);
+ $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)";
+ break;
+
+ default:
+ unset($_max_index);
+ $compiled_ref = "\$this->_foreach[$_var]";
+ }
+ break;
+
+ case 'section':
+ array_shift($indexes);
+ $_var = $this->_parse_var_props(substr($indexes[0], 1));
+ $compiled_ref = "\$this->_sections[$_var]";
+ break;
+
+ case 'get':
+ $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']";
+ break;
+
+ case 'post':
+ $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']";
+ break;
+
+ case 'cookies':
+ $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']";
+ break;
+
+ case 'env':
+ $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']";
+ break;
+
+ case 'server':
+ $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']";
+ break;
+
+ case 'session':
+ $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']";
+ break;
+
+ /*
+ * These cases are handled either at run-time or elsewhere in the
+ * compiler.
+ */
+ case 'request':
+ if ($this->request_use_auto_globals) {
+ $compiled_ref = '$_REQUEST';
+ break;
+ } else {
+ $this->_init_smarty_vars = true;
+ }
+ return null;
+
+ case 'capture':
+ return null;
+
+ case 'template':
+ $compiled_ref = "'$this->_current_file'";
+ $_max_index = 1;
+ break;
+
+ case 'version':
+ $compiled_ref = "'$this->_version'";
+ $_max_index = 1;
+ break;
+
+ case 'const':
+ if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) {
+ $this->_syntax_error("(secure mode) constants not permitted",
+ E_USER_WARNING, __FILE__, __LINE__);
+ return;
+ }
+ array_shift($indexes);
+ if (preg_match('!^\.\w+$!', $indexes[0])) {
+ $compiled_ref = '@' . substr($indexes[0], 1);
+ } else {
+ $_val = $this->_parse_var_props(substr($indexes[0], 1));
+ $compiled_ref = '@constant(' . $_val . ')';
+ }
+ $_max_index = 1;
+ break;
+
+ case 'config':
+ $compiled_ref = "\$this->_config[0]['vars']";
+ $_max_index = 3;
+ break;
+
+ case 'ldelim':
+ $compiled_ref = "'$this->left_delimiter'";
+ break;
+
+ case 'rdelim':
+ $compiled_ref = "'$this->right_delimiter'";
+ break;
+
+ default:
+ $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__);
+ break;
+ }
+
+ if (isset($_max_index) && count($indexes) > $_max_index) {
+ $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ array_shift($indexes);
+ return $compiled_ref;
+ }
+
+ /**
+ * compiles call to plugin of type $type with name $name
+ * returns a string containing the function-name or method call
+ * without the paramter-list that would have follow to make the
+ * call valid php-syntax
+ *
+ * @param string $type
+ * @param string $name
+ * @return string
+ */
+ function _compile_plugin_call($type, $name) {
+ if (isset($this->_plugins[$type][$name])) {
+ /* plugin loaded */
+ if (is_array($this->_plugins[$type][$name][0])) {
+ return ((is_object($this->_plugins[$type][$name][0][0])) ?
+ "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */
+ : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */
+ ). $this->_plugins[$type][$name][0][1];
+
+ } else {
+ /* function callback */
+ return $this->_plugins[$type][$name][0];
+
+ }
+ } else {
+ /* plugin not loaded -> auto-loadable-plugin */
+ return 'smarty_'.$type.'_'.$name;
+
+ }
+ }
+
+ /**
+ * load pre- and post-filters
+ */
+ function _load_filters()
+ {
+ if (count($this->_plugins['prefilter']) > 0) {
+ foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
+ if ($prefilter === false) {
+ unset($this->_plugins['prefilter'][$filter_name]);
+ $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));
+ require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
+ smarty_core_load_plugins($_params, $this);
+ }
+ }
+ }
+ if (count($this->_plugins['postfilter']) > 0) {
+ foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
+ if ($postfilter === false) {
+ unset($this->_plugins['postfilter'][$filter_name]);
+ $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));
+ require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
+ smarty_core_load_plugins($_params, $this);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Quote subpattern references
+ *
+ * @param string $string
+ * @return string
+ */
+ function _quote_replace($string)
+ {
+ return strtr($string, array('\\' => '\\\\', '$' => '\\$'));
+ }
+
+ /**
+ * display Smarty syntax error
+ *
+ * @param string $error_msg
+ * @param integer $error_type
+ * @param string $file
+ * @param integer $line
+ */
+ function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null)
+ {
+ $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type);
+ }
+
+
+ /**
+ * check if the compilation changes from cacheable to
+ * non-cacheable state with the beginning of the current
+ * plugin. return php-code to reflect the transition.
+ * @return string
+ */
+ function _push_cacheable_state($type, $name) {
+ $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
+ if ($_cacheable
+ || 0<$this->_cacheable_state++) return '';
+ if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty'));
+ $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:'
+ . $this->_cache_serial . '#' . $this->_nocache_count
+ . '}\'; endif;';
+ return $_ret;
+ }
+
+
+ /**
+ * check if the compilation changes from non-cacheable to
+ * cacheable state with the end of the current plugin return
+ * php-code to reflect the transition.
+ * @return string
+ */
+ function _pop_cacheable_state($type, $name) {
+ $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
+ if ($_cacheable
+ || --$this->_cacheable_state>0) return '';
+ return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:'
+ . $this->_cache_serial . '#' . ($this->_nocache_count++)
+ . '}\'; endif;';
+ }
+
+
+ /**
+ * push opening tag-name, file-name and line-number on the tag-stack
+ * @param string the opening tag's name
+ */
+ function _push_tag($open_tag)
+ {
+ array_push($this->_tag_stack, array($open_tag, $this->_current_line_no));
+ }
+
+ /**
+ * pop closing tag-name
+ * raise an error if this stack-top doesn't match with the closing tag
+ * @param string the closing tag's name
+ * @return string the opening tag's name
+ */
+ function _pop_tag($close_tag)
+ {
+ $message = '';
+ if (count($this->_tag_stack)>0) {
+ list($_open_tag, $_line_no) = array_pop($this->_tag_stack);
+ if ($close_tag == $_open_tag) {
+ return $_open_tag;
+ }
+ if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) {
+ return $this->_pop_tag($close_tag);
+ }
+ if ($close_tag == 'section' && $_open_tag == 'sectionelse') {
+ $this->_pop_tag($close_tag);
+ return $_open_tag;
+ }
+ if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') {
+ $this->_pop_tag($close_tag);
+ return $_open_tag;
+ }
+ if ($_open_tag == 'else' || $_open_tag == 'elseif') {
+ $_open_tag = 'if';
+ } elseif ($_open_tag == 'sectionelse') {
+ $_open_tag = 'section';
+ } elseif ($_open_tag == 'foreachelse') {
+ $_open_tag = 'foreach';
+ }
+ $message = " expected {/$_open_tag} (opened line $_line_no).";
+ }
+ $this->_syntax_error("mismatched tag {/$close_tag}.$message",
+ E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+}
+
+/**
+ * compare to values by their string length
+ *
+ * @access private
+ * @param string $a
+ * @param string $b
+ * @return 0|-1|1
+ */
+function _smarty_sort_length($a, $b)
+{
+ if($a == $b)
+ return 0;
+
+ if(strlen($a) == strlen($b))
+ return ($a > $b) ? -1 : 1;
+
+ return (strlen($a) > strlen($b)) ? -1 : 1;
+}
+
+
+/* vim: set et: */
+
+?>
diff --git a/lib/smarty-2.6.8/debug.tpl b/lib/smarty-2.6.8/debug.tpl
new file mode 100644
index 0000000..c05ef5d
--- /dev/null
+++ b/lib/smarty-2.6.8/debug.tpl
@@ -0,0 +1,157 @@
+{* Smarty *}
+{* debug.tpl, last updated version 2.1.0 *}
+{assign_debug_info}
+{capture assign=debug_output}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+ <title>Smarty Debug Console</title>
+{literal}
+<style type="text/css">
+/* <![CDATA[ */
+body, h1, h2, td, th, p {
+ font-family: sans-serif;
+ font-weight: normal;
+ font-size: 0.9em;
+ margin: 1px;
+ padding: 0;
+}
+
+h1 {
+ margin: 0;
+ text-align: left;
+ padding: 2px;
+ background-color: #f0c040;
+ color: black;
+ font-weight: bold;
+ font-size: 1.2em;
+ }
+
+h2 {
+ background-color: #9B410E;
+ color: white;
+ text-align: left;
+ font-weight: bold;
+ padding: 2px;
+ border-top: 1px solid black;
+}
+
+body {
+ background: black;
+}
+
+p, table, div {
+ background: #f0ead8;
+}
+
+p {
+ margin: 0;
+ font-style: italic;
+ text-align: center;
+}
+
+table {
+ width: 100%;
+}
+
+th, td {
+ font-family: monospace;
+ vertical-align: top;
+ text-align: left;
+ width: 50%;
+}
+
+td {
+ color: green;
+}
+
+.odd {
+ background-color: #eeeeee;
+}
+
+.even {
+ background-color: #fafafa;
+}
+
+.exectime {
+ font-size: 0.8em;
+ font-style: italic;
+}
+
+#table_assigned_vars th {
+ color: blue;
+}
+
+#table_config_vars th {
+ color: maroon;
+}
+/* ]]> */
+</style>
+{/literal}
+</head>
+<body>
+
+<h1>Smarty Debug Console</h1>
+
+<h2>included templates &amp; config files (load time in seconds)</h2>
+
+<div>
+{section name=templates loop=$_debug_tpls}
+ {section name=indent loop=$_debug_tpls[templates].depth}&nbsp;&nbsp;&nbsp;{/section}
+ <font color={if $_debug_tpls[templates].type eq "template"}brown{elseif $_debug_tpls[templates].type eq "insert"}black{else}green{/if}>
+ {$_debug_tpls[templates].filename|escape:html}</font>
+ {if isset($_debug_tpls[templates].exec_time)}
+ <span class="exectime">
+ ({$_debug_tpls[templates].exec_time|string_format:"%.5f"})
+ {if %templates.index% eq 0}(total){/if}
+ </span>
+ {/if}
+ <br />
+{sectionelse}
+ <p>no templates included</p>
+{/section}
+</div>
+
+<h2>assigned template variables</h2>
+
+<table id="table_assigned_vars">
+ {section name=vars loop=$_debug_keys}
+ <tr class="{cycle values="odd,even"}">
+ <th>{ldelim}${$_debug_keys[vars]|escape:'html'}{rdelim}</th>
+ <td>{$_debug_vals[vars]|@debug_print_var}</td></tr>
+ {sectionelse}
+ <tr><td><p>no template variables assigned</p></td></tr>
+ {/section}
+</table>
+
+<h2>assigned config file variables (outer template scope)</h2>
+
+<table id="table_config_vars">
+ {section name=config_vars loop=$_debug_config_keys}
+ <tr class="{cycle values="odd,even"}">
+ <th>{ldelim}#{$_debug_config_keys[config_vars]|escape:'html'}#{rdelim}</th>
+ <td>{$_debug_config_vals[config_vars]|@debug_print_var}</td></tr>
+ {sectionelse}
+ <tr><td><p>no config vars assigned</p></td></tr>
+ {/section}
+</table>
+</body>
+</html>
+{/capture}
+{if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"}
+ {$debug_output}
+{else}
+<script type="text/javascript">
+// <![CDATA[
+ if ( self.name == '' ) {ldelim}
+ var title = 'Console';
+ {rdelim}
+ else {ldelim}
+ var title = 'Console_' + self.name;
+ {rdelim}
+ _smarty_console = window.open("",title.value,"width=680,height=600,resizable,scrollbars=yes");
+ _smarty_console.document.write('{$debug_output|escape:'javascript'}');
+ _smarty_console.document.close();
+// ]]>
+</script>
+{/if} \ No newline at end of file
diff --git a/lib/smarty-2.6.8/internals/core.assemble_plugin_filepath.php b/lib/smarty-2.6.8/internals/core.assemble_plugin_filepath.php
new file mode 100644
index 0000000..690d3dd
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.assemble_plugin_filepath.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * assemble filepath of requested plugin
+ *
+ * @param string $type
+ * @param string $name
+ * @return string|false
+ */
+function smarty_core_assemble_plugin_filepath($params, &$smarty)
+{
+ static $_filepaths_cache = array();
+
+ $_plugin_filename = $params['type'] . '.' . $params['name'] . '.php';
+ if (isset($_filepaths_cache[$_plugin_filename])) {
+ return $_filepaths_cache[$_plugin_filename];
+ }
+ $_return = false;
+
+ foreach ((array)$smarty->plugins_dir as $_plugin_dir) {
+
+ $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename;
+
+ // see if path is relative
+ if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $_plugin_dir)) {
+ $_relative_paths[] = $_plugin_dir;
+ // relative path, see if it is in the SMARTY_DIR
+ if (@is_readable(SMARTY_DIR . $_plugin_filepath)) {
+ $_return = SMARTY_DIR . $_plugin_filepath;
+ break;
+ }
+ }
+ // try relative to cwd (or absolute)
+ if (@is_readable($_plugin_filepath)) {
+ $_return = $_plugin_filepath;
+ break;
+ }
+ }
+
+ if($_return === false) {
+ // still not found, try PHP include_path
+ if(isset($_relative_paths)) {
+ foreach ((array)$_relative_paths as $_plugin_dir) {
+
+ $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename;
+
+ $_params = array('file_path' => $_plugin_filepath);
+ require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');
+ if(smarty_core_get_include_path($_params, $smarty)) {
+ $_return = $_params['new_file_path'];
+ break;
+ }
+ }
+ }
+ }
+ $_filepaths_cache[$_plugin_filename] = $_return;
+ return $_return;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.assign_smarty_interface.php b/lib/smarty-2.6.8/internals/core.assign_smarty_interface.php
new file mode 100644
index 0000000..7e65a73
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.assign_smarty_interface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty assign_smarty_interface core plugin
+ *
+ * Type: core<br>
+ * Name: assign_smarty_interface<br>
+ * Purpose: assign the $smarty interface variable
+ * @param array Format: null
+ * @param Smarty
+ */
+function smarty_core_assign_smarty_interface($params, &$smarty)
+{
+ if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) {
+ return;
+ }
+
+ $_globals_map = array('g' => 'HTTP_GET_VARS',
+ 'p' => 'HTTP_POST_VARS',
+ 'c' => 'HTTP_COOKIE_VARS',
+ 's' => 'HTTP_SERVER_VARS',
+ 'e' => 'HTTP_ENV_VARS');
+
+ $_smarty_vars_request = array();
+
+ foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) {
+ if (isset($_globals_map[$_c])) {
+ $_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]);
+ }
+ }
+ $_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']);
+
+ $smarty->_smarty_vars['request'] = $_smarty_vars_request;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.create_dir_structure.php b/lib/smarty-2.6.8/internals/core.create_dir_structure.php
new file mode 100644
index 0000000..3eecc49
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.create_dir_structure.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * create full directory structure
+ *
+ * @param string $dir
+ */
+
+// $dir
+
+function smarty_core_create_dir_structure($params, &$smarty)
+{
+ if (!file_exists($params['dir'])) {
+ $_open_basedir_ini = ini_get('open_basedir');
+
+ if (DIRECTORY_SEPARATOR=='/') {
+ /* unix-style paths */
+ $_dir = $params['dir'];
+ $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY);
+ $_new_dir = (substr($_dir, 0, 1)=='/') ? '/' : getcwd().'/';
+ if($_use_open_basedir = !empty($_open_basedir_ini)) {
+ $_open_basedirs = explode(':', $_open_basedir_ini);
+ }
+
+ } else {
+ /* other-style paths */
+ $_dir = str_replace('\\','/', $params['dir']);
+ $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY);
+ if (preg_match('!^((//)|([a-zA-Z]:/))!', $_dir, $_root_dir)) {
+ /* leading "//" for network volume, or "[letter]:/" for full path */
+ $_new_dir = $_root_dir[1];
+ /* remove drive-letter from _dir_parts */
+ if (isset($_root_dir[3])) array_shift($_dir_parts);
+
+ } else {
+ $_new_dir = str_replace('\\', '/', getcwd()).'/';
+
+ }
+
+ if($_use_open_basedir = !empty($_open_basedir_ini)) {
+ $_open_basedirs = explode(';', str_replace('\\', '/', $_open_basedir_ini));
+ }
+
+ }
+
+ /* all paths use "/" only from here */
+ foreach ($_dir_parts as $_dir_part) {
+ $_new_dir .= $_dir_part;
+
+ if ($_use_open_basedir) {
+ // do not attempt to test or make directories outside of open_basedir
+ $_make_new_dir = false;
+ foreach ($_open_basedirs as $_open_basedir) {
+ if (substr($_new_dir, 0, strlen($_open_basedir)) == $_open_basedir) {
+ $_make_new_dir = true;
+ break;
+ }
+ }
+ } else {
+ $_make_new_dir = true;
+ }
+
+ if ($_make_new_dir && !file_exists($_new_dir) && !@mkdir($_new_dir, $smarty->_dir_perms) && !is_dir($_new_dir)) {
+ $smarty->trigger_error("problem creating directory '" . $_new_dir . "'");
+ return false;
+ }
+ $_new_dir .= '/';
+ }
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.display_debug_console.php b/lib/smarty-2.6.8/internals/core.display_debug_console.php
new file mode 100644
index 0000000..1a80f39
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.display_debug_console.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty debug_console function plugin
+ *
+ * Type: core<br>
+ * Name: display_debug_console<br>
+ * Purpose: display the javascript debug console window
+ * @param array Format: null
+ * @param Smarty
+ */
+function smarty_core_display_debug_console($params, &$smarty)
+{
+ // we must force compile the debug template in case the environment
+ // changed between separate applications.
+
+ if(empty($smarty->debug_tpl)) {
+ // set path to debug template from SMARTY_DIR
+ $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl';
+ if($smarty->security && is_file($smarty->debug_tpl)) {
+ $smarty->secure_dir[] = realpath($smarty->debug_tpl);
+ }
+ $smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl';
+ }
+
+ $_ldelim_orig = $smarty->left_delimiter;
+ $_rdelim_orig = $smarty->right_delimiter;
+
+ $smarty->left_delimiter = '{';
+ $smarty->right_delimiter = '}';
+
+ $_compile_id_orig = $smarty->_compile_id;
+ $smarty->_compile_id = null;
+
+ $_compile_path = $smarty->_get_compile_path($smarty->debug_tpl);
+ if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path))
+ {
+ ob_start();
+ $smarty->_include($_compile_path);
+ $_results = ob_get_contents();
+ ob_end_clean();
+ } else {
+ $_results = '';
+ }
+
+ $smarty->_compile_id = $_compile_id_orig;
+
+ $smarty->left_delimiter = $_ldelim_orig;
+ $smarty->right_delimiter = $_rdelim_orig;
+
+ return $_results;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.get_include_path.php b/lib/smarty-2.6.8/internals/core.get_include_path.php
new file mode 100644
index 0000000..4343241
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.get_include_path.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Get path to file from include_path
+ *
+ * @param string $file_path
+ * @param string $new_file_path
+ * @return boolean
+ * @staticvar array|null
+ */
+
+// $file_path, &$new_file_path
+
+function smarty_core_get_include_path(&$params, &$smarty)
+{
+ static $_path_array = null;
+
+ if(!isset($_path_array)) {
+ $_ini_include_path = ini_get('include_path');
+
+ if(strstr($_ini_include_path,';')) {
+ // windows pathnames
+ $_path_array = explode(';',$_ini_include_path);
+ } else {
+ $_path_array = explode(':',$_ini_include_path);
+ }
+ }
+ foreach ($_path_array as $_include_path) {
+ if (@is_readable($_include_path . DIRECTORY_SEPARATOR . $params['file_path'])) {
+ $params['new_file_path'] = $_include_path . DIRECTORY_SEPARATOR . $params['file_path'];
+ return true;
+ }
+ }
+ return false;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.get_microtime.php b/lib/smarty-2.6.8/internals/core.get_microtime.php
new file mode 100644
index 0000000..f1a28e0
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.get_microtime.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Get seconds and microseconds
+ * @return double
+ */
+function smarty_core_get_microtime($params, &$smarty)
+{
+ $mtime = microtime();
+ $mtime = explode(" ", $mtime);
+ $mtime = (double)($mtime[1]) + (double)($mtime[0]);
+ return ($mtime);
+}
+
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.get_php_resource.php b/lib/smarty-2.6.8/internals/core.get_php_resource.php
new file mode 100644
index 0000000..786d4e7
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.get_php_resource.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Retrieves PHP script resource
+ *
+ * sets $php_resource to the returned resource
+ * @param string $resource
+ * @param string $resource_type
+ * @param $php_resource
+ * @return boolean
+ */
+
+function smarty_core_get_php_resource(&$params, &$smarty)
+{
+
+ $params['resource_base_path'] = $smarty->trusted_dir;
+ $smarty->_parse_resource_name($params, $smarty);
+
+ /*
+ * Find out if the resource exists.
+ */
+
+ if ($params['resource_type'] == 'file') {
+ $_readable = false;
+ if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) {
+ $_readable = true;
+ } else {
+ // test for file in include_path
+ $_params = array('file_path' => $params['resource_name']);
+ require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');
+ if(smarty_core_get_include_path($_params, $smarty)) {
+ $_include_path = $_params['new_file_path'];
+ $_readable = true;
+ }
+ }
+ } else if ($params['resource_type'] != 'file') {
+ $_template_source = null;
+ $_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0])
+ && call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0],
+ array($params['resource_name'], &$_template_source, &$smarty));
+ }
+
+ /*
+ * Set the error function, depending on which class calls us.
+ */
+ if (method_exists($smarty, '_syntax_error')) {
+ $_error_funcc = '_syntax_error';
+ } else {
+ $_error_funcc = 'trigger_error';
+ }
+
+ if ($_readable) {
+ if ($smarty->security) {
+ require_once(SMARTY_CORE_DIR . 'core.is_trusted.php');
+ if (!smarty_core_is_trusted($params, $smarty)) {
+ $smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted');
+ return false;
+ }
+ }
+ } else {
+ $smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable');
+ return false;
+ }
+
+ if ($params['resource_type'] == 'file') {
+ $params['php_resource'] = $params['resource_name'];
+ } else {
+ $params['php_resource'] = $_template_source;
+ }
+ return true;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.is_secure.php b/lib/smarty-2.6.8/internals/core.is_secure.php
new file mode 100644
index 0000000..d54abd4
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.is_secure.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * determines if a resource is secure or not.
+ *
+ * @param string $resource_type
+ * @param string $resource_name
+ * @return boolean
+ */
+
+// $resource_type, $resource_name
+
+function smarty_core_is_secure($params, &$smarty)
+{
+ if (!$smarty->security || $smarty->security_settings['INCLUDE_ANY']) {
+ return true;
+ }
+
+ if ($params['resource_type'] == 'file') {
+ $_rp = realpath($params['resource_name']);
+ if (isset($params['resource_base_path'])) {
+ foreach ((array)$params['resource_base_path'] as $curr_dir) {
+ if ( ($_cd = realpath($curr_dir)) !== false &&
+ strncmp($_rp, $_cd, strlen($_cd)) == 0 &&
+ substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) {
+ return true;
+ }
+ }
+ }
+ if (!empty($smarty->secure_dir)) {
+ foreach ((array)$smarty->secure_dir as $curr_dir) {
+ if ( ($_cd = realpath($curr_dir)) !== false) {
+ if($_cd == $_rp) {
+ return true;
+ } elseif (strncmp($_rp, $_cd, strlen($_cd)) == 0 &&
+ substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR) {
+ return true;
+ }
+ }
+ }
+ }
+ } else {
+ // resource is not on local file system
+ return call_user_func_array(
+ $smarty->_plugins['resource'][$params['resource_type']][0][2],
+ array($params['resource_name'], &$smarty));
+ }
+
+ return false;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.is_trusted.php b/lib/smarty-2.6.8/internals/core.is_trusted.php
new file mode 100644
index 0000000..4299731
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.is_trusted.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * determines if a resource is trusted or not
+ *
+ * @param string $resource_type
+ * @param string $resource_name
+ * @return boolean
+ */
+
+ // $resource_type, $resource_name
+
+function smarty_core_is_trusted($params, &$smarty)
+{
+ $_smarty_trusted = false;
+ if ($params['resource_type'] == 'file') {
+ if (!empty($smarty->trusted_dir)) {
+ $_rp = realpath($params['resource_name']);
+ foreach ((array)$smarty->trusted_dir as $curr_dir) {
+ if (!empty($curr_dir) && is_readable ($curr_dir)) {
+ $_cd = realpath($curr_dir);
+ if (strncmp($_rp, $_cd, strlen($_cd)) == 0
+ && substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) {
+ $_smarty_trusted = true;
+ break;
+ }
+ }
+ }
+ }
+
+ } else {
+ // resource is not on local file system
+ $_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3],
+ array($params['resource_name'], $smarty));
+ }
+
+ return $_smarty_trusted;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.load_plugins.php b/lib/smarty-2.6.8/internals/core.load_plugins.php
new file mode 100644
index 0000000..6db1dc5
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.load_plugins.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Load requested plugins
+ *
+ * @param array $plugins
+ */
+
+// $plugins
+
+function smarty_core_load_plugins($params, &$smarty)
+{
+
+ foreach ($params['plugins'] as $_plugin_info) {
+ list($_type, $_name, $_tpl_file, $_tpl_line, $_delayed_loading) = $_plugin_info;
+ $_plugin = &$smarty->_plugins[$_type][$_name];
+
+ /*
+ * We do not load plugin more than once for each instance of Smarty.
+ * The following code checks for that. The plugin can also be
+ * registered dynamically at runtime, in which case template file
+ * and line number will be unknown, so we fill them in.
+ *
+ * The final element of the info array is a flag that indicates
+ * whether the dynamically registered plugin function has been
+ * checked for existence yet or not.
+ */
+ if (isset($_plugin)) {
+ if (empty($_plugin[3])) {
+ if (!is_callable($_plugin[0])) {
+ $smarty->_trigger_fatal_error("[plugin] $_type '$_name' is not implemented", $_tpl_file, $_tpl_line, __FILE__, __LINE__);
+ } else {
+ $_plugin[1] = $_tpl_file;
+ $_plugin[2] = $_tpl_line;
+ $_plugin[3] = true;
+ if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */
+ }
+ }
+ continue;
+ } else if ($_type == 'insert') {
+ /*
+ * For backwards compatibility, we check for insert functions in
+ * the symbol table before trying to load them as a plugin.
+ */
+ $_plugin_func = 'insert_' . $_name;
+ if (function_exists($_plugin_func)) {
+ $_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false);
+ continue;
+ }
+ }
+
+ $_plugin_file = $smarty->_get_plugin_filepath($_type, $_name);
+
+ if (! $_found = ($_plugin_file != false)) {
+ $_message = "could not load plugin file '$_type.$_name.php'\n";
+ }
+
+ /*
+ * If plugin file is found, it -must- provide the properly named
+ * plugin function. In case it doesn't, simply output the error and
+ * do not fall back on any other method.
+ */
+ if ($_found) {
+ include_once $_plugin_file;
+
+ $_plugin_func = 'smarty_' . $_type . '_' . $_name;
+ if (!function_exists($_plugin_func)) {
+ $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", $_tpl_file, $_tpl_line, __FILE__, __LINE__);
+ continue;
+ }
+ }
+ /*
+ * In case of insert plugins, their code may be loaded later via
+ * 'script' attribute.
+ */
+ else if ($_type == 'insert' && $_delayed_loading) {
+ $_plugin_func = 'smarty_' . $_type . '_' . $_name;
+ $_found = true;
+ }
+
+ /*
+ * Plugin specific processing and error checking.
+ */
+ if (!$_found) {
+ if ($_type == 'modifier') {
+ /*
+ * In case modifier falls back on using PHP functions
+ * directly, we only allow those specified in the security
+ * context.
+ */
+ if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) {
+ $_message = "(secure mode) modifier '$_name' is not allowed";
+ } else {
+ if (!function_exists($_name)) {
+ $_message = "modifier '$_name' is not implemented";
+ } else {
+ $_plugin_func = $_name;
+ $_found = true;
+ }
+ }
+ } else if ($_type == 'function') {
+ /*
+ * This is a catch-all situation.
+ */
+ $_message = "unknown tag - '$_name'";
+ }
+ }
+
+ if ($_found) {
+ $smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true);
+ } else {
+ // output error
+ $smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__);
+ }
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.load_resource_plugin.php b/lib/smarty-2.6.8/internals/core.load_resource_plugin.php
new file mode 100644
index 0000000..a7d37d1
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.load_resource_plugin.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * load a resource plugin
+ *
+ * @param string $type
+ */
+
+// $type
+
+function smarty_core_load_resource_plugin($params, &$smarty)
+{
+ /*
+ * Resource plugins are not quite like the other ones, so they are
+ * handled differently. The first element of plugin info is the array of
+ * functions provided by the plugin, the second one indicates whether
+ * all of them exist or not.
+ */
+
+ $_plugin = &$smarty->_plugins['resource'][$params['type']];
+ if (isset($_plugin)) {
+ if (!$_plugin[1] && count($_plugin[0])) {
+ $_plugin[1] = true;
+ foreach ($_plugin[0] as $_plugin_func) {
+ if (!is_callable($_plugin_func)) {
+ $_plugin[1] = false;
+ break;
+ }
+ }
+ }
+
+ if (!$_plugin[1]) {
+ $smarty->_trigger_fatal_error("[plugin] resource '" . $params['type'] . "' is not implemented", null, null, __FILE__, __LINE__);
+ }
+
+ return;
+ }
+
+ $_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']);
+ $_found = ($_plugin_file != false);
+
+ if ($_found) { /*
+ * If the plugin file is found, it -must- provide the properly named
+ * plugin functions.
+ */
+ include_once($_plugin_file);
+
+ /*
+ * Locate functions that we require the plugin to provide.
+ */
+ $_resource_ops = array('source', 'timestamp', 'secure', 'trusted');
+ $_resource_funcs = array();
+ foreach ($_resource_ops as $_op) {
+ $_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op;
+ if (!function_exists($_plugin_func)) {
+ $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", null, null, __FILE__, __LINE__);
+ return;
+ } else {
+ $_resource_funcs[] = $_plugin_func;
+ }
+ }
+
+ $smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true);
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.process_cached_inserts.php b/lib/smarty-2.6.8/internals/core.process_cached_inserts.php
new file mode 100644
index 0000000..1d78edd
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.process_cached_inserts.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Replace cached inserts with the actual results
+ *
+ * @param string $results
+ * @return string
+ */
+function smarty_core_process_cached_inserts($params, &$smarty)
+{
+ preg_match_all('!'.$smarty->_smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis',
+ $params['results'], $match);
+ list($cached_inserts, $insert_args) = $match;
+
+ for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) {
+ if ($smarty->debugging) {
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $debug_start_time = smarty_core_get_microtime($_params, $smarty);
+ }
+
+ $args = unserialize($insert_args[$i]);
+ $name = $args['name'];
+
+ if (isset($args['script'])) {
+ $_params = array('resource_name' => $smarty->_dequote($args['script']));
+ require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');
+ if(!smarty_core_get_php_resource($_params, $smarty)) {
+ return false;
+ }
+ $resource_type = $_params['resource_type'];
+ $php_resource = $_params['php_resource'];
+
+
+ if ($resource_type == 'file') {
+ $smarty->_include($php_resource, true);
+ } else {
+ $smarty->_eval($php_resource);
+ }
+ }
+
+ $function_name = $smarty->_plugins['insert'][$name][0];
+ if (empty($args['assign'])) {
+ $replace = $function_name($args, $smarty);
+ } else {
+ $smarty->assign($args['assign'], $function_name($args, $smarty));
+ $replace = '';
+ }
+
+ $params['results'] = substr_replace($params['results'], $replace, strpos($params['results'], $cached_inserts[$i]), strlen($cached_inserts[$i]));
+ if ($smarty->debugging) {
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $smarty->_smarty_debug_info[] = array('type' => 'insert',
+ 'filename' => 'insert_'.$name,
+ 'depth' => $smarty->_inclusion_depth,
+ 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time);
+ }
+ }
+
+ return $params['results'];
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.process_compiled_include.php b/lib/smarty-2.6.8/internals/core.process_compiled_include.php
new file mode 100644
index 0000000..d539423
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.process_compiled_include.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Replace nocache-tags by results of the corresponding non-cacheable
+ * functions and return it
+ *
+ * @param string $compiled_tpl
+ * @param string $cached_source
+ * @return string
+ */
+
+function smarty_core_process_compiled_include($params, &$smarty)
+{
+ $_cache_including = $smarty->_cache_including;
+ $smarty->_cache_including = true;
+
+ $_return = $params['results'];
+
+ foreach ($smarty->_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) {
+ $smarty->_include($_include_file_path, true);
+ }
+
+ foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) {
+ $_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s',
+ array(&$smarty, '_process_compiled_include_callback'),
+ $_return);
+ }
+ $smarty->_cache_including = $_cache_including;
+ return $_return;
+}
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.read_cache_file.php b/lib/smarty-2.6.8/internals/core.read_cache_file.php
new file mode 100644
index 0000000..c60e113
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.read_cache_file.php
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * read a cache file, determine if it needs to be
+ * regenerated or not
+ *
+ * @param string $tpl_file
+ * @param string $cache_id
+ * @param string $compile_id
+ * @param string $results
+ * @return boolean
+ */
+
+// $tpl_file, $cache_id, $compile_id, &$results
+
+function smarty_core_read_cache_file(&$params, &$smarty)
+{
+ static $content_cache = array();
+
+ if ($smarty->force_compile) {
+ // force compile enabled, always regenerate
+ return false;
+ }
+
+ if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) {
+ list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']];
+ return true;
+ }
+
+ if (!empty($smarty->cache_handler_func)) {
+ // use cache_handler function
+ call_user_func_array($smarty->cache_handler_func,
+ array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null));
+ } else {
+ // use local cache file
+ $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']);
+ $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id);
+ $params['results'] = $smarty->_read_file($_cache_file);
+ }
+
+ if (empty($params['results'])) {
+ // nothing to parse (error?), regenerate cache
+ return false;
+ }
+
+ $_contents = $params['results'];
+ $_info_start = strpos($_contents, "\n") + 1;
+ $_info_len = (int)substr($_contents, 0, $_info_start - 1);
+ $_cache_info = unserialize(substr($_contents, $_info_start, $_info_len));
+ $params['results'] = substr($_contents, $_info_start + $_info_len);
+
+ if ($smarty->caching == 2 && isset ($_cache_info['expires'])){
+ // caching by expiration time
+ if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) {
+ // cache expired, regenerate
+ return false;
+ }
+ } else {
+ // caching by lifetime
+ if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) {
+ // cache expired, regenerate
+ return false;
+ }
+ }
+
+ if ($smarty->compile_check) {
+ $_params = array('get_source' => false, 'quiet'=>true);
+ foreach (array_keys($_cache_info['template']) as $_template_dep) {
+ $_params['resource_name'] = $_template_dep;
+ if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) {
+ // template file has changed, regenerate cache
+ return false;
+ }
+ }
+
+ if (isset($_cache_info['config'])) {
+ $_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true);
+ foreach (array_keys($_cache_info['config']) as $_config_dep) {
+ $_params['resource_name'] = $_config_dep;
+ if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) {
+ // config file has changed, regenerate cache
+ return false;
+ }
+ }
+ }
+ }
+
+ $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info);
+
+ $smarty->_cache_info = $_cache_info;
+ return true;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.rm_auto.php b/lib/smarty-2.6.8/internals/core.rm_auto.php
new file mode 100644
index 0000000..b251f64
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.rm_auto.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * delete an automagically created file by name and id
+ *
+ * @param string $auto_base
+ * @param string $auto_source
+ * @param string $auto_id
+ * @param integer $exp_time
+ * @return boolean
+ */
+
+// $auto_base, $auto_source = null, $auto_id = null, $exp_time = null
+
+function smarty_core_rm_auto($params, &$smarty)
+{
+ if (!@is_dir($params['auto_base']))
+ return false;
+
+ if(!isset($params['auto_id']) && !isset($params['auto_source'])) {
+ $_params = array(
+ 'dirname' => $params['auto_base'],
+ 'level' => 0,
+ 'exp_time' => $params['exp_time']
+ );
+ require_once(SMARTY_CORE_DIR . 'core.rmdir.php');
+ $_res = smarty_core_rmdir($_params, $smarty);
+ } else {
+ $_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']);
+
+ if(isset($params['auto_source'])) {
+ if (isset($params['extensions'])) {
+ $_res = false;
+ foreach ((array)$params['extensions'] as $_extension)
+ $_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']);
+ } else {
+ $_res = $smarty->_unlink($_tname, $params['exp_time']);
+ }
+ } elseif ($smarty->use_sub_dirs) {
+ $_params = array(
+ 'dirname' => $_tname,
+ 'level' => 1,
+ 'exp_time' => $params['exp_time']
+ );
+ require_once(SMARTY_CORE_DIR . 'core.rmdir.php');
+ $_res = smarty_core_rmdir($_params, $smarty);
+ } else {
+ // remove matching file names
+ $_handle = opendir($params['auto_base']);
+ $_res = true;
+ while (false !== ($_filename = readdir($_handle))) {
+ if($_filename == '.' || $_filename == '..') {
+ continue;
+ } elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) {
+ $_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']);
+ }
+ }
+ }
+ }
+
+ return $_res;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.rmdir.php b/lib/smarty-2.6.8/internals/core.rmdir.php
new file mode 100644
index 0000000..2166c44
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.rmdir.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * delete a dir recursively (level=0 -> keep root)
+ * WARNING: no tests, it will try to remove what you tell it!
+ *
+ * @param string $dirname
+ * @param integer $level
+ * @param integer $exp_time
+ * @return boolean
+ */
+
+// $dirname, $level = 1, $exp_time = null
+
+function smarty_core_rmdir($params, &$smarty)
+{
+ if(!isset($params['level'])) { $params['level'] = 1; }
+ if(!isset($params['exp_time'])) { $params['exp_time'] = null; }
+
+ if($_handle = @opendir($params['dirname'])) {
+
+ while (false !== ($_entry = readdir($_handle))) {
+ if ($_entry != '.' && $_entry != '..') {
+ if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) {
+ $_params = array(
+ 'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry,
+ 'level' => $params['level'] + 1,
+ 'exp_time' => $params['exp_time']
+ );
+ smarty_core_rmdir($_params, $smarty);
+ }
+ else {
+ $smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']);
+ }
+ }
+ }
+ closedir($_handle);
+ }
+
+ if ($params['level']) {
+ return @rmdir($params['dirname']);
+ }
+ return (bool)$_handle;
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.run_insert_handler.php b/lib/smarty-2.6.8/internals/core.run_insert_handler.php
new file mode 100644
index 0000000..71c3845
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.run_insert_handler.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Handle insert tags
+ *
+ * @param array $args
+ * @return string
+ */
+function smarty_core_run_insert_handler($params, &$smarty)
+{
+
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ if ($smarty->debugging) {
+ $_params = array();
+ $_debug_start_time = smarty_core_get_microtime($_params, $smarty);
+ }
+
+ if ($smarty->caching) {
+ $_arg_string = serialize($params['args']);
+ $_name = $params['args']['name'];
+ if (!isset($smarty->_cache_info['insert_tags'][$_name])) {
+ $smarty->_cache_info['insert_tags'][$_name] = array('insert',
+ $_name,
+ $smarty->_plugins['insert'][$_name][1],
+ $smarty->_plugins['insert'][$_name][2],
+ !empty($params['args']['script']) ? true : false);
+ }
+ return $smarty->_smarty_md5."{insert_cache $_arg_string}".$smarty->_smarty_md5;
+ } else {
+ if (isset($params['args']['script'])) {
+ $_params = array('resource_name' => $smarty->_dequote($params['args']['script']));
+ require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');
+ if(!smarty_core_get_php_resource($_params, $smarty)) {
+ return false;
+ }
+
+ if ($_params['resource_type'] == 'file') {
+ $smarty->_include($_params['php_resource'], true);
+ } else {
+ $smarty->_eval($_params['php_resource']);
+ }
+ unset($params['args']['script']);
+ }
+
+ $_funcname = $smarty->_plugins['insert'][$params['args']['name']][0];
+ $_content = $_funcname($params['args'], $smarty);
+ if ($smarty->debugging) {
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $smarty->_smarty_debug_info[] = array('type' => 'insert',
+ 'filename' => 'insert_'.$params['args']['name'],
+ 'depth' => $smarty->_inclusion_depth,
+ 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time);
+ }
+
+ if (!empty($params['args']["assign"])) {
+ $smarty->assign($params['args']["assign"], $_content);
+ } else {
+ return $_content;
+ }
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.smarty_include_php.php b/lib/smarty-2.6.8/internals/core.smarty_include_php.php
new file mode 100644
index 0000000..30c6e76
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.smarty_include_php.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * called for included php files within templates
+ *
+ * @param string $smarty_file
+ * @param string $smarty_assign variable to assign the included template's
+ * output into
+ * @param boolean $smarty_once uses include_once if this is true
+ * @param array $smarty_include_vars associative array of vars from
+ * {include file="blah" var=$var}
+ */
+
+// $file, $assign, $once, $_smarty_include_vars
+
+function smarty_core_smarty_include_php($params, &$smarty)
+{
+ $_params = array('resource_name' => $params['smarty_file']);
+ require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');
+ smarty_core_get_php_resource($_params, $smarty);
+ $_smarty_resource_type = $_params['resource_type'];
+ $_smarty_php_resource = $_params['php_resource'];
+
+ if (!empty($params['smarty_assign'])) {
+ ob_start();
+ if ($_smarty_resource_type == 'file') {
+ $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']);
+ } else {
+ $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']);
+ }
+ $smarty->assign($params['smarty_assign'], ob_get_contents());
+ ob_end_clean();
+ } else {
+ if ($_smarty_resource_type == 'file') {
+ $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']);
+ } else {
+ $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']);
+ }
+ }
+}
+
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.write_cache_file.php b/lib/smarty-2.6.8/internals/core.write_cache_file.php
new file mode 100644
index 0000000..72f785b
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.write_cache_file.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Prepend the cache information to the cache file
+ * and write it
+ *
+ * @param string $tpl_file
+ * @param string $cache_id
+ * @param string $compile_id
+ * @param string $results
+ * @return true|null
+ */
+
+ // $tpl_file, $cache_id, $compile_id, $results
+
+function smarty_core_write_cache_file($params, &$smarty)
+{
+
+ // put timestamp in cache header
+ $smarty->_cache_info['timestamp'] = time();
+ if ($smarty->cache_lifetime > -1){
+ // expiration set
+ $smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime;
+ } else {
+ // cache will never expire
+ $smarty->_cache_info['expires'] = -1;
+ }
+
+ // collapse nocache.../nocache-tags
+ if (preg_match_all('!\{(/?)nocache\:[0-9a-f]{32}#\d+\}!', $params['results'], $match, PREG_PATTERN_ORDER)) {
+ // remove everything between every pair of outermost noache.../nocache-tags
+ // and replace it by a single nocache-tag
+ // this new nocache-tag will be replaced by dynamic contents in
+ // smarty_core_process_compiled_includes() on a cache-read
+
+ $match_count = count($match[0]);
+ $results = preg_split('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!', $params['results'], -1, PREG_SPLIT_DELIM_CAPTURE);
+
+ $level = 0;
+ $j = 0;
+ for ($i=0, $results_count = count($results); $i < $results_count && $j < $match_count; $i++) {
+ if ($results[$i] == $match[0][$j]) {
+ // nocache tag
+ if ($match[1][$j]) { // closing tag
+ $level--;
+ unset($results[$i]);
+ } else { // opening tag
+ if ($level++ > 0) unset($results[$i]);
+ }
+ $j++;
+ } elseif ($level > 0) {
+ unset($results[$i]);
+ }
+ }
+ $params['results'] = implode('', $results);
+ }
+ $smarty->_cache_info['cache_serials'] = $smarty->_cache_serials;
+
+ // prepend the cache header info into cache file
+ $_cache_info = serialize($smarty->_cache_info);
+ $params['results'] = strlen($_cache_info) . "\n" . $_cache_info . $params['results'];
+
+ if (!empty($smarty->cache_handler_func)) {
+ // use cache_handler function
+ call_user_func_array($smarty->cache_handler_func,
+ array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null));
+ } else {
+ // use local cache file
+
+ if(!@is_writable($smarty->cache_dir)) {
+ // cache_dir not writable, see if it exists
+ if(!@is_dir($smarty->cache_dir)) {
+ $smarty->trigger_error('the $cache_dir \'' . $smarty->cache_dir . '\' does not exist, or is not a directory.', E_USER_ERROR);
+ return false;
+ }
+ $smarty->trigger_error('unable to write to $cache_dir \'' . realpath($smarty->cache_dir) . '\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR);
+ return false;
+ }
+
+ $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']);
+ $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id);
+ $_params = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true);
+ require_once(SMARTY_CORE_DIR . 'core.write_file.php');
+ smarty_core_write_file($_params, $smarty);
+ return true;
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.write_compiled_include.php b/lib/smarty-2.6.8/internals/core.write_compiled_include.php
new file mode 100644
index 0000000..c14adb5
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.write_compiled_include.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Extract non-cacheable parts out of compiled template and write it
+ *
+ * @param string $compile_path
+ * @param string $template_compiled
+ * @return boolean
+ */
+
+function smarty_core_write_compiled_include($params, &$smarty)
+{
+ $_tag_start = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\'; endif;';
+ $_tag_end = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{/nocache\:(\\2)#(\\3)\}\'; endif;';
+
+ preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us',
+ $params['compiled_content'], $_match_source, PREG_SET_ORDER);
+
+ // no nocache-parts found: done
+ if (count($_match_source)==0) return;
+
+ // convert the matched php-code to functions
+ $_include_compiled = "<?php /* Smarty version ".$smarty->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
+ $_include_compiled .= " compiled from " . strtr(urlencode($params['resource_name']), array('%2F'=>'/', '%3A'=>':')) . " */\n\n";
+
+ $_compile_path = $params['include_file_path'];
+
+ $smarty->_cache_serials[$_compile_path] = $params['cache_serial'];
+ $_include_compiled .= "\$this->_cache_serials['".$_compile_path."'] = '".$params['cache_serial']."';\n\n?>";
+
+ $_include_compiled .= $params['plugins_code'];
+ $_include_compiled .= "<?php";
+
+ $this_varname = ((double)phpversion() >= 5.0) ? '_smarty' : 'this';
+ for ($_i = 0, $_for_max = count($_match_source); $_i < $_for_max; $_i++) {
+ $_match =& $_match_source[$_i];
+ $source = $_match[4];
+ if ($this_varname == '_smarty') {
+ /* rename $this to $_smarty in the sourcecode */
+ $tokens = token_get_all('<?php ' . $_match[4]);
+
+ /* remove trailing <?php */
+ $open_tag = '';
+ while ($tokens) {
+ $token = array_shift($tokens);
+ if (is_array($token)) {
+ $open_tag .= $token[1];
+ } else {
+ $open_tag .= $token;
+ }
+ if ($open_tag == '<?php ') break;
+ }
+
+ for ($i=0, $count = count($tokens); $i < $count; $i++) {
+ if (is_array($tokens[$i])) {
+ if ($tokens[$i][0] == T_VARIABLE && $tokens[$i][1] == '$this') {
+ $tokens[$i] = '$' . $this_varname;
+ } else {
+ $tokens[$i] = $tokens[$i][1];
+ }
+ }
+ }
+ $source = implode('', $tokens);
+ }
+
+ /* add function to compiled include */
+ $_include_compiled .= "
+function _smarty_tplfunc_$_match[2]_$_match[3](&\$$this_varname)
+{
+$source
+}
+
+";
+ }
+ $_include_compiled .= "\n\n?>\n";
+
+ $_params = array('filename' => $_compile_path,
+ 'contents' => $_include_compiled, 'create_dirs' => true);
+
+ require_once(SMARTY_CORE_DIR . 'core.write_file.php');
+ smarty_core_write_file($_params, $smarty);
+ return true;
+}
+
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.write_compiled_resource.php b/lib/smarty-2.6.8/internals/core.write_compiled_resource.php
new file mode 100644
index 0000000..b902eff
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.write_compiled_resource.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * write the compiled resource
+ *
+ * @param string $compile_path
+ * @param string $compiled_content
+ * @return true
+ */
+function smarty_core_write_compiled_resource($params, &$smarty)
+{
+ if(!@is_writable($smarty->compile_dir)) {
+ // compile_dir not writable, see if it exists
+ if(!@is_dir($smarty->compile_dir)) {
+ $smarty->trigger_error('the $compile_dir \'' . $smarty->compile_dir . '\' does not exist, or is not a directory.', E_USER_ERROR);
+ return false;
+ }
+ $smarty->trigger_error('unable to write to $compile_dir \'' . realpath($smarty->compile_dir) . '\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR);
+ return false;
+ }
+
+ $_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true);
+ require_once(SMARTY_CORE_DIR . 'core.write_file.php');
+ smarty_core_write_file($_params, $smarty);
+ return true;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/internals/core.write_file.php b/lib/smarty-2.6.8/internals/core.write_file.php
new file mode 100644
index 0000000..8a3a3b3
--- /dev/null
+++ b/lib/smarty-2.6.8/internals/core.write_file.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * write out a file to disk
+ *
+ * @param string $filename
+ * @param string $contents
+ * @param boolean $create_dirs
+ * @return boolean
+ */
+function smarty_core_write_file($params, &$smarty)
+{
+ $_dirname = dirname($params['filename']);
+
+ if ($params['create_dirs']) {
+ $_params = array('dir' => $_dirname);
+ require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php');
+ smarty_core_create_dir_structure($_params, $smarty);
+ }
+
+ // write to tmp file, then rename it to avoid file locking race condition
+ $_tmp_file = tempnam($_dirname, 'wrt');
+
+ if (!($fd = @fopen($_tmp_file, 'wb'))) {
+ $_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt');
+ if (!($fd = @fopen($_tmp_file, 'wb'))) {
+ $smarty->trigger_error("problem writing temporary file '$_tmp_file'");
+ return false;
+ }
+ }
+
+ fwrite($fd, $params['contents']);
+ fclose($fd);
+
+ if (DIRECTORY_SEPARATOR == '\\' || !@rename($_tmp_file, $params['filename'])) {
+ // On platforms and filesystems that cannot overwrite with rename()
+ // delete the file before renaming it -- because windows always suffers
+ // this, it is short-circuited to avoid the initial rename() attempt
+ @unlink($params['filename']);
+ @rename($_tmp_file, $params['filename']);
+ }
+ @chmod($params['filename'], $smarty->_file_perms);
+
+ return true;
+}
+
+/* vim: set expandtab: */
+
+?> \ No newline at end of file
diff --git a/lib/smarty-2.6.8/plugins/block.textformat.php b/lib/smarty-2.6.8/plugins/block.textformat.php
new file mode 100644
index 0000000..8cd010a
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/block.textformat.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {textformat}{/textformat} block plugin
+ *
+ * Type: block function<br>
+ * Name: textformat<br>
+ * Purpose: format text a certain way with preset styles
+ * or custom wrap/indent settings<br>
+ * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat}
+ * (Smarty online manual)
+ * @param array
+ * <pre>
+ * Params: style: string (email)
+ * indent: integer (0)
+ * wrap: integer (80)
+ * wrap_char string ("\n")
+ * indent_char: string (" ")
+ * wrap_boundary: boolean (true)
+ * </pre>
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string contents of the block
+ * @param Smarty clever simulation of a method
+ * @return string string $content re-formatted
+ */
+function smarty_block_textformat($params, $content, &$smarty)
+{
+ if (is_null($content)) {
+ return;
+ }
+
+ $style = null;
+ $indent = 0;
+ $indent_first = 0;
+ $indent_char = ' ';
+ $wrap = 80;
+ $wrap_char = "\n";
+ $wrap_cut = false;
+ $assign = null;
+
+ foreach ($params as $_key => $_val) {
+ switch ($_key) {
+ case 'style':
+ case 'indent_char':
+ case 'wrap_char':
+ case 'assign':
+ $$_key = (string)$_val;
+ break;
+
+ case 'indent':
+ case 'indent_first':
+ case 'wrap':
+ $$_key = (int)$_val;
+ break;
+
+ case 'wrap_cut':
+ $$_key = (bool)$_val;
+ break;
+
+ default:
+ $smarty->trigger_error("textformat: unknown attribute '$_key'");
+ }
+ }
+
+ if ($style == 'email') {
+ $wrap = 72;
+ }
+
+ // split into paragraphs
+ $_paragraphs = preg_split('![\r\n][\r\n]!',$content);
+ $_output = '';
+
+ for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) {
+ if ($_paragraphs[$_x] == '') {
+ continue;
+ }
+ // convert mult. spaces & special chars to single space
+ $_paragraphs[$_x] = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'), array(' ',''), $_paragraphs[$_x]);
+ // indent first line
+ if($indent_first > 0) {
+ $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x];
+ }
+ // wordwrap sentences
+ $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut);
+ // indent lines
+ if($indent > 0) {
+ $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]);
+ }
+ }
+ $_output = implode($wrap_char . $wrap_char, $_paragraphs);
+
+ return $assign ? $smarty->assign($assign, $_output) : $_output;
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/compiler.assign.php b/lib/smarty-2.6.8/plugins/compiler.assign.php
new file mode 100644
index 0000000..be17298
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/compiler.assign.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {assign} compiler function plugin
+ *
+ * Type: compiler function<br>
+ * Name: assign<br>
+ * Purpose: assign a value to a template variable
+ * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com> (initial author)
+ * @auther messju mohr <messju at lammfellpuschen dot de> (conversion to compiler function)
+ * @param string containing var-attribute and value-attribute
+ * @param Smarty_Compiler
+ */
+function smarty_compiler_assign($tag_attrs, &$compiler)
+{
+ $_params = $compiler->_parse_attrs($tag_attrs);
+
+ if (!isset($_params['var'])) {
+ $compiler->_syntax_error("assign: missing 'var' parameter", E_USER_WARNING);
+ return;
+ }
+
+ if (!isset($_params['value'])) {
+ $compiler->_syntax_error("assign: missing 'value' parameter", E_USER_WARNING);
+ return;
+ }
+
+ return "\$this->assign({$_params['var']}, {$_params['value']});";
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.assign_debug_info.php b/lib/smarty-2.6.8/plugins/function.assign_debug_info.php
new file mode 100644
index 0000000..6540498
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.assign_debug_info.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {assign_debug_info} function plugin
+ *
+ * Type: function<br>
+ * Name: assign_debug_info<br>
+ * Purpose: assign debug info to the template<br>
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array unused in this plugin, this plugin uses {@link Smarty::$_config},
+ * {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info}
+ * @param Smarty
+ */
+function smarty_function_assign_debug_info($params, &$smarty)
+{
+ $assigned_vars = $smarty->_tpl_vars;
+ ksort($assigned_vars);
+ if (@is_array($smarty->_config[0])) {
+ $config_vars = $smarty->_config[0];
+ ksort($config_vars);
+ $smarty->assign("_debug_config_keys", array_keys($config_vars));
+ $smarty->assign("_debug_config_vals", array_values($config_vars));
+ }
+
+ $included_templates = $smarty->_smarty_debug_info;
+
+ $smarty->assign("_debug_keys", array_keys($assigned_vars));
+ $smarty->assign("_debug_vals", array_values($assigned_vars));
+
+ $smarty->assign("_debug_tpls", $included_templates);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.config_load.php b/lib/smarty-2.6.8/plugins/function.config_load.php
new file mode 100644
index 0000000..db89f63
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.config_load.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {config_load} function plugin
+ *
+ * Type: function<br>
+ * Name: config_load<br>
+ * Purpose: load config file vars
+ * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author messju mohr <messju at lammfellpuschen dot de> (added use of resources)
+ * @param array Format:
+ * <pre>
+ * array('file' => required config file name,
+ * 'section' => optional config file section to load
+ * 'scope' => local/parent/global
+ * 'global' => overrides scope, setting to parent if true)
+ * </pre>
+ * @param Smarty
+ */
+function smarty_function_config_load($params, &$smarty)
+{
+ if ($smarty->debugging) {
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $_debug_start_time = smarty_core_get_microtime($_params, $smarty);
+ }
+
+ $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null;
+ $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null;
+ $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global';
+ $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false;
+
+ if (!isset($_file) || strlen($_file) == 0) {
+ $smarty->trigger_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__);
+ }
+
+ if (isset($_scope)) {
+ if ($_scope != 'local' &&
+ $_scope != 'parent' &&
+ $_scope != 'global') {
+ $smarty->trigger_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__);
+ }
+ } else {
+ if ($_global) {
+ $_scope = 'parent';
+ } else {
+ $_scope = 'local';
+ }
+ }
+
+ $_params = array('resource_name' => $_file,
+ 'resource_base_path' => $smarty->config_dir,
+ 'get_source' => false);
+ $smarty->_parse_resource_name($_params);
+ $_file_path = $_params['resource_type'] . ':' . $_params['resource_name'];
+ if (isset($_section))
+ $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section);
+ else
+ $_compile_file = $smarty->_get_compile_path($_file_path);
+
+ if($smarty->force_compile || !file_exists($_compile_file)) {
+ $_compile = true;
+ } elseif ($smarty->compile_check) {
+ $_params = array('resource_name' => $_file,
+ 'resource_base_path' => $smarty->config_dir,
+ 'get_source' => false);
+ $_compile = $smarty->_fetch_resource_info($_params) &&
+ $_params['resource_timestamp'] > filemtime($_compile_file);
+ } else {
+ $_compile = false;
+ }
+
+ if($_compile) {
+ // compile config file
+ if(!is_object($smarty->_conf_obj)) {
+ require_once SMARTY_DIR . $smarty->config_class . '.class.php';
+ $smarty->_conf_obj = new $smarty->config_class();
+ $smarty->_conf_obj->overwrite = $smarty->config_overwrite;
+ $smarty->_conf_obj->booleanize = $smarty->config_booleanize;
+ $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden;
+ $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines;
+ }
+
+ $_params = array('resource_name' => $_file,
+ 'resource_base_path' => $smarty->config_dir,
+ $_params['get_source'] = true);
+ if (!$smarty->_fetch_resource_info($_params)) {
+ return;
+ }
+ $smarty->_conf_obj->set_file_contents($_file, $_params['source_content']);
+ $_config_vars = array_merge($smarty->_conf_obj->get($_file),
+ $smarty->_conf_obj->get($_file, $_section));
+ if(function_exists('var_export')) {
+ $_output = '<?php $_config_vars = ' . var_export($_config_vars, true) . '; ?>';
+ } else {
+ $_output = '<?php $_config_vars = unserialize(\'' . strtr(serialize($_config_vars),array('\''=>'\\\'', '\\'=>'\\\\')) . '\'); ?>';
+ }
+ $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => $_params['resource_timestamp']));
+ require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php');
+ smarty_core_write_compiled_resource($_params, $smarty);
+ } else {
+ include($_compile_file);
+ }
+
+ if ($smarty->caching) {
+ $smarty->_cache_info['config'][$_file] = true;
+ }
+
+ $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars);
+ $smarty->_config[0]['files'][$_file] = true;
+
+ if ($_scope == 'parent') {
+ $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars);
+ $smarty->_config[1]['files'][$_file] = true;
+ } else if ($_scope == 'global') {
+ for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) {
+ $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars);
+ $smarty->_config[$i]['files'][$_file] = true;
+ }
+ }
+
+ if ($smarty->debugging) {
+ $_params = array();
+ require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+ $smarty->_smarty_debug_info[] = array('type' => 'config',
+ 'filename' => $_file.' ['.$_section.'] '.$_scope,
+ 'depth' => $smarty->_inclusion_depth,
+ 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time);
+ }
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.counter.php b/lib/smarty-2.6.8/plugins/function.counter.php
new file mode 100644
index 0000000..1f26db5
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.counter.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {counter} function plugin
+ *
+ * Type: function<br>
+ * Name: counter<br>
+ * Purpose: print out a counter value
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @link http://smarty.php.net/manual/en/language.function.counter.php {counter}
+ * (Smarty online manual)
+ * @param array parameters
+ * @param Smarty
+ * @return string|null
+ */
+function smarty_function_counter($params, &$smarty)
+{
+ static $counters = array();
+
+ $name = (isset($params['name'])) ? $params['name'] : 'default';
+ if (!isset($counters[$name])) {
+ $counters[$name] = array(
+ 'start'=>1,
+ 'skip'=>1,
+ 'direction'=>'up',
+ 'count'=>1
+ );
+ }
+ $counter =& $counters[$name];
+
+ if (isset($params['start'])) {
+ $counter['start'] = $counter['count'] = (int)$params['start'];
+ }
+
+ if (!empty($params['assign'])) {
+ $counter['assign'] = $params['assign'];
+ }
+
+ if (isset($counter['assign'])) {
+ $smarty->assign($counter['assign'], $counter['count']);
+ }
+
+ if (isset($params['print'])) {
+ $print = (bool)$params['print'];
+ } else {
+ $print = empty($counter['assign']);
+ }
+
+ if ($print) {
+ $retval = $counter['count'];
+ } else {
+ $retval = null;
+ }
+
+ if (isset($params['skip'])) {
+ $counter['skip'] = $params['skip'];
+ }
+
+ if (isset($params['direction'])) {
+ $counter['direction'] = $params['direction'];
+ }
+
+ if ($counter['direction'] == "down")
+ $counter['count'] -= $counter['skip'];
+ else
+ $counter['count'] += $counter['skip'];
+
+ return $retval;
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.cycle.php b/lib/smarty-2.6.8/plugins/function.cycle.php
new file mode 100644
index 0000000..fe78bb8
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.cycle.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {cycle} function plugin
+ *
+ * Type: function<br>
+ * Name: cycle<br>
+ * Date: May 3, 2002<br>
+ * Purpose: cycle through given values<br>
+ * Input:
+ * - name = name of cycle (optional)
+ * - values = comma separated list of values to cycle,
+ * or an array of values to cycle
+ * (this can be left out for subsequent calls)
+ * - reset = boolean - resets given var to true
+ * - print = boolean - print var or not. default is true
+ * - advance = boolean - whether or not to advance the cycle
+ * - delimiter = the value delimiter, default is ","
+ * - assign = boolean, assigns to template var instead of
+ * printed.
+ *
+ * Examples:<br>
+ * <pre>
+ * {cycle values="#eeeeee,#d0d0d0d"}
+ * {cycle name=row values="one,two,three" reset=true}
+ * {cycle name=row}
+ * </pre>
+ * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author credit to Mark Priatel <mpriatel@rogers.com>
+ * @author credit to Gerard <gerard@interfold.com>
+ * @author credit to Jason Sweat <jsweat_php@yahoo.com>
+ * @version 1.3
+ * @param array
+ * @param Smarty
+ * @return string|null
+ */
+function smarty_function_cycle($params, &$smarty)
+{
+ static $cycle_vars;
+
+ $name = (empty($params['name'])) ? 'default' : $params['name'];
+ $print = (isset($params['print'])) ? (bool)$params['print'] : true;
+ $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true;
+ $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false;
+
+ if (!in_array('values', array_keys($params))) {
+ if(!isset($cycle_vars[$name]['values'])) {
+ $smarty->trigger_error("cycle: missing 'values' parameter");
+ return;
+ }
+ } else {
+ if(isset($cycle_vars[$name]['values'])
+ && $cycle_vars[$name]['values'] != $params['values'] ) {
+ $cycle_vars[$name]['index'] = 0;
+ }
+ $cycle_vars[$name]['values'] = $params['values'];
+ }
+
+ $cycle_vars[$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ',';
+
+ if(is_array($cycle_vars[$name]['values'])) {
+ $cycle_array = $cycle_vars[$name]['values'];
+ } else {
+ $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']);
+ }
+
+ if(!isset($cycle_vars[$name]['index']) || $reset ) {
+ $cycle_vars[$name]['index'] = 0;
+ }
+
+ if (isset($params['assign'])) {
+ $print = false;
+ $smarty->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]);
+ }
+
+ if($print) {
+ $retval = $cycle_array[$cycle_vars[$name]['index']];
+ } else {
+ $retval = null;
+ }
+
+ if($advance) {
+ if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) {
+ $cycle_vars[$name]['index'] = 0;
+ } else {
+ $cycle_vars[$name]['index']++;
+ }
+ }
+
+ return $retval;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.debug.php b/lib/smarty-2.6.8/plugins/function.debug.php
new file mode 100644
index 0000000..4345230
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.debug.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {debug} function plugin
+ *
+ * Type: function<br>
+ * Name: debug<br>
+ * Date: July 1, 2002<br>
+ * Purpose: popup debug window
+ * @link http://smarty.php.net/manual/en/language.function.debug.php {debug}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @version 1.0
+ * @param array
+ * @param Smarty
+ * @return string output from {@link Smarty::_generate_debug_output()}
+ */
+function smarty_function_debug($params, &$smarty)
+{
+ if (isset($params['output'])) {
+ $smarty->assign('_smarty_debug_output', $params['output']);
+ }
+ require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');
+ return smarty_core_display_debug_console(null, $smarty);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.eval.php b/lib/smarty-2.6.8/plugins/function.eval.php
new file mode 100644
index 0000000..ff0472d
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.eval.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {eval} function plugin
+ *
+ * Type: function<br>
+ * Name: eval<br>
+ * Purpose: evaluate a template variable as a template<br>
+ * @link http://smarty.php.net/manual/en/language.function.eval.php {eval}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array
+ * @param Smarty
+ */
+function smarty_function_eval($params, &$smarty)
+{
+
+ if (!isset($params['var'])) {
+ $smarty->trigger_error("eval: missing 'var' parameter");
+ return;
+ }
+
+ if($params['var'] == '') {
+ return;
+ }
+
+ $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled);
+
+ ob_start();
+ $smarty->_eval('?>' . $_var_compiled);
+ $_contents = ob_get_contents();
+ ob_end_clean();
+
+ if (!empty($params['assign'])) {
+ $smarty->assign($params['assign'], $_contents);
+ } else {
+ return $_contents;
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.fetch.php b/lib/smarty-2.6.8/plugins/function.fetch.php
new file mode 100644
index 0000000..81b1bfc
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.fetch.php
@@ -0,0 +1,221 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {fetch} plugin
+ *
+ * Type: function<br>
+ * Name: fetch<br>
+ * Purpose: fetch file, web or ftp data and display results
+ * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array
+ * @param Smarty
+ * @return string|null if the assign parameter is passed, Smarty assigns the
+ * result to a template variable
+ */
+function smarty_function_fetch($params, &$smarty)
+{
+ if (empty($params['file'])) {
+ $smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty");
+ return;
+ }
+
+ $content = '';
+ if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) {
+ $_params = array('resource_type' => 'file', 'resource_name' => $params['file']);
+ require_once(SMARTY_CORE_DIR . 'core.is_secure.php');
+ if(!smarty_core_is_secure($_params, $smarty)) {
+ $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed');
+ return;
+ }
+
+ // fetch the file
+ if($fp = @fopen($params['file'],'r')) {
+ while(!feof($fp)) {
+ $content .= fgets ($fp,4096);
+ }
+ fclose($fp);
+ } else {
+ $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\'');
+ return;
+ }
+ } else {
+ // not a local file
+ if(preg_match('!^http://!i',$params['file'])) {
+ // http fetch
+ if($uri_parts = parse_url($params['file'])) {
+ // set defaults
+ $host = $server_name = $uri_parts['host'];
+ $timeout = 30;
+ $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
+ $agent = "Smarty Template Engine ".$smarty->_version;
+ $referer = "";
+ $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/';
+ $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : '';
+ $_is_proxy = false;
+ if(empty($uri_parts['port'])) {
+ $port = 80;
+ } else {
+ $port = $uri_parts['port'];
+ }
+ if(!empty($uri_parts['user'])) {
+ $user = $uri_parts['user'];
+ }
+ if(!empty($uri_parts['pass'])) {
+ $pass = $uri_parts['pass'];
+ }
+ // loop through parameters, setup headers
+ foreach($params as $param_key => $param_value) {
+ switch($param_key) {
+ case "file":
+ case "assign":
+ case "assign_headers":
+ break;
+ case "user":
+ if(!empty($param_value)) {
+ $user = $param_value;
+ }
+ break;
+ case "pass":
+ if(!empty($param_value)) {
+ $pass = $param_value;
+ }
+ break;
+ case "accept":
+ if(!empty($param_value)) {
+ $accept = $param_value;
+ }
+ break;
+ case "header":
+ if(!empty($param_value)) {
+ if(!preg_match('![\w\d-]+: .+!',$param_value)) {
+ $smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'");
+ return;
+ } else {
+ $extra_headers[] = $param_value;
+ }
+ }
+ break;
+ case "proxy_host":
+ if(!empty($param_value)) {
+ $proxy_host = $param_value;
+ }
+ break;
+ case "proxy_port":
+ if(!preg_match('!\D!', $param_value)) {
+ $proxy_port = (int) $param_value;
+ } else {
+ $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'");
+ return;
+ }
+ break;
+ case "agent":
+ if(!empty($param_value)) {
+ $agent = $param_value;
+ }
+ break;
+ case "referer":
+ if(!empty($param_value)) {
+ $referer = $param_value;
+ }
+ break;
+ case "timeout":
+ if(!preg_match('!\D!', $param_value)) {
+ $timeout = (int) $param_value;
+ } else {
+ $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'");
+ return;
+ }
+ break;
+ default:
+ $smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'");
+ return;
+ }
+ }
+ if(!empty($proxy_host) && !empty($proxy_port)) {
+ $_is_proxy = true;
+ $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout);
+ } else {
+ $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout);
+ }
+
+ if(!$fp) {
+ $smarty->_trigger_fatal_error("[plugin] unable to fetch: $errstr ($errno)");
+ return;
+ } else {
+ if($_is_proxy) {
+ fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n");
+ } else {
+ fputs($fp, "GET $uri HTTP/1.0\r\n");
+ }
+ if(!empty($host)) {
+ fputs($fp, "Host: $host\r\n");
+ }
+ if(!empty($accept)) {
+ fputs($fp, "Accept: $accept\r\n");
+ }
+ if(!empty($agent)) {
+ fputs($fp, "User-Agent: $agent\r\n");
+ }
+ if(!empty($referer)) {
+ fputs($fp, "Referer: $referer\r\n");
+ }
+ if(isset($extra_headers) && is_array($extra_headers)) {
+ foreach($extra_headers as $curr_header) {
+ fputs($fp, $curr_header."\r\n");
+ }
+ }
+ if(!empty($user) && !empty($pass)) {
+ fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n");
+ }
+
+ fputs($fp, "\r\n");
+ while(!feof($fp)) {
+ $content .= fgets($fp,4096);
+ }
+ fclose($fp);
+ $csplit = split("\r\n\r\n",$content,2);
+
+ $content = $csplit[1];
+
+ if(!empty($params['assign_headers'])) {
+ $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0]));
+ }
+ }
+ } else {
+ $smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax");
+ return;
+ }
+ } else {
+ // ftp fetch
+ if($fp = @fopen($params['file'],'r')) {
+ while(!feof($fp)) {
+ $content .= fgets ($fp,4096);
+ }
+ fclose($fp);
+ } else {
+ $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\'');
+ return;
+ }
+ }
+
+ }
+
+
+ if (!empty($params['assign'])) {
+ $smarty->assign($params['assign'],$content);
+ } else {
+ return $content;
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.html_checkboxes.php b/lib/smarty-2.6.8/plugins/function.html_checkboxes.php
new file mode 100644
index 0000000..ed8ad7f
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.html_checkboxes.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_checkboxes} function plugin
+ *
+ * File: function.html_checkboxes.php<br>
+ * Type: function<br>
+ * Name: html_checkboxes<br>
+ * Date: 24.Feb.2003<br>
+ * Purpose: Prints out a list of checkbox input types<br>
+ * Input:<br>
+ * - name (optional) - string default "checkbox"
+ * - values (required) - array
+ * - options (optional) - associative array
+ * - checked (optional) - array default not set
+ * - separator (optional) - ie <br> or &nbsp;
+ * - output (optional) - the output next to each checkbox
+ * - assign (optional) - assign the output as an array to this variable
+ * Examples:
+ * <pre>
+ * {html_checkboxes values=$ids output=$names}
+ * {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
+ * {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
+ * </pre>
+ * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}
+ * (Smarty online manual)
+ * @author Christopher Kvarme <christopher.kvarme@flashjab.com>
+ * @author credits to Monte Ohrt <monte at ohrt dot com>
+ * @version 1.0
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_function_escape_special_chars()
+ */
+function smarty_function_html_checkboxes($params, &$smarty)
+{
+ require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+
+ $name = 'checkbox';
+ $values = null;
+ $options = null;
+ $selected = null;
+ $separator = '';
+ $labels = true;
+ $output = null;
+
+ $extra = '';
+
+ foreach($params as $_key => $_val) {
+ switch($_key) {
+ case 'name':
+ case 'separator':
+ $$_key = $_val;
+ break;
+
+ case 'labels':
+ $$_key = (bool)$_val;
+ break;
+
+ case 'options':
+ $$_key = (array)$_val;
+ break;
+
+ case 'values':
+ case 'output':
+ $$_key = array_values((array)$_val);
+ break;
+
+ case 'checked':
+ case 'selected':
+ $selected = array_map('strval', array_values((array)$_val));
+ break;
+
+ case 'checkboxes':
+ $smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING);
+ $options = (array)$_val;
+ break;
+
+ case 'assign':
+ break;
+
+ default:
+ if(!is_array($_val)) {
+ $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
+ } else {
+ $smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+ }
+ break;
+ }
+ }
+
+ if (!isset($options) && !isset($values))
+ return ''; /* raise error here? */
+
+ settype($selected, 'array');
+ $_html_result = array();
+
+ if (isset($options)) {
+
+ foreach ($options as $_key=>$_val)
+ $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
+
+
+ } else {
+ foreach ($values as $_i=>$_key) {
+ $_val = isset($output[$_i]) ? $output[$_i] : '';
+ $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
+ }
+
+ }
+
+ if(!empty($params['assign'])) {
+ $smarty->assign($params['assign'], $_html_result);
+ } else {
+ return implode("\n",$_html_result);
+ }
+
+}
+
+function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) {
+ $_output = '';
+ if ($labels) $_output .= '<label>';
+ $_output .= '<input type="checkbox" name="'
+ . smarty_function_escape_special_chars($name) . '[]" value="'
+ . smarty_function_escape_special_chars($value) . '"';
+
+ if (in_array((string)$value, $selected)) {
+ $_output .= ' checked="checked"';
+ }
+ $_output .= $extra . ' />' . $output;
+ if ($labels) $_output .= '</label>';
+ $_output .= $separator;
+
+ return $_output;
+}
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.html_image.php b/lib/smarty-2.6.8/plugins/function.html_image.php
new file mode 100644
index 0000000..9abae72
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.html_image.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_image} function plugin
+ *
+ * Type: function<br>
+ * Name: html_image<br>
+ * Date: Feb 24, 2003<br>
+ * Purpose: format HTML tags for the image<br>
+ * Input:<br>
+ * - file = file (and path) of image (required)
+ * - height = image height (optional, default actual height)
+ * - width = image width (optional, default actual width)
+ * - basedir = base directory for absolute paths, default
+ * is environment variable DOCUMENT_ROOT
+ * - path_prefix = prefix for path output (optional, default empty)
+ *
+ * Examples: {html_image file="/images/masthead.gif"}
+ * Output: <img src="/images/masthead.gif" width=400 height=23>
+ * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author credits to Duda <duda@big.hu> - wrote first image function
+ * in repository, helped with lots of functionality
+ * @version 1.0
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_function_escape_special_chars()
+ */
+function smarty_function_html_image($params, &$smarty)
+{
+ require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+
+ $alt = '';
+ $file = '';
+ $height = '';
+ $width = '';
+ $extra = '';
+ $prefix = '';
+ $suffix = '';
+ $path_prefix = '';
+ $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
+ $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : '';
+ foreach($params as $_key => $_val) {
+ switch($_key) {
+ case 'file':
+ case 'height':
+ case 'width':
+ case 'dpi':
+ case 'path_prefix':
+ case 'basedir':
+ $$_key = $_val;
+ break;
+
+ case 'alt':
+ if(!is_array($_val)) {
+ $$_key = smarty_function_escape_special_chars($_val);
+ } else {
+ $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+ }
+ break;
+
+ case 'link':
+ case 'href':
+ $prefix = '<a href="' . $_val . '">';
+ $suffix = '</a>';
+ break;
+
+ default:
+ if(!is_array($_val)) {
+ $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
+ } else {
+ $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+ }
+ break;
+ }
+ }
+
+ if (empty($file)) {
+ $smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE);
+ return;
+ }
+
+ if (substr($file,0,1) == '/') {
+ $_image_path = $basedir . $file;
+ } else {
+ $_image_path = $file;
+ }
+
+ if(!isset($params['width']) || !isset($params['height'])) {
+ if(!$_image_data = @getimagesize($_image_path)) {
+ if(!file_exists($_image_path)) {
+ $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE);
+ return;
+ } else if(!is_readable($_image_path)) {
+ $smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE);
+ return;
+ } else {
+ $smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE);
+ return;
+ }
+ }
+ if ($smarty->security &&
+ ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) &&
+ (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) &&
+ (!smarty_core_is_secure($_params, $smarty)) ) {
+ $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE);
+ }
+
+ if(!isset($params['width'])) {
+ $width = $_image_data[0];
+ }
+ if(!isset($params['height'])) {
+ $height = $_image_data[1];
+ }
+
+ }
+
+ if(isset($params['dpi'])) {
+ if(strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) {
+ $dpi_default = 72;
+ } else {
+ $dpi_default = 96;
+ }
+ $_resize = $dpi_default/$params['dpi'];
+ $width = round($width * $_resize);
+ $height = round($height * $_resize);
+ }
+
+ return $prefix . '<img src="'.$path_prefix.$file.'" alt="'.$alt.'" width="'.$width.'" height="'.$height.'"'.$extra.' />' . $suffix;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.html_options.php b/lib/smarty-2.6.8/plugins/function.html_options.php
new file mode 100644
index 0000000..cebadde
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.html_options.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_options} function plugin
+ *
+ * Type: function<br>
+ * Name: html_options<br>
+ * Input:<br>
+ * - name (optional) - string default "select"
+ * - values (required if no options supplied) - array
+ * - options (required if no values supplied) - associative array
+ * - selected (optional) - string default not set
+ * - output (required if not options supplied) - array
+ * Purpose: Prints the list of <option> tags generated from
+ * the passed parameters
+ * @link http://smarty.php.net/manual/en/language.function.html.options.php {html_image}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_function_escape_special_chars()
+ */
+function smarty_function_html_options($params, &$smarty)
+{
+ require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+
+ $name = null;
+ $values = null;
+ $options = null;
+ $selected = array();
+ $output = null;
+
+ $extra = '';
+
+ foreach($params as $_key => $_val) {
+ switch($_key) {
+ case 'name':
+ $$_key = (string)$_val;
+ break;
+
+ case 'options':
+ $$_key = (array)$_val;
+ break;
+
+ case 'values':
+ case 'output':
+ $$_key = array_values((array)$_val);
+ break;
+
+ case 'selected':
+ $$_key = array_map('strval', array_values((array)$_val));
+ break;
+
+ default:
+ if(!is_array($_val)) {
+ $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
+ } else {
+ $smarty->trigger_error("html_options: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+ }
+ break;
+ }
+ }
+
+ if (!isset($options) && !isset($values))
+ return ''; /* raise error here? */
+
+ $_html_result = '';
+
+ if (isset($options)) {
+
+ foreach ($options as $_key=>$_val)
+ $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected);
+
+ } else {
+
+ foreach ($values as $_i=>$_key) {
+ $_val = isset($output[$_i]) ? $output[$_i] : '';
+ $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected);
+ }
+
+ }
+
+ if(!empty($name)) {
+ $_html_result = '<select name="' . $name . '"' . $extra . '>' . "\n" . $_html_result . '</select>' . "\n";
+ }
+
+ return $_html_result;
+
+}
+
+function smarty_function_html_options_optoutput($key, $value, $selected) {
+ if(!is_array($value)) {
+ $_html_result = '<option label="' . smarty_function_escape_special_chars($value) . '" value="' .
+ smarty_function_escape_special_chars($key) . '"';
+ if (in_array((string)$key, $selected))
+ $_html_result .= ' selected="selected"';
+ $_html_result .= '>' . smarty_function_escape_special_chars($value) . '</option>' . "\n";
+ } else {
+ $_html_result = smarty_function_html_options_optgroup($key, $value, $selected);
+ }
+ return $_html_result;
+}
+
+function smarty_function_html_options_optgroup($key, $values, $selected) {
+ $optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n";
+ foreach ($values as $key => $value) {
+ $optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected);
+ }
+ $optgroup_html .= "</optgroup>\n";
+ return $optgroup_html;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.html_radios.php b/lib/smarty-2.6.8/plugins/function.html_radios.php
new file mode 100644
index 0000000..7503cfa
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.html_radios.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_radios} function plugin
+ *
+ * File: function.html_radios.php<br>
+ * Type: function<br>
+ * Name: html_radios<br>
+ * Date: 24.Feb.2003<br>
+ * Purpose: Prints out a list of radio input types<br>
+ * Input:<br>
+ * - name (optional) - string default "radio"
+ * - values (required) - array
+ * - options (optional) - associative array
+ * - checked (optional) - array default not set
+ * - separator (optional) - ie <br> or &nbsp;
+ * - output (optional) - the output next to each radio button
+ * - assign (optional) - assign the output as an array to this variable
+ * Examples:
+ * <pre>
+ * {html_radios values=$ids output=$names}
+ * {html_radios values=$ids name='box' separator='<br>' output=$names}
+ * {html_radios values=$ids checked=$checked separator='<br>' output=$names}
+ * </pre>
+ * @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios}
+ * (Smarty online manual)
+ * @author Christopher Kvarme <christopher.kvarme@flashjab.com>
+ * @author credits to Monte Ohrt <monte at ohrt dot com>
+ * @version 1.0
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_function_escape_special_chars()
+ */
+function smarty_function_html_radios($params, &$smarty)
+{
+ require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+
+ $name = 'radio';
+ $values = null;
+ $options = null;
+ $selected = null;
+ $separator = '';
+ $labels = true;
+ $label_ids = false;
+ $output = null;
+ $extra = '';
+
+ foreach($params as $_key => $_val) {
+ switch($_key) {
+ case 'name':
+ case 'separator':
+ $$_key = (string)$_val;
+ break;
+
+ case 'checked':
+ case 'selected':
+ if(is_array($_val)) {
+ $smarty->trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING);
+ } else {
+ $selected = (string)$_val;
+ }
+ break;
+
+ case 'labels':
+ case 'label_ids':
+ $$_key = (bool)$_val;
+ break;
+
+ case 'options':
+ $$_key = (array)$_val;
+ break;
+
+ case 'values':
+ case 'output':
+ $$_key = array_values((array)$_val);
+ break;
+
+ case 'radios':
+ $smarty->trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING);
+ $options = (array)$_val;
+ break;
+
+ case 'assign':
+ break;
+
+ default:
+ if(!is_array($_val)) {
+ $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
+ } else {
+ $smarty->trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+ }
+ break;
+ }
+ }
+
+ if (!isset($options) && !isset($values))
+ return ''; /* raise error here? */
+
+ $_html_result = array();
+
+ if (isset($options)) {
+
+ foreach ($options as $_key=>$_val)
+ $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids);
+
+ } else {
+
+ foreach ($values as $_i=>$_key) {
+ $_val = isset($output[$_i]) ? $output[$_i] : '';
+ $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids);
+ }
+
+ }
+
+ if(!empty($params['assign'])) {
+ $smarty->assign($params['assign'], $_html_result);
+ } else {
+ return implode("\n",$_html_result);
+ }
+
+}
+
+function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids) {
+ $_output = '';
+ if ($labels) {
+ if($label_ids) {
+ $_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!', '_', $name . '_' . $value));
+ $_output .= '<label for="' . $_id . '">';
+ } else {
+ $_output .= '<label>';
+ }
+ }
+ $_output .= '<input type="radio" name="'
+ . smarty_function_escape_special_chars($name) . '" value="'
+ . smarty_function_escape_special_chars($value) . '"';
+
+ if ($labels && $label_ids) $_output .= ' id="' . $_id . '"';
+
+ if ((string)$value==$selected) {
+ $_output .= ' checked="checked"';
+ }
+ $_output .= $extra . ' />' . $output;
+ if ($labels) $_output .= '</label>';
+ $_output .= $separator;
+
+ return $_output;
+}
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.html_select_date.php b/lib/smarty-2.6.8/plugins/function.html_select_date.php
new file mode 100644
index 0000000..e5eb183
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.html_select_date.php
@@ -0,0 +1,331 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {html_select_date} plugin
+ *
+ * Type: function<br>
+ * Name: html_select_date<br>
+ * Purpose: Prints the dropdowns for date selection.
+ *
+ * ChangeLog:<br>
+ * - 1.0 initial release
+ * - 1.1 added support for +/- N syntax for begin
+ * and end year values. (Monte)
+ * - 1.2 added support for yyyy-mm-dd syntax for
+ * time value. (Jan Rosier)
+ * - 1.3 added support for choosing format for
+ * month values (Gary Loescher)
+ * - 1.3.1 added support for choosing format for
+ * day values (Marcus Bointon)
+ * - 1.3.2 support negative timestamps, force year
+ * dropdown to include given date unless explicitly set (Monte)
+ * - 1.3.4 fix behaviour of 0000-00-00 00:00:00 dates to match that
+ * of 0000-00-00 dates (cybot, boots)
+ * @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date}
+ * (Smarty online manual)
+ * @version 1.3.4
+ * @author Andrei Zmievski
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_html_select_date($params, &$smarty)
+{
+ require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+ require_once $smarty->_get_plugin_filepath('shared','make_timestamp');
+ require_once $smarty->_get_plugin_filepath('function','html_options');
+ /* Default values. */
+ $prefix = "Date_";
+ $start_year = strftime("%Y");
+ $end_year = $start_year;
+ $display_days = true;
+ $display_months = true;
+ $display_years = true;
+ $month_format = "%B";
+ /* Write months as numbers by default GL */
+ $month_value_format = "%m";
+ $day_format = "%02d";
+ /* Write day values using this format MB */
+ $day_value_format = "%d";
+ $year_as_text = false;
+ /* Display years in reverse order? Ie. 2000,1999,.... */
+ $reverse_years = false;
+ /* Should the select boxes be part of an array when returned from PHP?
+ e.g. setting it to "birthday", would create "birthday[Day]",
+ "birthday[Month]" & "birthday[Year]". Can be combined with prefix */
+ $field_array = null;
+ /* <select size>'s of the different <select> tags.
+ If not set, uses default dropdown. */
+ $day_size = null;
+ $month_size = null;
+ $year_size = null;
+ /* Unparsed attributes common to *ALL* the <select>/<input> tags.
+ An example might be in the template: all_extra ='class ="foo"'. */
+ $all_extra = null;
+ /* Separate attributes for the tags. */
+ $day_extra = null;
+ $month_extra = null;
+ $year_extra = null;
+ /* Order in which to display the fields.
+ "D" -> day, "M" -> month, "Y" -> year. */
+ $field_order = 'MDY';
+ /* String printed between the different fields. */
+ $field_separator = "\n";
+ $time = time();
+ $all_empty = null;
+ $day_empty = null;
+ $month_empty = null;
+ $year_empty = null;
+ $extra_attrs = '';
+
+ foreach ($params as $_key=>$_value) {
+ switch ($_key) {
+ case 'prefix':
+ case 'time':
+ case 'start_year':
+ case 'end_year':
+ case 'month_format':
+ case 'day_format':
+ case 'day_value_format':
+ case 'field_array':
+ case 'day_size':
+ case 'month_size':
+ case 'year_size':
+ case 'all_extra':
+ case 'day_extra':
+ case 'month_extra':
+ case 'year_extra':
+ case 'field_order':
+ case 'field_separator':
+ case 'month_value_format':
+ case 'month_empty':
+ case 'day_empty':
+ case 'year_empty':
+ $$_key = (string)$_value;
+ break;
+
+ case 'all_empty':
+ $$_key = (string)$_value;
+ $day_empty = $month_empty = $year_empty = $all_empty;
+ break;
+
+ case 'display_days':
+ case 'display_months':
+ case 'display_years':
+ case 'year_as_text':
+ case 'reverse_years':
+ $$_key = (bool)$_value;
+ break;
+
+ default:
+ if(!is_array($_value)) {
+ $extra_attrs .= ' '.$_key.'="'.smarty_function_escape_special_chars($_value).'"';
+ } else {
+ $smarty->trigger_error("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+ }
+ break;
+ }
+ }
+
+ if (preg_match('!^-\d+$!', $time)) {
+ // negative timestamp, use date()
+ $time = date('Y-m-d', $time);
+ }
+ // If $time is not in format yyyy-mm-dd
+ if (preg_match('/^(\d{0,4}-\d{0,2}-\d{0,2})/', $time, $found)) {
+ $time = $found[1];
+ } else {
+ // use smarty_make_timestamp to get an unix timestamp and
+ // strftime to make yyyy-mm-dd
+ $time = strftime('%Y-%m-%d', smarty_make_timestamp($time));
+ }
+ // Now split this in pieces, which later can be used to set the select
+ $time = explode("-", $time);
+
+ // make syntax "+N" or "-N" work with start_year and end_year
+ if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) {
+ if ($match[1] == '+') {
+ $end_year = strftime('%Y') + $match[2];
+ } else {
+ $end_year = strftime('%Y') - $match[2];
+ }
+ }
+ if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) {
+ if ($match[1] == '+') {
+ $start_year = strftime('%Y') + $match[2];
+ } else {
+ $start_year = strftime('%Y') - $match[2];
+ }
+ }
+ if (strlen($time[0]) > 0) {
+ if ($start_year > $time[0] && !isset($params['start_year'])) {
+ // force start year to include given date if not explicitly set
+ $start_year = $time[0];
+ }
+ if($end_year < $time[0] && !isset($params['end_year'])) {
+ // force end year to include given date if not explicitly set
+ $end_year = $time[0];
+ }
+ }
+
+ $field_order = strtoupper($field_order);
+
+ $html_result = $month_result = $day_result = $year_result = "";
+
+ $field_separator_count = -1;
+ if ($display_months) {
+ $field_separator_count++;
+ $month_names = array();
+ $month_values = array();
+ if(isset($month_empty)) {
+ $month_names[''] = $month_empty;
+ $month_values[''] = '';
+ }
+ for ($i = 1; $i <= 12; $i++) {
+ $month_names[$i] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000));
+ $month_values[$i] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000));
+ }
+
+ $month_result .= '<select name=';
+ if (null !== $field_array){
+ $month_result .= '"' . $field_array . '[' . $prefix . 'Month]"';
+ } else {
+ $month_result .= '"' . $prefix . 'Month"';
+ }
+ if (null !== $month_size){
+ $month_result .= ' size="' . $month_size . '"';
+ }
+ if (null !== $month_extra){
+ $month_result .= ' ' . $month_extra;
+ }
+ if (null !== $all_extra){
+ $month_result .= ' ' . $all_extra;
+ }
+ $month_result .= $extra_attrs . '>'."\n";
+
+ $month_result .= smarty_function_html_options(array('output' => $month_names,
+ 'values' => $month_values,
+ 'selected' => (int)$time[1] ? strftime($month_value_format, mktime(0, 0, 0, (int)$time[1], 1, 2000)) : '',
+ 'print_result' => false),
+ $smarty);
+ $month_result .= '</select>';
+ }
+
+ if ($display_days) {
+ $field_separator_count++;
+ $days = array();
+ if (isset($day_empty)) {
+ $days[''] = $day_empty;
+ $day_values[''] = '';
+ }
+ for ($i = 1; $i <= 31; $i++) {
+ $days[] = sprintf($day_format, $i);
+ $day_values[] = sprintf($day_value_format, $i);
+ }
+
+ $day_result .= '<select name=';
+ if (null !== $field_array){
+ $day_result .= '"' . $field_array . '[' . $prefix . 'Day]"';
+ } else {
+ $day_result .= '"' . $prefix . 'Day"';
+ }
+ if (null !== $day_size){
+ $day_result .= ' size="' . $day_size . '"';
+ }
+ if (null !== $all_extra){
+ $day_result .= ' ' . $all_extra;
+ }
+ if (null !== $day_extra){
+ $day_result .= ' ' . $day_extra;
+ }
+ $day_result .= $extra_attrs . '>'."\n";
+ $day_result .= smarty_function_html_options(array('output' => $days,
+ 'values' => $day_values,
+ 'selected' => $time[2],
+ 'print_result' => false),
+ $smarty);
+ $day_result .= '</select>';
+ }
+
+ if ($display_years) {
+ $field_separator_count++;
+ if (null !== $field_array){
+ $year_name = $field_array . '[' . $prefix . 'Year]';
+ } else {
+ $year_name = $prefix . 'Year';
+ }
+ if ($year_as_text) {
+ $year_result .= '<input type="text" name="' . $year_name . '" value="' . $time[0] . '" size="4" maxlength="4"';
+ if (null !== $all_extra){
+ $year_result .= ' ' . $all_extra;
+ }
+ if (null !== $year_extra){
+ $year_result .= ' ' . $year_extra;
+ }
+ $year_result .= ' />';
+ } else {
+ $years = range((int)$start_year, (int)$end_year);
+ if ($reverse_years) {
+ rsort($years, SORT_NUMERIC);
+ } else {
+ sort($years, SORT_NUMERIC);
+ }
+ $yearvals = $years;
+ if(isset($year_empty)) {
+ array_unshift($years, $year_empty);
+ array_unshift($yearvals, '');
+ }
+ $year_result .= '<select name="' . $year_name . '"';
+ if (null !== $year_size){
+ $year_result .= ' size="' . $year_size . '"';
+ }
+ if (null !== $all_extra){
+ $year_result .= ' ' . $all_extra;
+ }
+ if (null !== $year_extra){
+ $year_result .= ' ' . $year_extra;
+ }
+ $year_result .= $extra_attrs . '>'."\n";
+ $year_result .= smarty_function_html_options(array('output' => $years,
+ 'values' => $yearvals,
+ 'selected' => $time[0],
+ 'print_result' => false),
+ $smarty);
+ $year_result .= '</select>';
+ }
+ }
+
+ // Loop thru the field_order field
+ for ($i = 0; $i <= 2; $i++){
+ $c = substr($field_order, $i, 1);
+ switch ($c){
+ case 'D':
+ $html_result .= $day_result;
+ break;
+
+ case 'M':
+ $html_result .= $month_result;
+ break;
+
+ case 'Y':
+ $html_result .= $year_result;
+ break;
+ }
+ // Add the field seperator
+ if($i < $field_separator_count) {
+ $html_result .= $field_separator;
+ }
+ }
+
+ return $html_result;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.html_select_time.php b/lib/smarty-2.6.8/plugins/function.html_select_time.php
new file mode 100644
index 0000000..2e5be7e
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.html_select_time.php
@@ -0,0 +1,194 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_select_time} function plugin
+ *
+ * Type: function<br>
+ * Name: html_select_time<br>
+ * Purpose: Prints the dropdowns for time selection
+ * @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time}
+ * (Smarty online manual)
+ * @author Roberto Berto <roberto@berto.net>
+ * @credits Monte Ohrt <monte AT ohrt DOT com>
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_make_timestamp()
+ */
+function smarty_function_html_select_time($params, &$smarty)
+{
+ require_once $smarty->_get_plugin_filepath('shared','make_timestamp');
+ require_once $smarty->_get_plugin_filepath('function','html_options');
+ /* Default values. */
+ $prefix = "Time_";
+ $time = time();
+ $display_hours = true;
+ $display_minutes = true;
+ $display_seconds = true;
+ $display_meridian = true;
+ $use_24_hours = true;
+ $minute_interval = 1;
+ $second_interval = 1;
+ /* Should the select boxes be part of an array when returned from PHP?
+ e.g. setting it to "birthday", would create "birthday[Hour]",
+ "birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]".
+ Can be combined with prefix. */
+ $field_array = null;
+ $all_extra = null;
+ $hour_extra = null;
+ $minute_extra = null;
+ $second_extra = null;
+ $meridian_extra = null;
+
+ foreach ($params as $_key=>$_value) {
+ switch ($_key) {
+ case 'prefix':
+ case 'time':
+ case 'field_array':
+ case 'all_extra':
+ case 'hour_extra':
+ case 'minute_extra':
+ case 'second_extra':
+ case 'meridian_extra':
+ $$_key = (string)$_value;
+ break;
+
+ case 'display_hours':
+ case 'display_minutes':
+ case 'display_seconds':
+ case 'display_meridian':
+ case 'use_24_hours':
+ $$_key = (bool)$_value;
+ break;
+
+ case 'minute_interval':
+ case 'second_interval':
+ $$_key = (int)$_value;
+ break;
+
+ default:
+ $smarty->trigger_error("[html_select_time] unknown parameter $_key", E_USER_WARNING);
+ }
+ }
+
+ $time = smarty_make_timestamp($time);
+
+ $html_result = '';
+
+ if ($display_hours) {
+ $hours = $use_24_hours ? range(0, 23) : range(1, 12);
+ $hour_fmt = $use_24_hours ? '%H' : '%I';
+ for ($i = 0, $for_max = count($hours); $i < $for_max; $i++)
+ $hours[$i] = sprintf('%02d', $hours[$i]);
+ $html_result .= '<select name=';
+ if (null !== $field_array) {
+ $html_result .= '"' . $field_array . '[' . $prefix . 'Hour]"';
+ } else {
+ $html_result .= '"' . $prefix . 'Hour"';
+ }
+ if (null !== $hour_extra){
+ $html_result .= ' ' . $hour_extra;
+ }
+ if (null !== $all_extra){
+ $html_result .= ' ' . $all_extra;
+ }
+ $html_result .= '>'."\n";
+ $html_result .= smarty_function_html_options(array('output' => $hours,
+ 'values' => $hours,
+ 'selected' => strftime($hour_fmt, $time),
+ 'print_result' => false),
+ $smarty);
+ $html_result .= "</select>\n";
+ }
+
+ if ($display_minutes) {
+ $all_minutes = range(0, 59);
+ for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i+= $minute_interval)
+ $minutes[] = sprintf('%02d', $all_minutes[$i]);
+ $selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval);
+ $html_result .= '<select name=';
+ if (null !== $field_array) {
+ $html_result .= '"' . $field_array . '[' . $prefix . 'Minute]"';
+ } else {
+ $html_result .= '"' . $prefix . 'Minute"';
+ }
+ if (null !== $minute_extra){
+ $html_result .= ' ' . $minute_extra;
+ }
+ if (null !== $all_extra){
+ $html_result .= ' ' . $all_extra;
+ }
+ $html_result .= '>'."\n";
+
+ $html_result .= smarty_function_html_options(array('output' => $minutes,
+ 'values' => $minutes,
+ 'selected' => $selected,
+ 'print_result' => false),
+ $smarty);
+ $html_result .= "</select>\n";
+ }
+
+ if ($display_seconds) {
+ $all_seconds = range(0, 59);
+ for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i+= $second_interval)
+ $seconds[] = sprintf('%02d', $all_seconds[$i]);
+ $selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval);
+ $html_result .= '<select name=';
+ if (null !== $field_array) {
+ $html_result .= '"' . $field_array . '[' . $prefix . 'Second]"';
+ } else {
+ $html_result .= '"' . $prefix . 'Second"';
+ }
+
+ if (null !== $second_extra){
+ $html_result .= ' ' . $second_extra;
+ }
+ if (null !== $all_extra){
+ $html_result .= ' ' . $all_extra;
+ }
+ $html_result .= '>'."\n";
+
+ $html_result .= smarty_function_html_options(array('output' => $seconds,
+ 'values' => $seconds,
+ 'selected' => $selected,
+ 'print_result' => false),
+ $smarty);
+ $html_result .= "</select>\n";
+ }
+
+ if ($display_meridian && !$use_24_hours) {
+ $html_result .= '<select name=';
+ if (null !== $field_array) {
+ $html_result .= '"' . $field_array . '[' . $prefix . 'Meridian]"';
+ } else {
+ $html_result .= '"' . $prefix . 'Meridian"';
+ }
+
+ if (null !== $meridian_extra){
+ $html_result .= ' ' . $meridian_extra;
+ }
+ if (null !== $all_extra){
+ $html_result .= ' ' . $all_extra;
+ }
+ $html_result .= '>'."\n";
+
+ $html_result .= smarty_function_html_options(array('output' => array('AM', 'PM'),
+ 'values' => array('am', 'pm'),
+ 'selected' => strtolower(strftime('%p', $time)),
+ 'print_result' => false),
+ $smarty);
+ $html_result .= "</select>\n";
+ }
+
+ return $html_result;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.html_table.php b/lib/smarty-2.6.8/plugins/function.html_table.php
new file mode 100644
index 0000000..32aeba8
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.html_table.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_table} function plugin
+ *
+ * Type: function<br>
+ * Name: html_table<br>
+ * Date: Feb 17, 2003<br>
+ * Purpose: make an html table from an array of data<br>
+ * Input:<br>
+ * - loop = array to loop through
+ * - cols = number of columns, comma separated list of column names
+ * or array of column names
+ * - rows = number of rows
+ * - table_attr = table attributes
+ * - th_attr = table heading attributes (arrays are cycled)
+ * - tr_attr = table row attributes (arrays are cycled)
+ * - td_attr = table cell attributes (arrays are cycled)
+ * - trailpad = value to pad trailing cells with
+ * - caption = text for caption element
+ * - vdir = vertical direction (default: "down", means top-to-bottom)
+ * - hdir = horizontal direction (default: "right", means left-to-right)
+ * - inner = inner loop (default "cols": print $loop line by line,
+ * $loop will be printed column by column otherwise)
+ *
+ *
+ * Examples:
+ * <pre>
+ * {table loop=$data}
+ * {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
+ * {table loop=$data cols="first,second,third" tr_attr=$colors}
+ * </pre>
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author credit to Messju Mohr <messju at lammfellpuschen dot de>
+ * @author credit to boots <boots dot smarty at yahoo dot com>
+ * @version 1.1
+ * @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table}
+ * (Smarty online manual)
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_html_table($params, &$smarty)
+{
+ $table_attr = 'border="1"';
+ $tr_attr = '';
+ $th_attr = '';
+ $td_attr = '';
+ $cols = $cols_count = 3;
+ $rows = 3;
+ $trailpad = '&nbsp;';
+ $vdir = 'down';
+ $hdir = 'right';
+ $inner = 'cols';
+ $caption = '';
+
+ if (!isset($params['loop'])) {
+ $smarty->trigger_error("html_table: missing 'loop' parameter");
+ return;
+ }
+
+ foreach ($params as $_key=>$_value) {
+ switch ($_key) {
+ case 'loop':
+ $$_key = (array)$_value;
+ break;
+
+ case 'cols':
+ if (is_array($_value) && !empty($_value)) {
+ $cols = $_value;
+ $cols_count = count($_value);
+ } elseif (!is_numeric($_value) && is_string($_value) && !empty($_value)) {
+ $cols = explode(',', $_value);
+ $cols_count = count($cols);
+ } elseif (!empty($_value)) {
+ $cols_count = (int)$_value;
+ } else {
+ $cols_count = $cols;
+ }
+ break;
+
+ case 'rows':
+ $$_key = (int)$_value;
+ break;
+
+ case 'table_attr':
+ case 'trailpad':
+ case 'hdir':
+ case 'vdir':
+ case 'inner':
+ case 'caption':
+ $$_key = (string)$_value;
+ break;
+
+ case 'tr_attr':
+ case 'td_attr':
+ case 'th_attr':
+ $$_key = $_value;
+ break;
+ }
+ }
+
+ $loop_count = count($loop);
+ if (empty($params['rows'])) {
+ /* no rows specified */
+ $rows = ceil($loop_count/$cols_count);
+ } elseif (empty($params['cols'])) {
+ if (!empty($params['rows'])) {
+ /* no cols specified, but rows */
+ $cols_count = ceil($loop_count/$rows);
+ }
+ }
+
+ $output = "<table $table_attr>\n";
+
+ if (!empty($caption)) {
+ $output .= '<caption>' . $caption . "</caption>\n";
+ }
+
+ if (is_array($cols)) {
+ $cols = ($hdir == 'right') ? $cols : array_reverse($cols);
+ $output .= "<thead><tr>\n";
+
+ for ($r=0; $r<$cols_count; $r++) {
+ $output .= '<th' . smarty_function_html_table_cycle('th', $th_attr, $r) . '>';
+ $output .= $cols[$r];
+ $output .= "</th>\n";
+ }
+ $output .= "</tr></thead>\n";
+ }
+
+ $output .= "<tbody>\n";
+ for ($r=0; $r<$rows; $r++) {
+ $output .= "<tr" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . ">\n";
+ $rx = ($vdir == 'down') ? $r*$cols_count : ($rows-1-$r)*$cols_count;
+
+ for ($c=0; $c<$cols_count; $c++) {
+ $x = ($hdir == 'right') ? $rx+$c : $rx+$cols_count-1-$c;
+ if ($inner!='cols') {
+ /* shuffle x to loop over rows*/
+ $x = floor($x/$cols_count) + ($x%$cols_count)*$rows;
+ }
+
+ if ($x<$loop_count) {
+ $output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">" . $loop[$x] . "</td>\n";
+ } else {
+ $output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">$trailpad</td>\n";
+ }
+ }
+ $output .= "</tr>\n";
+ }
+ $output .= "</tbody>\n";
+ $output .= "</table>\n";
+
+ return $output;
+}
+
+function smarty_function_html_table_cycle($name, $var, $no) {
+ if(!is_array($var)) {
+ $ret = $var;
+ } else {
+ $ret = $var[$no % count($var)];
+ }
+
+ return ($ret) ? ' '.$ret : '';
+}
+
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.mailto.php b/lib/smarty-2.6.8/plugins/function.mailto.php
new file mode 100644
index 0000000..20e9ed9
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.mailto.php
@@ -0,0 +1,165 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {mailto} function plugin
+ *
+ * Type: function<br>
+ * Name: mailto<br>
+ * Date: May 21, 2002
+ * Purpose: automate mailto address link creation, and optionally
+ * encode them.<br>
+ * Input:<br>
+ * - address = e-mail address
+ * - text = (optional) text to display, default is address
+ * - encode = (optional) can be one of:
+ * * none : no encoding (default)
+ * * javascript : encode with javascript
+ * * javascript_charcode : encode with javascript charcode
+ * * hex : encode with hexidecimal (no javascript)
+ * - cc = (optional) address(es) to carbon copy
+ * - bcc = (optional) address(es) to blind carbon copy
+ * - subject = (optional) e-mail subject
+ * - newsgroups = (optional) newsgroup(s) to post to
+ * - followupto = (optional) address(es) to follow up to
+ * - extra = (optional) extra tags for the href link
+ *
+ * Examples:
+ * <pre>
+ * {mailto address="me@domain.com"}
+ * {mailto address="me@domain.com" encode="javascript"}
+ * {mailto address="me@domain.com" encode="hex"}
+ * {mailto address="me@domain.com" subject="Hello to you!"}
+ * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
+ * {mailto address="me@domain.com" extra='class="mailto"'}
+ * </pre>
+ * @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto}
+ * (Smarty online manual)
+ * @version 1.2
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author credits to Jason Sweat (added cc, bcc and subject functionality)
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_mailto($params, &$smarty)
+{
+ $extra = '';
+
+ if (empty($params['address'])) {
+ $smarty->trigger_error("mailto: missing 'address' parameter");
+ return;
+ } else {
+ $address = $params['address'];
+ }
+
+ $text = $address;
+
+ // netscape and mozilla do not decode %40 (@) in BCC field (bug?)
+ // so, don't encode it.
+ $search = array('%40', '%2C');
+ $replace = array('@', ',');
+ $mail_parms = array();
+ foreach ($params as $var=>$value) {
+ switch ($var) {
+ case 'cc':
+ case 'bcc':
+ case 'followupto':
+ if (!empty($value))
+ $mail_parms[] = $var.'='.str_replace($search,$replace,rawurlencode($value));
+ break;
+
+ case 'subject':
+ case 'newsgroups':
+ $mail_parms[] = $var.'='.rawurlencode($value);
+ break;
+
+ case 'extra':
+ case 'text':
+ $$var = $value;
+
+ default:
+ }
+ }
+
+ $mail_parm_vals = '';
+ for ($i=0; $i<count($mail_parms); $i++) {
+ $mail_parm_vals .= (0==$i) ? '?' : '&';
+ $mail_parm_vals .= $mail_parms[$i];
+ }
+ $address .= $mail_parm_vals;
+
+ $encode = (empty($params['encode'])) ? 'none' : $params['encode'];
+ if (!in_array($encode,array('javascript','javascript_charcode','hex','none')) ) {
+ $smarty->trigger_error("mailto: 'encode' parameter must be none, javascript or hex");
+ return;
+ }
+
+ if ($encode == 'javascript' ) {
+ $string = 'document.write(\'<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>\');';
+
+ $js_encode = '';
+ for ($x=0; $x < strlen($string); $x++) {
+ $js_encode .= '%' . bin2hex($string[$x]);
+ }
+
+ return '<script type="text/javascript">eval(unescape(\''.$js_encode.'\'))</script>';
+
+ } elseif ($encode == 'javascript_charcode' ) {
+ $string = '<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>';
+
+ for($x = 0, $y = strlen($string); $x < $y; $x++ ) {
+ $ord[] = ord($string[$x]);
+ }
+
+ $_ret = "<script type=\"text/javascript\" language=\"javascript\">\n";
+ $_ret .= "<!--\n";
+ $_ret .= "{document.write(String.fromCharCode(";
+ $_ret .= implode(',',$ord);
+ $_ret .= "))";
+ $_ret .= "}\n";
+ $_ret .= "//-->\n";
+ $_ret .= "</script>\n";
+
+ return $_ret;
+
+
+ } elseif ($encode == 'hex') {
+
+ preg_match('!^(.*)(\?.*)$!',$address,$match);
+ if(!empty($match[2])) {
+ $smarty->trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript.");
+ return;
+ }
+ $address_encode = '';
+ for ($x=0; $x < strlen($address); $x++) {
+ if(preg_match('!\w!',$address[$x])) {
+ $address_encode .= '%' . bin2hex($address[$x]);
+ } else {
+ $address_encode .= $address[$x];
+ }
+ }
+ $text_encode = '';
+ for ($x=0; $x < strlen($text); $x++) {
+ $text_encode .= '&#x' . bin2hex($text[$x]).';';
+ }
+
+ $mailto = "&#109;&#97;&#105;&#108;&#116;&#111;&#58;";
+ return '<a href="'.$mailto.$address_encode.'" '.$extra.'>'.$text_encode.'</a>';
+
+ } else {
+ // no encoding
+ return '<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>';
+
+ }
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.math.php b/lib/smarty-2.6.8/plugins/function.math.php
new file mode 100644
index 0000000..71672fe
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.math.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {math} function plugin
+ *
+ * Type: function<br>
+ * Name: math<br>
+ * Purpose: handle math computations in template<br>
+ * @link http://smarty.php.net/manual/en/language.function.math.php {math}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_math($params, &$smarty)
+{
+ // be sure equation parameter is present
+ if (empty($params['equation'])) {
+ $smarty->trigger_error("math: missing equation parameter");
+ return;
+ }
+
+ $equation = $params['equation'];
+
+ // make sure parenthesis are balanced
+ if (substr_count($equation,"(") != substr_count($equation,")")) {
+ $smarty->trigger_error("math: unbalanced parenthesis");
+ return;
+ }
+
+ // match all vars in equation, make sure all are passed
+ preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]+)!",$equation, $match);
+ $allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10',
+ 'max','min','pi','pow','rand','round','sin','sqrt','srand','tan');
+
+ foreach($match[1] as $curr_var) {
+ if ($curr_var && !in_array($curr_var, array_keys($params)) && !in_array($curr_var, $allowed_funcs)) {
+ $smarty->trigger_error("math: function call $curr_var not allowed");
+ return;
+ }
+ }
+
+ foreach($params as $key => $val) {
+ if ($key != "equation" && $key != "format" && $key != "assign") {
+ // make sure value is not empty
+ if (strlen($val)==0) {
+ $smarty->trigger_error("math: parameter $key is empty");
+ return;
+ }
+ if (!is_numeric($val)) {
+ $smarty->trigger_error("math: parameter $key: is not numeric");
+ return;
+ }
+ $equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation);
+ }
+ }
+
+ eval("\$smarty_math_result = ".$equation.";");
+
+ if (empty($params['format'])) {
+ if (empty($params['assign'])) {
+ return $smarty_math_result;
+ } else {
+ $smarty->assign($params['assign'],$smarty_math_result);
+ }
+ } else {
+ if (empty($params['assign'])){
+ printf($params['format'],$smarty_math_result);
+ } else {
+ $smarty->assign($params['assign'],sprintf($params['format'],$smarty_math_result));
+ }
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.popup.php b/lib/smarty-2.6.8/plugins/function.popup.php
new file mode 100644
index 0000000..3a76b78
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.popup.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {popup} function plugin
+ *
+ * Type: function<br>
+ * Name: popup<br>
+ * Purpose: make text pop up in windows via overlib
+ * @link http://smarty.php.net/manual/en/language.function.popup.php {popup}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_popup($params, &$smarty)
+{
+ $append = '';
+ foreach ($params as $_key=>$_value) {
+ switch ($_key) {
+ case 'text':
+ case 'trigger':
+ case 'function':
+ case 'inarray':
+ $$_key = (string)$_value;
+ if ($_key == 'function' || $_key == 'inarray')
+ $append .= ',' . strtoupper($_key) . ",'$_value'";
+ break;
+
+ case 'caption':
+ case 'closetext':
+ case 'status':
+ $append .= ',' . strtoupper($_key) . ",'" . str_replace("'","\'",$_value) . "'";
+ break;
+
+ case 'fgcolor':
+ case 'bgcolor':
+ case 'textcolor':
+ case 'capcolor':
+ case 'closecolor':
+ case 'textfont':
+ case 'captionfont':
+ case 'closefont':
+ case 'fgbackground':
+ case 'bgbackground':
+ case 'caparray':
+ case 'capicon':
+ case 'background':
+ case 'frame':
+ $append .= ',' . strtoupper($_key) . ",'$_value'";
+ break;
+
+ case 'textsize':
+ case 'captionsize':
+ case 'closesize':
+ case 'width':
+ case 'height':
+ case 'border':
+ case 'offsetx':
+ case 'offsety':
+ case 'snapx':
+ case 'snapy':
+ case 'fixx':
+ case 'fixy':
+ case 'padx':
+ case 'pady':
+ case 'timeout':
+ case 'delay':
+ $append .= ',' . strtoupper($_key) . ",$_value";
+ break;
+
+ case 'sticky':
+ case 'left':
+ case 'right':
+ case 'center':
+ case 'above':
+ case 'below':
+ case 'noclose':
+ case 'autostatus':
+ case 'autostatuscap':
+ case 'fullhtml':
+ case 'hauto':
+ case 'vauto':
+ case 'mouseoff':
+ case 'followmouse':
+ case 'closeclick':
+ if ($_value) $append .= ',' . strtoupper($_key);
+ break;
+
+ default:
+ $smarty->trigger_error("[popup] unknown parameter $_key", E_USER_WARNING);
+ }
+ }
+
+ if (empty($text) && !isset($inarray) && empty($function)) {
+ $smarty->trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required");
+ return false;
+ }
+
+ if (empty($trigger)) { $trigger = "onmouseover"; }
+
+ $retval = $trigger . '="return overlib(\''.preg_replace(array("!'!","![\r\n]!"),array("\'",'\r'),$text).'\'';
+ $retval .= $append . ');"';
+ if ($trigger == 'onmouseover')
+ $retval .= ' onmouseout="nd();"';
+
+
+ return $retval;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/function.popup_init.php b/lib/smarty-2.6.8/plugins/function.popup_init.php
new file mode 100644
index 0000000..93cb454
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/function.popup_init.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {popup_init} function plugin
+ *
+ * Type: function<br>
+ * Name: popup_init<br>
+ * Purpose: initialize overlib
+ * @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init}
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_popup_init($params, &$smarty)
+{
+ $zindex = 1000;
+
+ if (!empty($params['zindex'])) {
+ $zindex = $params['zindex'];
+ }
+
+ if (!empty($params['src'])) {
+ return '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:'.$zindex.';"></div>' . "\n"
+ . '<script type="text/javascript" language="JavaScript" src="'.$params['src'].'"></script>' . "\n";
+ } else {
+ $smarty->trigger_error("popup_init: missing src parameter");
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.capitalize.php b/lib/smarty-2.6.8/plugins/modifier.capitalize.php
new file mode 100644
index 0000000..4a611d9
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.capitalize.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty capitalize modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: capitalize<br>
+ * Purpose: capitalize words in the string
+ * @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE
+ * capitalize (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return string
+ */
+function smarty_modifier_capitalize($string, $uc_digits = false)
+{
+ smarty_modifier_capitalize_ucfirst(null, $uc_digits);
+ return preg_replace_callback('!\'?\b\w(\w|\')*\b!', 'smarty_modifier_capitalize_ucfirst', $string);
+}
+
+function smarty_modifier_capitalize_ucfirst($string, $uc_digits = null)
+{
+ static $_uc_digits = false;
+
+ if(isset($uc_digits)) {
+ $_uc_digits = $uc_digits;
+ return;
+ }
+
+ if(substr($string[0],0,1) != "'" && !preg_match("!\d!",$string[0]) || $_uc_digits)
+ return ucfirst($string[0]);
+ else
+ return $string[0];
+}
+
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.cat.php b/lib/smarty-2.6.8/plugins/modifier.cat.php
new file mode 100644
index 0000000..2e37940
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.cat.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty cat modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: cat<br>
+ * Date: Feb 24, 2003
+ * Purpose: catenate a value to a variable
+ * Input: string to catenate
+ * Example: {$var|cat:"foo"}
+ * @link http://smarty.php.net/manual/en/language.modifier.cat.php cat
+ * (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @version 1.0
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_cat($string, $cat)
+{
+ return $string . $cat;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.count_characters.php b/lib/smarty-2.6.8/plugins/modifier.count_characters.php
new file mode 100644
index 0000000..5ed9a87
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.count_characters.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty count_characters modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: count_characteres<br>
+ * Purpose: count the number of characters in a text
+ * @link http://smarty.php.net/manual/en/language.modifier.count.characters.php
+ * count_characters (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param boolean include whitespace in the character count
+ * @return integer
+ */
+function smarty_modifier_count_characters($string, $include_spaces = false)
+{
+ if ($include_spaces)
+ return(strlen($string));
+
+ return preg_match_all("/[^\s]/",$string, $match);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.count_paragraphs.php b/lib/smarty-2.6.8/plugins/modifier.count_paragraphs.php
new file mode 100644
index 0000000..e0e274d
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.count_paragraphs.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty count_paragraphs modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: count_paragraphs<br>
+ * Purpose: count the number of paragraphs in a text
+ * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php
+ * count_paragraphs (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return integer
+ */
+function smarty_modifier_count_paragraphs($string)
+{
+ // count \r or \n characters
+ return count(preg_split('/[\r\n]+/', $string));
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.count_sentences.php b/lib/smarty-2.6.8/plugins/modifier.count_sentences.php
new file mode 100644
index 0000000..f66ea17
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.count_sentences.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty count_sentences modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: count_sentences
+ * Purpose: count the number of sentences in a text
+ * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php
+ * count_sentences (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return integer
+ */
+function smarty_modifier_count_sentences($string)
+{
+ // find periods with a word before but not after.
+ return preg_match_all('/[^\s]\.(?!\w)/', $string, $match);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.count_words.php b/lib/smarty-2.6.8/plugins/modifier.count_words.php
new file mode 100644
index 0000000..9d339f5
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.count_words.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty count_words modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: count_words<br>
+ * Purpose: count the number of words in a text
+ * @link http://smarty.php.net/manual/en/language.modifier.count.words.php
+ * count_words (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return integer
+ */
+function smarty_modifier_count_words($string)
+{
+ // split text by ' ',\r,\n,\f,\t
+ $split_array = preg_split('/\s+/',$string);
+ // count matches that contain alphanumerics
+ $word_count = preg_grep('/[a-zA-Z0-9\\x80-\\xff]/', $split_array);
+
+ return count($word_count);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.date_format.php b/lib/smarty-2.6.8/plugins/modifier.date_format.php
new file mode 100644
index 0000000..8cf7d5e
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.date_format.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Include the {@link shared.make_timestamp.php} plugin
+ */
+require_once $smarty->_get_plugin_filepath('shared', 'make_timestamp');
+/**
+ * Smarty date_format modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: date_format<br>
+ * Purpose: format datestamps via strftime<br>
+ * Input:<br>
+ * - string: input date string
+ * - format: strftime format for output
+ * - default_date: default date if $string is empty
+ * @link http://smarty.php.net/manual/en/language.modifier.date.format.php
+ * date_format (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param string
+ * @param string
+ * @return string|void
+ * @uses smarty_make_timestamp()
+ */
+function smarty_modifier_date_format($string, $format = '%b %e, %Y', $default_date = '')
+{
+ if ($string != '') {
+ $timestamp = smarty_make_timestamp($string);
+ } elseif ($default_date != '') {
+ $timestamp = smarty_make_timestamp($default_date);
+ } else {
+ return;
+ }
+ if (DIRECTORY_SEPARATOR == '\\') {
+ $_win_from = array('%D', '%h', '%n', '%r', '%R', '%t', '%T');
+ $_win_to = array('%m/%d/%y', '%b', "\n", '%I:%M:%S %p', '%H:%M', "\t", '%H:%M:%S');
+ if (strpos($format, '%e') !== false) {
+ $_win_from[] = '%e';
+ $_win_to[] = sprintf('%\' 2d', date('j', $timestamp));
+ }
+ if (strpos($format, '%l') !== false) {
+ $_win_from[] = '%l';
+ $_win_to[] = sprintf('%\' 2d', date('h', $timestamp));
+ }
+ $format = str_replace($_win_from, $_win_to, $format);
+ }
+ return strftime($format, $timestamp);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.debug_print_var.php b/lib/smarty-2.6.8/plugins/modifier.debug_print_var.php
new file mode 100644
index 0000000..e4f7bc0
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.debug_print_var.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty debug_print_var modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: debug_print_var<br>
+ * Purpose: formats variable contents for display in the console
+ * @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php
+ * debug_print_var (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param array|object
+ * @param integer
+ * @param integer
+ * @return string
+ */
+function smarty_modifier_debug_print_var($var, $depth = 0, $length = 40)
+{
+ $_replace = array(
+ "\n" => '<i>\n</i>',
+ "\r" => '<i>\r</i>',
+ "\t" => '<i>\t</i>'
+ );
+
+ switch (gettype($var)) {
+ case 'array' :
+ $results = '<b>Array (' . count($var) . ')</b>';
+ foreach ($var as $curr_key => $curr_val) {
+ $results .= '<br>' . str_repeat('&nbsp;', $depth * 2)
+ . '<b>' . strtr($curr_key, $_replace) . '</b> =&gt; '
+ . smarty_modifier_debug_print_var($curr_val, ++$depth, $length);
+ $depth--;
+ }
+ break;
+ case 'object' :
+ $object_vars = get_object_vars($var);
+ $results = '<b>' . get_class($var) . ' Object (' . count($object_vars) . ')</b>';
+ foreach ($object_vars as $curr_key => $curr_val) {
+ $results .= '<br>' . str_repeat('&nbsp;', $depth * 2)
+ . '<b> -&gt;' . strtr($curr_key, $_replace) . '</b> = '
+ . smarty_modifier_debug_print_var($curr_val, ++$depth, $length);
+ $depth--;
+ }
+ break;
+ case 'boolean' :
+ case 'NULL' :
+ case 'resource' :
+ if (true === $var) {
+ $results = 'true';
+ } elseif (false === $var) {
+ $results = 'false';
+ } elseif (null === $var) {
+ $results = 'null';
+ } else {
+ $results = htmlspecialchars((string) $var);
+ }
+ $results = '<i>' . $results . '</i>';
+ break;
+ case 'integer' :
+ case 'float' :
+ $results = htmlspecialchars((string) $var);
+ break;
+ case 'string' :
+ $results = strtr($var, $_replace);
+ if (strlen($var) > $length ) {
+ $results = substr($var, 0, $length - 3) . '...';
+ }
+ $results = htmlspecialchars('"' . $results . '"');
+ break;
+ case 'unknown type' :
+ default :
+ $results = strtr((string) $var, $_replace);
+ if (strlen($results) > $length ) {
+ $results = substr($results, 0, $length - 3) . '...';
+ }
+ $results = htmlspecialchars($results);
+ }
+
+ return $results;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.default.php b/lib/smarty-2.6.8/plugins/modifier.default.php
new file mode 100644
index 0000000..70011fd
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.default.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty default modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: default<br>
+ * Purpose: designate default value for empty variables
+ * @link http://smarty.php.net/manual/en/language.modifier.default.php
+ * default (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_default($string, $default = '')
+{
+ if (!isset($string) || $string === '')
+ return $default;
+ else
+ return $string;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.escape.php b/lib/smarty-2.6.8/plugins/modifier.escape.php
new file mode 100644
index 0000000..a2f52b2
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.escape.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty escape modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: escape<br>
+ * Purpose: Escape the string according to escapement type
+ * @link http://smarty.php.net/manual/en/language.modifier.escape.php
+ * escape (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param html|htmlall|url|quotes|hex|hexentity|javascript
+ * @return string
+ */
+function smarty_modifier_escape($string, $esc_type = 'html', $char_set = 'ISO-8859-1')
+{
+ switch ($esc_type) {
+ case 'html':
+ return htmlspecialchars($string, ENT_QUOTES, $char_set);
+
+ case 'htmlall':
+ return htmlentities($string, ENT_QUOTES, $char_set);
+
+ case 'url':
+ return rawurlencode($string);
+
+ case 'urlpathinfo':
+ return str_replace('%2F','/',rawurlencode($string));
+
+ case 'quotes':
+ // escape unescaped single quotes
+ return preg_replace("%(?<!\\\\)'%", "\\'", $string);
+
+ case 'hex':
+ // escape every character into hex
+ $return = '';
+ for ($x=0; $x < strlen($string); $x++) {
+ $return .= '%' . bin2hex($string[$x]);
+ }
+ return $return;
+
+ case 'hexentity':
+ $return = '';
+ for ($x=0; $x < strlen($string); $x++) {
+ $return .= '&#x' . bin2hex($string[$x]) . ';';
+ }
+ return $return;
+
+ case 'decentity':
+ $return = '';
+ for ($x=0; $x < strlen($string); $x++) {
+ $return .= '&#' . ord($string[$x]) . ';';
+ }
+ return $return;
+
+ case 'javascript':
+ // escape quotes and backslashes, newlines, etc.
+ return strtr($string, array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n','</'=>'<\/'));
+
+ case 'mail':
+ // safe way to display e-mail address on a web page
+ return str_replace(array('@', '.'),array(' [AT] ', ' [DOT] '), $string);
+
+ case 'nonstd':
+ // escape non-standard chars, such as ms document quotes
+ $_res = '';
+ for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) {
+ $_ord = ord(substr($string, $_i, 1));
+ // non-standard char, escape it
+ if($_ord >= 126){
+ $_res .= '&#' . $_ord . ';';
+ }
+ else {
+ $_res .= substr($string, $_i, 1);
+ }
+ }
+ return $_res;
+
+ default:
+ return $string;
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.indent.php b/lib/smarty-2.6.8/plugins/modifier.indent.php
new file mode 100644
index 0000000..394147a
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.indent.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty indent modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: indent<br>
+ * Purpose: indent lines of text
+ * @link http://smarty.php.net/manual/en/language.modifier.indent.php
+ * indent (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param integer
+ * @param string
+ * @return string
+ */
+function smarty_modifier_indent($string,$chars=4,$char=" ")
+{
+ return preg_replace('!^!m',str_repeat($char,$chars),$string);
+}
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.lower.php b/lib/smarty-2.6.8/plugins/modifier.lower.php
new file mode 100644
index 0000000..20e7a8d
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.lower.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty lower modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: lower<br>
+ * Purpose: convert string to lowercase
+ * @link http://smarty.php.net/manual/en/language.modifier.lower.php
+ * lower (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return string
+ */
+function smarty_modifier_lower($string)
+{
+ return strtolower($string);
+}
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.nl2br.php b/lib/smarty-2.6.8/plugins/modifier.nl2br.php
new file mode 100644
index 0000000..d6fabff
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.nl2br.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty plugin
+ *
+ * Type: modifier<br>
+ * Name: nl2br<br>
+ * Date: Feb 26, 2003
+ * Purpose: convert \r\n, \r or \n to <<br>>
+ * Input:<br>
+ * - contents = contents to replace
+ * - preceed_test = if true, includes preceeding break tags
+ * in replacement
+ * Example: {$text|nl2br}
+ * @link http://smarty.php.net/manual/en/language.modifier.nl2br.php
+ * nl2br (Smarty online manual)
+ * @version 1.0
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return string
+ */
+function smarty_modifier_nl2br($string)
+{
+ return nl2br($string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.regex_replace.php b/lib/smarty-2.6.8/plugins/modifier.regex_replace.php
new file mode 100644
index 0000000..d4d2030
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.regex_replace.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty regex_replace modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: regex_replace<br>
+ * Purpose: regular expression search/replace
+ * @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php
+ * regex_replace (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param string|array
+ * @param string|array
+ * @return string
+ */
+function smarty_modifier_regex_replace($string, $search, $replace)
+{
+ if (preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && (strpos($match[1], 'e') !== false)) {
+ /* remove eval-modifier from $search */
+ $search = substr($search, 0, -strlen($match[1])) . preg_replace('![e\s]+!', '', $match[1]);
+ }
+
+ return preg_replace($search, $replace, $string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.replace.php b/lib/smarty-2.6.8/plugins/modifier.replace.php
new file mode 100644
index 0000000..df041c8
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.replace.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty replace modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: replace<br>
+ * Purpose: simple search/replace
+ * @link http://smarty.php.net/manual/en/language.modifier.replace.php
+ * replace (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_replace($string, $search, $replace)
+{
+ return str_replace($search, $replace, $string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.spacify.php b/lib/smarty-2.6.8/plugins/modifier.spacify.php
new file mode 100644
index 0000000..c2423f4
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.spacify.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty spacify modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: spacify<br>
+ * Purpose: add spaces between characters in a string
+ * @link http://smarty.php.net/manual/en/language.modifier.spacify.php
+ * spacify (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_spacify($string, $spacify_char = ' ')
+{
+ return implode($spacify_char,
+ preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY));
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.string_format.php b/lib/smarty-2.6.8/plugins/modifier.string_format.php
new file mode 100644
index 0000000..9e051a5
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.string_format.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty string_format modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: string_format<br>
+ * Purpose: format strings via sprintf
+ * @link http://smarty.php.net/manual/en/language.modifier.string.format.php
+ * string_format (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_string_format($string, $format)
+{
+ return sprintf($format, $string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.strip.php b/lib/smarty-2.6.8/plugins/modifier.strip.php
new file mode 100644
index 0000000..cc5c453
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.strip.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty strip modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: strip<br>
+ * Purpose: Replace all repeated spaces, newlines, tabs
+ * with a single space or supplied replacement string.<br>
+ * Example: {$var|strip} {$var|strip:"&nbsp;"}
+ * Date: September 25th, 2002
+ * @link http://smarty.php.net/manual/en/language.modifier.strip.php
+ * strip (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @version 1.0
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_strip($text, $replace = ' ')
+{
+ return preg_replace('!\s+!', $replace, $text);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.strip_tags.php b/lib/smarty-2.6.8/plugins/modifier.strip_tags.php
new file mode 100644
index 0000000..93011a8
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.strip_tags.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty strip_tags modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: strip_tags<br>
+ * Purpose: strip html tags from text
+ * @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php
+ * strip_tags (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param boolean
+ * @return string
+ */
+function smarty_modifier_strip_tags($string, $replace_with_space = true)
+{
+ if ($replace_with_space)
+ return preg_replace('!<[^>]*?>!', ' ', $string);
+ else
+ return strip_tags($string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.truncate.php b/lib/smarty-2.6.8/plugins/modifier.truncate.php
new file mode 100644
index 0000000..35c8969
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.truncate.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty truncate modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: truncate<br>
+ * Purpose: Truncate a string to a certain length if necessary,
+ * optionally splitting in the middle of a word, and
+ * appending the $etc string or inserting $etc into the middle.
+ * @link http://smarty.php.net/manual/en/language.modifier.truncate.php
+ * truncate (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param integer
+ * @param string
+ * @param boolean
+ * @param boolean
+ * @return string
+ */
+function smarty_modifier_truncate($string, $length = 80, $etc = '...',
+ $break_words = false, $middle = false)
+{
+ if ($length == 0)
+ return '';
+
+ if (strlen($string) > $length) {
+ $length -= min($length, strlen($etc));
+ if (!$break_words && !$middle) {
+ $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1));
+ }
+ if(!$middle) {
+ return substr($string, 0, $length) . $etc;
+ } else {
+ return substr($string, 0, $length/2) . $etc . substr($string, -$length/2);
+ }
+ } else {
+ return $string;
+ }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.upper.php b/lib/smarty-2.6.8/plugins/modifier.upper.php
new file mode 100644
index 0000000..c12480f
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.upper.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty upper modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: upper<br>
+ * Purpose: convert string to uppercase
+ * @link http://smarty.php.net/manual/en/language.modifier.upper.php
+ * upper (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return string
+ */
+function smarty_modifier_upper($string)
+{
+ return strtoupper($string);
+}
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/modifier.wordwrap.php b/lib/smarty-2.6.8/plugins/modifier.wordwrap.php
new file mode 100644
index 0000000..ce07181
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/modifier.wordwrap.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty wordwrap modifier plugin
+ *
+ * Type: modifier<br>
+ * Name: wordwrap<br>
+ * Purpose: wrap a string of text at a given length
+ * @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php
+ * wordwrap (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @param integer
+ * @param string
+ * @param boolean
+ * @return string
+ */
+function smarty_modifier_wordwrap($string,$length=80,$break="\n",$cut=false)
+{
+ return wordwrap($string,$length,$break,$cut);
+}
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/outputfilter.trimwhitespace.php b/lib/smarty-2.6.8/plugins/outputfilter.trimwhitespace.php
new file mode 100644
index 0000000..97b0d21
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/outputfilter.trimwhitespace.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty trimwhitespace outputfilter plugin
+ *
+ * File: outputfilter.trimwhitespace.php<br>
+ * Type: outputfilter<br>
+ * Name: trimwhitespace<br>
+ * Date: Jan 25, 2003<br>
+ * Purpose: trim leading white space and blank lines from
+ * template source after it gets interpreted, cleaning
+ * up code and saving bandwidth. Does not affect
+ * <<PRE>></PRE> and <SCRIPT></SCRIPT> blocks.<br>
+ * Install: Drop into the plugin directory, call
+ * <code>$smarty->load_filter('output','trimwhitespace');</code>
+ * from application.
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author Contributions from Lars Noschinski <lars@usenet.noschinski.de>
+ * @version 1.3
+ * @param string
+ * @param Smarty
+ */
+function smarty_outputfilter_trimwhitespace($source, &$smarty)
+{
+ // Pull out the script blocks
+ preg_match_all("!<script[^>]+>.*?</script>!is", $source, $match);
+ $_script_blocks = $match[0];
+ $source = preg_replace("!<script[^>]+>.*?</script>!is",
+ '@@@SMARTY:TRIM:SCRIPT@@@', $source);
+
+ // Pull out the pre blocks
+ preg_match_all("!<pre>.*?</pre>!is", $source, $match);
+ $_pre_blocks = $match[0];
+ $source = preg_replace("!<pre>.*?</pre>!is",
+ '@@@SMARTY:TRIM:PRE@@@', $source);
+
+ // Pull out the textarea blocks
+ preg_match_all("!<textarea[^>]+>.*?</textarea>!is", $source, $match);
+ $_textarea_blocks = $match[0];
+ $source = preg_replace("!<textarea[^>]+>.*?</textarea>!is",
+ '@@@SMARTY:TRIM:TEXTAREA@@@', $source);
+
+ // remove all leading spaces, tabs and carriage returns NOT
+ // preceeded by a php close tag.
+ $source = trim(preg_replace('/((?<!\?>)\n)[\s]+/m', '\1', $source));
+
+ // replace textarea blocks
+ smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source);
+
+ // replace pre blocks
+ smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source);
+
+ // replace script blocks
+ smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source);
+
+ return $source;
+}
+
+function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) {
+ $_len = strlen($search_str);
+ $_pos = 0;
+ for ($_i=0, $_count=count($replace); $_i<$_count; $_i++)
+ if (($_pos=strpos($subject, $search_str, $_pos))!==false)
+ $subject = substr_replace($subject, $replace[$_i], $_pos, $_len);
+ else
+ break;
+
+}
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/shared.escape_special_chars.php b/lib/smarty-2.6.8/plugins/shared.escape_special_chars.php
new file mode 100644
index 0000000..c07ce31
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/shared.escape_special_chars.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Smarty shared plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * escape_special_chars common function
+ *
+ * Function: smarty_function_escape_special_chars<br>
+ * Purpose: used by other smarty functions to escape
+ * special chars except for already escaped ones
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return string
+ */
+function smarty_function_escape_special_chars($string)
+{
+ if(!is_array($string)) {
+ $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
+ $string = htmlspecialchars($string);
+ $string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string);
+ }
+ return $string;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/lib/smarty-2.6.8/plugins/shared.make_timestamp.php b/lib/smarty-2.6.8/plugins/shared.make_timestamp.php
new file mode 100644
index 0000000..b42eb11
--- /dev/null
+++ b/lib/smarty-2.6.8/plugins/shared.make_timestamp.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Smarty shared plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Function: smarty_make_timestamp<br>
+ * Purpose: used by other smarty functions to make a timestamp
+ * from a string.
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return string
+ */
+function smarty_make_timestamp($string)
+{
+ if(empty($string)) {
+ // use "now":
+ $time = time();
+
+ } elseif (preg_match('/^\d{14}$/', $string)) {
+ // it is mysql timestamp format of YYYYMMDDHHMMSS?
+ $time = mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2),
+ substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4));
+
+ } elseif (is_numeric($string)) {
+ // it is a numeric string, we handle it as timestamp
+ $time = (int)$string;
+
+ } else {
+ // strtotime should handle it
+ $time = strtotime($string);
+ if ($time == -1 || $time === false) {
+ // strtotime() was not able to parse $string, use "now":
+ $time = time();
+ }
+ }
+ return $time;
+
+}
+
+/* vim: set expandtab: */
+
+?>