diff --git a/doc/rpm-build/post_install.php b/doc/rpm-build/post_install.php index f82e155f5c..d335f602c3 100755 --- a/doc/rpm-build/post_install.php +++ b/doc/rpm-build/post_install.php @@ -24,7 +24,7 @@ $config = array( 'domain' => 'default', 'config_user' => 'admin', 'config_passwd' => randomstring(), - 'db_type' => 'mysql', + 'db_type' => 'mysqli', 'db_host' => 'localhost', 'db_port' => 3306, 'db_name' => 'egroupware', diff --git a/phpgwapi/inc/adodb/drivers/adodb-mysqli.inc.php b/phpgwapi/inc/adodb/drivers/adodb-mysqli.inc.php new file mode 100644 index 0000000000..de4e001b1c --- /dev/null +++ b/phpgwapi/inc/adodb/drivers/adodb-mysqli.inc.php @@ -0,0 +1,972 @@ +_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" + */ + foreach($this->optionFlags as $arr) { + mysqli_options($this->_connectionID,$arr[0],$arr[1]); + } + + if (strstr($argHostname,':')) list($argHostname,$this->port) = explode(':',$argHostname); + $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); + } + + /** + * Check if we are connected + * + * Reimplemented as check in ADOConnection::IsConnected will allways return true, as _connectionID is mysqli object! + * + * @see ADOConnection::IsConnected() + * @return boolean + */ + function IsConnected() + { + return $this->_connectionID && @mysqli_ping($this->_connectionID); + } + + function IfNull( $field, $ifNull ) + { + return " IFNULL($field, $ifNull) "; // if MySQL + } + + 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'); + $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; + } + + // 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 && $this->_connectionID) + 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; + return "from_unixtime(unix_timestamp($date)+($dayFraction)*24*3600)"; + } + + 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" + function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $asociative = FALSE ) + { + if ( !empty($owner) ) { + $table = "$owner.$table"; + } + $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); + $create_sql = $a_create_table[1]; + + $matches = array(); + $foreign_keys = array(); + if ( preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches) ) { + $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 ( $asociative ) { + $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->databaseName = $dbName; + if ($this->_connectionID) { + $result = @mysqli_select_db($this->_connectionID, $dbName); + if (!$result && $this->debug) { + 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; + } + + /** + * @var array $charset2mysql translate www charsets to mysql ones + */ + var $charset2mysql = array( + 'utf-8' => 'utf8', + 'iso-8859-1' => 'latin1', + 'iso-8859-2' => 'latin2', + 'windows-1251' => 'cp1251', + 'koi8-r' => 'koi8r', // 4.0: koi8_ru + 'euc-kr' => 'euckr', // 4.0: euc_kr + 'euc-jp' => 'ujis', // 4.0: - + 'iso-8859-7' => 'greek', // 4.0: - + ); + + /** + * gets the client encoding from the connection + * + * mysqli_client_encoding only returns the default charset, not the one currently used! + * + * @return string/boolean charset or false + */ + function GetCharSet() + { + $this->charSet = $this->GetOne('SELECT @@character_set_connection'); + if ($this->charSet) { + $mysql2charset = array_flip($this->charset2mysql); + if (isset($mysql2charset[$this->charSet])) { + $this->charSet = $mysql2charset[$this->charSet]; + } + } + return $this->charSet ? $this->charSet : false; + } + + /** + * sets the client encoding from the connection + * + * mysqli_set_charset is php5.1+, the query used here works since mysql4.1 + * + * mysqli_set_charset is strongly prefered, as mysqli_real_escape only uses charset set this way! + * + * @param string $charset_name + * @return boolean true on success, false otherwise + */ + function SetCharSet($charset_name) + { + $mysql_charset = isset($this->charset2mysql[$charset_name]) ? $this->charset2mysql[$charset_name] : $charset_name; + if (function_exists('mysqli_set_charset')) { + if (!mysqli_set_charset($this->_connectionID,$mysql_charset)) return false; + } + elseif (!mysqli_query($this->_connectionID,'SET NAMES '.$this->qstr($mysql_charset))) return false; + if ($this->GetCharSet()) { + return $this->charSet == $charset_name || $this->charset2mysql[$this->charSet] == $charset_name; + } + return false; + } +} + +/*-------------------------------------------------------------------------------------- + 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); + } + + function &FetchField($fieldOffset = -1) + { + $fieldnr = $fieldOffset; + if ($fieldOffset != -1) { + $fieldOffset = mysqli_field_seek($this->_queryID, $fieldnr); + } + $o = mysqli_fetch_field($this->_queryID); + 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 "

--- Error in type matching $t -----

"; + return 'N'; + } + } // function + + +} // rs class + +} + +?> \ No newline at end of file diff --git a/phpgwapi/inc/class.egw_db.inc.php b/phpgwapi/inc/class.egw_db.inc.php index d2b1d37f24..4c3efe22ef 100644 --- a/phpgwapi/inc/class.egw_db.inc.php +++ b/phpgwapi/inc/class.egw_db.inc.php @@ -418,14 +418,10 @@ class egw_db return null; // in case error-reporting = 'no' } $connect = $GLOBALS['egw_info']['server']['db_persistent'] ? 'PConnect' : 'Connect'; - if (($Ok = $this->Link_ID->$connect($Host, $User, $Password))) + if (($Ok = $this->Link_ID->$connect($Host, $User, $Password, $Database))) { $this->ServerInfo = $this->Link_ID->ServerInfo(); $this->set_capabilities($type,$this->ServerInfo['version']); - if($Database) - { - $Ok = $this->Link_ID->SelectDB($Database); - } } if (!$Ok) { @@ -456,8 +452,7 @@ class egw_db $this->Link_ID =& $GLOBALS['egw']->ADOdb; } } - // next ADOdb version: if (!$this->Link_ID->isConnected()) $this->Link_ID->Connect(); - if (!$this->Link_ID->_connectionID) $this->Link_ID->Connect(); + if (!$this->Link_ID->isConnected()) $this->Link_ID->Connect(); if ($new_connection) { diff --git a/setup/inc/class.setup_cmd_database.inc.php b/setup/inc/class.setup_cmd_database.inc.php index f750e7f182..1caec0bd67 100644 --- a/setup/inc/class.setup_cmd_database.inc.php +++ b/setup/inc/class.setup_cmd_database.inc.php @@ -19,10 +19,10 @@ class setup_cmd_database extends setup_cmd * Allow to run this command via setup-cli */ const SETUP_CLI_CALLABLE = true; - + /** * Maximum length of database name (at least for MySQL this is the limit) - * + * * @var int */ const MAX_DB_NAME_LEN = 16; @@ -68,7 +68,7 @@ class setup_cmd_database extends setup_cmd 'db_root_pw' => $db_root_pw, 'sub_command' => $sub_command, 'db_grant_host' => $db_grant_host, - 'make_db_name_unique' => $make_db_name_unique, + 'make_db_name_unique' => $make_db_name_unique, ); } //error_log(__METHOD__.'('.array2string($domain).") make_db_name_unique=".array2string($domain['make_db_name_unique'])); @@ -163,7 +163,7 @@ class setup_cmd_database extends setup_cmd * Check and if does not yet exist create the new database and user * * The check will fail if the database exists, but already contains tables - * + * * if $this->make_db_name_unique is set, a decrementing nummeric prefix gets * added to $this->db_name AND $this->db_user, if db already exists. * @@ -177,7 +177,7 @@ class setup_cmd_database extends setup_cmd // shorten db-name/-user to self::MAX_DB_NAME_LEN chars if ($this->make_db_name_unique && strlen($this->db_name) > self::MAX_DB_NAME_LEN) { - $this->set_defaults['db_name'] = $this->db_name = + $this->set_defaults['db_name'] = $this->db_name = $this->set_defaults['db_user'] = $this->db_user = // change user too (otherwise existing user/db could not connect any more!) substr($this->db_name,0,self::MAX_DB_NAME_LEN); } @@ -193,7 +193,7 @@ class setup_cmd_database extends setup_cmd catch(egw_exception_db $e) { // catches failed to create database // try connect as root to check if wrong root/root_pw is the problem $this->connect($this->db_root,$this->db_root_pw,$this->db_meta); - + // if we should create a db with a unique name (try it only N times, not endless!) if ($this->make_db_name_unique && $try_make_unique++ < 20) { @@ -209,10 +209,10 @@ class setup_cmd_database extends setup_cmd { $num = '2'; } - $this->set_defaults['db_name'] = $this->db_name = + $this->set_defaults['db_name'] = $this->db_name = $this->set_defaults['db_user'] = $this->db_user = // change user too (otherwise existing user/db could not connect any more!) substr($this->db_name,0,self::MAX_DB_NAME_LEN-strlen($num)).$num; - + return $this->create(); } catch (egw_exception_wrong_userinput $e2) @@ -270,7 +270,7 @@ class setup_cmd_database extends setup_cmd * @param string $db_type='mysql' * @return array */ - static function defaults($db_type='mysql') + static function defaults($db_type='mysqli') { switch($db_type) { @@ -312,7 +312,7 @@ class setup_cmd_database extends setup_cmd if (strpos($this->$name,'$domain') !== false) { // limit names to 16 chars (16 char is user-name limit in MySQL) - $this->set_defaults[$name] = $this->$name = + $this->set_defaults[$name] = $this->$name = substr(str_replace(array('$domain','.','-'),array($this->domain,'_','_'),$this->$name), 0,self::MAX_DB_NAME_LEN); } diff --git a/setup/inc/class.setup_header.inc.php b/setup/inc/class.setup_header.inc.php new file mode 100644 index 0000000000..7394f54ce1 --- /dev/null +++ b/setup/inc/class.setup_header.inc.php @@ -0,0 +1,274 @@ + + * @author Miles Lott + * @author Tony Puglisi (Angles) + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id$ + */ + +/** + * Functions to manage the eGW config file header.inc.php + * + * Used by manageheader.php and the new setup command line interface setup-cli.php + * + * @package setup + * @author Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + */ +class setup_header +{ + /** + * @var array with php-extension / ADOdb drive names => describtiv label + */ + var $db_fullnames = array( + 'mysqli' => 'MySQLi (recommended, incl. transactions)', + 'mysql' => 'MySQL (deprecated)', + 'mysqlt' => 'MySQL (deprecated, transactions)', + 'pgsql' => 'PostgreSQL', + 'mssql' => 'MS SQL Server', + 'odbc_mssql' => 'MS SQL Server via ODBC', + 'oracle' => 'Oracle', + 'odbc_oracle' => 'Oracle via ODBC', + 'sapdb' => 'SAP/Max DB via ODBC', + ); + + /** + * @var array with php-extension / ADOdb drive names => default port used by database + */ + var $default_db_ports = array( + 'pgsql' => 5432, + 'mysql' => 3306, + 'mysqli' => 3306, + 'mysqlt' => 3306, + 'mssql' => 1433, + 'odbc_mssql' => '', + 'oracle' => 1521, + 'odbc_oracle' => '', + 'sapdb' => '', + ); + + /** + * Detect settings or set defaults for the header.inc.php file (used if it does not yet exist) + * + * Sets $GLOBALS['egw_info'], $GLOBALS['egw_domains'] and the defines EGW_SERVER_ROOT and EGW_INCLUDE_ROOT, + * as if the header has been included + * + * @param string $domain='default' domain to set + */ + function defaults($domain='default') + { + $egw_root = realpath(dirname(__FILE__).'/../..'); + $GLOBALS['egw_info']['server']['server_root'] = $GLOBALS['egw_info']['server']['include_root'] = $egw_root; + define('EGW_SERVER_ROOT',$egw_root); // this is usally already defined by setup and cant be changed + define('EGW_INCLUDE_ROOT',$egw_root); + + $GLOBALS['egw_info']['server']['header_admin_user'] = 'admin'; + $GLOBALS['egw_info']['server']['header_admin_password'] = ''; + $GLOBALS['egw_info']['server']['setup_acl'] = ''; + + if ($domain) $GLOBALS['egw_domain'][$domain] = $this->domain_defaults(); + + $GLOBALS['egw_info']['server']['show_domain_selectbox'] = false; + $GLOBALS['egw_info']['server']['db_persistent'] = True; + $GLOBALS['egw_info']['login_template_set'] = 'idots'; + $GLOBALS['egw_info']['server']['mcrypt_enabled'] = False; + $GLOBALS['egw_info']['server']['versions']['mcrypt'] = ''; + $GLOBALS['egw_info']['server']['mcrypt_iv'] = $this->generate_mcyrpt_iv(); + } + + function domain_defaults($user='admin',$passwd='',$supported_db=null) + { + if (is_null($supported_db)) $supported_db = $this->check_db_support($null); + $default_db = count($supported_db) ? $supported_db[0] : 'mysqli'; + + return array( + 'db_host' => 'localhost', + 'db_port' => $this->default_db_ports[$default_db], + 'db_name' => 'egroupware', + 'db_user' => 'egroupware', + 'db_pass' => '', + 'db_type' => $default_db, + 'config_user' => $user, + 'config_passwd' => $passwd, + ); + } + + /** + * Checks the values of the (included) header.inc.php file + * + * The values are set in $GLOBALS['egw_info'], $GLOBALS['egw_domain'] and EGW_SERVER_ROOT + * + * @return array with errors or null if no errors + */ + function validation_errors($path=EGW_SERVER_ROOT) + { + $errors = null; + + if (!is_dir($path) || !is_readable($path) || !is_dir($path.'/phpgwapi')) + { + $errors[] = lang("%1 '%2' does NOT exist, is not readable by the webserver or contains no eGroupWare installation!",lang('Server root'),$path); + } + if(!$GLOBALS['egw_info']['server']['header_admin_password']) + { + $errors[] = lang("You didn't enter a header admin password"); + } + if(!$GLOBALS['egw_info']['server']['header_admin_user']) + { + $errors[] = lang("You didn't enter a header admin username"); + } + if (!is_array($GLOBALS['egw_domain']) || !count($GLOBALS['egw_domain'])) + { + $errors[] = lang('You need to add at least one eGroupWare domain / database instance.'); + } + else + { + foreach($GLOBALS['egw_domain'] as $domain => $data) + { + if (!$data['config_passwd']) + { + $errors[] = lang("You didn't enter a config password for domain %1",$domain); + } + if(!$data['config_user']) + { + $errors[] = lang("You didn't enter a config username for domain %1",$domain); + } + } + } + return $errors; + } + + /** + * generate header.inc.php file from given values + * + * setup_header::generate($GLOBALS['egw_info'],$GLOBALS['egw_domains']) + * should write an identical header.inc.php as the one include + * + * @param array $egw_info usual content (in server key) plus keys server_root and include_root + * @param array $egw_domains info about the existing eGW domains / DB instances + * @return string content of header.inc.php + */ + function generate($egw_info,$egw_domain) + { + $tpl =& CreateObject('phpgwapi.Template','../'); + $tpl->set_file(array('header' => 'header.inc.php.template')); + $tpl->set_block('header','domain','domain'); + + foreach($egw_domain as $domain => $data) + { + $var = array('DB_DOMAIN' => $domain); + foreach($data as $name => $value) + { + if ($name == 'db_port' && !$value) $value = $this->default_db_ports[$data['db_type']]; + if ($name == 'config_passwd') + { + $var['CONFIG_PASS'] = $this->is_md5($value) ? $value : md5($value); + } + else + { + $var[strtoupper($name)] = addslashes($value); + } + } + $tpl->set_var($var); + $tpl->parse('domains','domain',True); + } + $tpl->set_var('domain',''); + + $var = Array(); + foreach($egw_info['server'] as $name => $value) + { + if ($name == 'header_admin_password' && !$this->is_md5($value)) $value = md5($value); + if ($name == 'versions') + { + $name = 'mcrypt_version'; + $value = $value['mcrypt']; + } + static $bools = array( + 'mcrypt_enabled' => 'ENABLE_MCRYPT', + 'db_persistent' => 'db_persistent', + 'show_domain_selectbox' => 'DOMAIN_SELECTBOX', + ); + if (isset($bools[$name])) + { + $name = $bools[$name]; + $value = $value ? 'true' : 'false'; + } + $var[strtoupper($name)] = addslashes($value); + } + $tpl->set_var($var); + + return $tpl->parse('out','header'); + } + + /** + * Gernerate a random mcrypt_iv vector + * + * @return string + */ + function generate_mcyrpt_iv() + { + srand((double)microtime()*1000000); + $random_char = array( + '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L', + 'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' + ); + + $iv = ''; + for($i=0; $i<30; $i++) + { + $iv .= $random_char[rand(1,count($random_char))]; + } + return $iv; + } + + function check_db_support(&$detected) + { + $supported_db = $detected = array(); + foreach(array( + // short => array(extension,func_to_check,supported_db(s)) + 'mysqli' => array('mysql','mysqli_connect','mysqli'), + 'mysql' => array('mysql','mysql_connect','mysql'), + 'mysqlt' => array('mysql','mysql_connect','mysqlt'), + 'pgsql' => array('pgsql','pg_connect','pgsql'), + 'mssql' => array('mssql','mssql_connect','mssql'), + 'odbc' => array('odbc',false,'sapdb','odbc_mssql','odbc_oracle'), + 'oracle' => array('oci8',false,'oracle'), + ) as $db => $data) + { + $ext = array_shift($data); + $func_to_check = array_shift($data); + $name = isset($this->db_fullnames[$db]) ? $this->db_fullnames[$db] : strtoupper($db); + if (check_load_extension($ext) || $func_to_check && function_exists($func_to_check)) + { + $detected[] = lang('You appear to have %1 support.',$name); + $supported_db = array_merge($supported_db,$data); + } + else + { + $detected[] .= lang('No %1 support found. Disabling',$name); + } + } + return $supported_db; + } + + static function is_md5($str) + { + return preg_match('/^[0-9a-f]{32}$/',$str); + } +} + +// some constanst for pre php4.3 +if (!defined('PHP_SHLIB_SUFFIX')) +{ + define('PHP_SHLIB_SUFFIX',strtoupper(substr(PHP_OS, 0,3)) == 'WIN' ? 'dll' : 'so'); +} +if (!defined('PHP_SHLIB_PREFIX')) +{ + define('PHP_SHLIB_PREFIX',PHP_SHLIB_SUFFIX == 'dll' ? 'php_' : ''); +}