Source for file BitInstaller.php
Documentation is available at BitInstaller.php
* Initiolize BitInstaller
* loadAllUpgradeFiles load upgrade files from all packages that are installed
* Minimal login just for install in case users tables have been modified
function login( $pLogin, $pPassword, $pChallenge= NULL, $pResponse= NULL ) {
$loginCol = strpos( $pLogin, '@' ) ? 'email' : 'login';
if( $gBitUser->validate( $pLogin, $pPassword, $pChallenge, $pResponse ) ) {
$userInfo = $gBitUser->getUserInfo( array( $loginCol => $pLogin ) );
// User is valid and not due to change pass..
$gBitUser->mUserId = $userInfo['user_id'];
$gBitUser->mInfo = $userInfo;
$gBitUser->loadPermissions( TRUE );
$gBitUser->sendSessionCookie( $sessionId );
$gBitUser->updateSession( $sessionId );
return $gBitUser->isAdmin();
* loadUpgradeFiles This will load all files in the dir <pckage>/admin/upgrades/<version>.php with a version greater than the one installed
if( !empty( $pPackage )) {
while( FALSE !== ( $file = readdir( $upDir ))) {
// we only want to load files of versions that are greater than is installed
include_once( $dir. $file );
* @param array $pParams Hash of information about upgrade
* @param string $pParams[package] Name of package that is upgrading
* @param string $pParams[version] Version of this upgrade
* @param string $pParams[description] Description of what the upgrade does
* @param string $pParams[post_upgrade] Textual note of stuff that needs to be observed after the upgrade
* @param array $pUpgradeHash Hash of update rules. See existing upgrades on how this works.
$this->mPackageUpgrades[$pParams['package']][$pParams['version']]['upgrade'] = $pUpgradeHash;
// sort everything for a nice display
* @param array $pParams Hash of information about upgrade
* @param string $pParams[package] Name of package that is upgrading
* @param string $pParams[version] Version of this upgrade
* @param string $pParams[description] Description of what the upgrade does
* @param string $pParams[post_upgrade] Textual note of stuff that needs to be observed after the upgrade
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( empty( $pParams['package'] )) {
$this->mErrors['package'] = "Please provide a valid package name.";
$pParams['package'] = strtolower( $pParams['package'] );
if( empty( $pParams['version'] ) || !$this->validateVersion( $pParams['version'] )) {
$this->mErrors['version'] = "Please provide a valid version number.";
} elseif( empty( $this->mErrors ) && !empty( $this->mPackageUpgrades[$pParams['package']][$pParams['version']] )) {
$this->mErrors['version'] = "Please make sure you use a unique version number to register your new database changes.";
if( empty( $pParams['description'] )) {
$this->mErrors['description'] = "Please add a brief description of what this upgrade is all about.";
// since this should only show up when devs are working, we'll simply display the output:
* @param array $pUpgradeHash
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
$pPackage = strtolower( $pPackage ); // lower case for uniformity
if( !empty( $pUpgradeHash ) ) {
$this->mUpgrades[$pPackage] = $pUpgradeHash;
* @param string $pTemplate
* @param string $pBrowserTitle
header( 'Content-Type: text/html; charset=utf-8' );
// force the session to close *before* displaying. Why? Note this very important comment from http://us4.php.net/exec
if( !empty( $pPackage ) ) {
$gBitSmarty->verifyCompileDir();
$gBitSmarty->display( $pTemplate );
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
return( !empty( $this->mPackages[$pPackage]['installed'] ));
* getWebServerUid set global wwwuser and wwwgroup
global $wwwuser, $wwwgroup;
$wwwuser = $wwwgroup = '';
$wwwuser = $user ? $user['name'] : false;
$wwwgroup = $group ? $group['name'] : false;
$wwwuser = 'nobody (or the user account the web server is running under)';
$wwwgroup = 'nobody (or the group account the web server is running under)';
* @return database adjusted table prefix
// avoid errors in ADONewConnection() (wrong database driver etc...)
// strip out some schema stuff
// avoid database change messages
ini_set('sybct.min_server_severity', '11');
// Do a little prep work for postgres, no break, cause we want default case too
// Assume we want to dump in a schema, so set the search path and nuke the prefix here.
$quote = strpos( $schema, '"' );
// set scope to current schema
$result = $this->mDb->query( "SET search_path TO $schema" );
// return everything after the prefix
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( !empty( $pPackage ) && !empty( $this->mUpgrades[$pPackage] )) {
return( $this->applyUpgrade( $pPackage, $this->mUpgrades[$pPackage] ));
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
// make sure everything is in the right order
// version we are upgrading from
if( !empty( $errors[$version] )) {
// if the upgrade ended without incidence, we store the package version.
// this way any successfully applied upgrade can only be applied once.
* @param array $pUpgradeHash
* @return empty array on success, array with errors on failure
global $gBitDb, $gBitDbType;
if( !empty( $pUpgradeHash ) && is_array( $pUpgradeHash )) {
// set table prefixes and handle special case of sequence prefixes
$dict = NewDataDictionary( $gBitDb->mDb );
$failedcommands = array();
for( $i = 0; $i < count( $pUpgradeHash ); $i++ ) {
vd( "[$pPackage][$i] is NOT an array" );
$type = key( $pUpgradeHash[$i] );
$step = &$pUpgradeHash[$i][$type];
for( $j = 0; $j < count( $step ); $j++ ) {
foreach( $dd as $create ) {
$completeTableName = $tablePrefix. $tableName;
$sql = $dict->CreateTableSQL( $completeTableName, $create[$tableName], 'REPLACE' );
if( $sql && ( $dict->ExecuteSQLArray( $sql, FALSE ) > 0 ) ) {
$errors[] = 'Failed to create '. $completeTableName;
$failedcommands[] = implode( " ", $sql );
foreach( $dd as $alter ) {
$completeTableName = $tablePrefix. $tableName;
$this->mDb->convertQuery( $completeTableName );
foreach( $alter[$tableName] as $from => $flds ) {
$sql = $dict->ChangeTableSQL( $completeTableName, $flds );
$sql = $dict->ChangeTableSQL( $completeTableName, array( $flds ));
for( $sqlIdx = 0; $sqlIdx < count( $sql ); $sqlIdx++ ) {
$this->mDb->convertQuery( $sqlFoo );
if( $sql && $dict->ExecuteSQLArray( $sql, FALSE ) > 0 ) {
$errors[] = 'Failed to alter '. $completeTableName. ' -> '. $alter[$tableName];
$failedcommands[] = implode( " ", $sql );
foreach( $dd as $rename ) {
$completeTableName = $tablePrefix. $tableName;
if( $sql = @$dict->RenameTableSQL( $completeTableName, $tablePrefix. $rename[$tableName] ) ) {
foreach( $sql AS $query ) {
$this->mDb->query( $query );
$errors[] = 'Failed to rename table '. $completeTableName. '.'. $rename[$tableName][0]. ' to '. $rename[$tableName][1];
$failedcommands[] = implode( " ", $sql );
foreach( $dd as $rename ) {
$completeTableName = $tablePrefix. $tableName;
foreach( $rename[$tableName] as $from => $flds ) {
// MySQL needs the fields string, others do not.
// see http://phplens.com/lens/adodb/docs-datadict.htm
if( $sql = @$dict->RenameColumnSQL( $completeTableName, $from, $to, $flds ) ) {
foreach( $sql AS $query ) {
$this->mDb->query( $query );
$errors[] = 'Failed to rename column '. $completeTableName. '.'. $rename[$tableName][0]. ' to '. $rename[$tableName][1];
$failedcommands[] = implode( " ", $sql );
foreach( $dd as $create ) {
foreach( $create as $sequence ) {
$this->mDb->CreateSequence( $sequencePrefix. $sequence );
foreach( $dd as $rename ) {
foreach( $rename as $from => $to ) {
if( $gBitDbType != 'mysql' || $this->mDb->tableExists( $tablePrefix. $from ) ) {
if( $id = $this->mDb->GenID( $from ) ) {
$this->mDb->DropSequence( $sequencePrefix. $from );
$this->mDb->CreateSequence( $sequencePrefix. $to, $id );
$errors[] = 'Failed to rename sequence '. $sequencePrefix. $from. ' to '. $sequencePrefix. $to;
$failedcommands[] = implode( " ", $sql );
$this->mDb->CreateSequence( $sequencePrefix. $to, $pUpgradeHash['sequences'][$to]['start'] );
foreach( $dd as $drop ) {
foreach( $drop as $sequence ) {
$this->mDb->DropSequence( $sequencePrefix. $sequence );
foreach( $dd as $drop ) {
$completeTableName = $tablePrefix. $tableName;
foreach( $drop[$tableName] as $col ) {
if( $sql = $dict->DropColumnSQL( $completeTableName, $col ) ) {
foreach( $sql AS $query ) {
$this->mDb->query( $query );
$errors[] = 'Failed to drop column '. $completeTableName;
$failedcommands[] = implode( " ", $sql );
foreach( $dd as $drop ) {
foreach( $drop as $tableName ) {
$completeTableName = $tablePrefix. $tableName;
$sql = $dict->DropTableSQL( $completeTableName );
if( $sql && $dict->ExecuteSQLArray( $sql ) > 0 ) {
$errors[] = 'Failed to drop table '. $completeTableName;
$failedcommands[] = implode( " ", $sql );
foreach( $dd as $indices ) {
$completeTableName = $tablePrefix. $indices[$index][0];
if( $sql = $dict->CreateIndexSQL( $index, $completeTableName, $indices[$index][1], $indices[$index][2] ) ) {
foreach( $sql AS $query ) {
$this->mDb->query( $query );
$errors[] = 'Failed to create index '. $index;
$failedcommands[] = implode( " ", $sql );
if( !empty( $sql ) ) $sql = null;
uksort( $step, 'upgrade_query_sort' );
if( $dbType == 'MYSQL' && preg_match( '/mysql/', $gBitDbType )) {
} elseif( $dbType == 'PGSQL' && preg_match( '/postgres/', $gBitDbType )) {
} elseif( $dbType == 'SQL92' && !empty( $step['SQL92'] )) {
foreach( $sql as $query ) {
if( !$result = $this->mDb->query( $query )) {
$errors[] = 'Failed to execute SQL query';
$failedcommands[] = implode( " ", $sql );
// turn on features that are turned on
if( !empty( $failedcommands )) {
$ret['errors'] = $errors;
$ret['failedcommands'] = $failedcommands;
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
//echo "FieldCount: ".$result->FieldCount()."\n";
for( $i = 0; $i < $result->FieldCount(); $i++ ) {
$field = $result->FetchField($i);
//echo $i."-".$field->name."-".$result->MetaType($field->type)."-".$field->max_length."\n";
if(( $result->MetaType( $field->type ) == 'B' ) || ( $result->MetaType( $field->type )== 'X' && $field->max_length >= 16777215 ))
* convertBlobs enumerate blob fields and encoded
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
foreach( $blobs as $blob ) {
$res[$blob] = $gDb->dbByteEncode( $res[$blob] );
* @return TRUE on success, FALSE on failure
* @deprecated i think this isn't used any more
// Let's find out if we are have admin perm or a root user
if( empty( $gBitUser ) || $gBitUser->isAdmin() ) {
// let's try to load up user_id - if successful, we know we have one.
if( !$rootUser->isValid() ) {
* check_session_save_path
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
if( ini_get( 'session.save_handler' ) == 'files' ) {
$save_path = ini_get( 'session.save_path' );
$errors .= "The directory '$save_path' does not exist or PHP is not allowed to access it (check session.save_path or open_basedir entries in php.ini).\n";
$errors .= "The directory '$save_path' is not writeable.\n";
$save_path = static::tempdir();
ini_set('session.save_path', $save_path);
* @param string $gBitDbType
* @param string $gBitDbHost
* @param string $gBitDbUser
* @param string $gBitDbPassword
* @param string $gBitDbName
* @return TRUE on success, FALSE on failure - mErrors will contain reason for failure
function makeConnection( $gBitDbType, $gBitDbHost, $gBitDbUser, $gBitDbPassword, $gBitDbName ) {
$gDb = &ADONewConnection( $gBitDbType );
if( !$gDb->Connect( $gBitDbHost, $gBitDbUser, $gBitDbPassword, $gBitDbName )) {
echo $gDb->ErrorMsg(). "\n";
global $gBitDbCaseSensitivity;
$gDb->mCaseSensitive = $gBitDbCaseSensitivity;
$gDb->SetFetchMode( ADODB_FETCH_ASSOC );
* upgrade_package_sort sort packages before they are upgraded
* @return numeric sort direction
if(( $aa['required'] && $bb['required'] ) || ( !$aa['required'] && !$bb['required'] )) {
} elseif( $aa['required'] && !$bb['required'] ) {
} elseif( !$aa['required'] && $bb['required'] ) {
* upgrade_version_sort sort upgrades based on version number
* @return numeric sort direction
* upgrade_query_sort sort queries that SQL92 queries are called last
* @return numeric sort direction
} elseif( $b == 'SQL92' ) {
|