/** * Verifies if current MySQL server supports profiling * * @access public * * @return boolean whether profiling is supported */ function PMA_profilingSupported() { if (!PMA_cacheExists('profiling_supported', true)) { // 5.0.37 has profiling but for example, 5.1.20 does not // (avoid a trip to the server for MySQL before 5.0.37) // and do not set a constant as we might be switching servers if (defined('PMA_MYSQL_INT_VERSION') && PMA_MYSQL_INT_VERSION >= 50037 && PMA_DBI_fetch_value("SHOW VARIABLES LIKE 'profiling'")) { PMA_cacheSet('profiling_supported', true, true); } else { PMA_cacheSet('profiling_supported', false, true); } } return PMA_cacheGet('profiling_supported', true); }
/** * sets privilege information extracted from SHOW GRANTS result * * Detection for some CREATE privilege. * * Since MySQL 4.1.2, we can easily detect current user's grants using $userlink * (no control user needed) and we don't have to try any other method for * detection * * @todo fix to get really all privileges, not only explicitly defined for this user * from MySQL manual: (http://dev.mysql.com/doc/refman/5.0/en/show-grants.html) * SHOW GRANTS displays only the privileges granted explicitly to the named * account. Other privileges might be available to the account, but they are not * displayed. For example, if an anonymous account exists, the named account * might be able to use its privileges, but SHOW GRANTS will not display them. * * @uses $_SESSION['is_create_db_priv'] for caching * @uses $_SESSION['is_process_priv'] for caching * @uses $_SESSION['is_reload_priv'] for caching * @uses $_SESSION['db_to_create'] for caching * @uses $_SESSION['dbs_where_create_table_allowed'] for caching * @uses $GLOBALS['is_create_db_priv'] to set it * @uses $GLOBALS['is_process_priv'] to set it * @uses $GLOBALS['is_reload_priv'] to set it * @uses $GLOBALS['db_to_create'] to set it * @uses $GLOBALS['dbs_where_create_table_allowed'] to set it * @uses $GLOBALS['server'] * @uses PMA_DBI_try_query() * @uses PMA_DBI_fetch_row() * @uses PMA_DBI_free_result() * @uses PMA_DBI_getError() * @uses PMA_unQuote() * @uses PMA_backquote() * @uses preg_match() * @uses preg_replace() * @uses substr() * @uses strpos() */ function PMA_analyseShowGrant() { if (PMA_cacheExists('is_create_db_priv', true)) { $GLOBALS['is_create_db_priv'] = PMA_cacheGet('is_create_db_priv', true); $GLOBALS['is_process_priv'] = PMA_cacheGet('is_process_priv', true); $GLOBALS['is_reload_priv'] = PMA_cacheGet('is_reload_priv', true); $GLOBALS['db_to_create'] = PMA_cacheGet('db_to_create', true); $GLOBALS['dbs_where_create_table_allowed'] = PMA_cacheGet('dbs_where_create_table_allowed', true); return; } // defaults $GLOBALS['is_create_db_priv'] = false; $GLOBALS['is_process_priv'] = true; $GLOBALS['is_reload_priv'] = false; $GLOBALS['db_to_create'] = ''; $GLOBALS['dbs_where_create_table_allowed'] = array(); $rs_usr = PMA_DBI_try_query('SHOW GRANTS'); if (!$rs_usr) { return; } $re0 = '(^|(\\\\\\\\)+|[^\\\\])'; // non-escaped wildcards $re1 = '(^|[^\\\\])(\\\\)+'; // escaped wildcards while ($row = PMA_DBI_fetch_row($rs_usr)) { // extract db from GRANT ... ON *.* or GRANT ... ON db.* $db_name_offset = strpos($row[0], ' ON ') + 4; $show_grants_dbname = substr($row[0], $db_name_offset, strpos($row[0], '.', $db_name_offset) - $db_name_offset); $show_grants_dbname = PMA_unQuote($show_grants_dbname, '`'); $show_grants_str = substr($row[0], 6, strpos($row[0], ' ON ') - 6); if ($show_grants_str == 'RELOAD') { $GLOBALS['is_reload_priv'] = true; } /** * @todo if we find CREATE VIEW but not CREATE, do not offer * the create database dialog box */ if ($show_grants_str == 'ALL' || $show_grants_str == 'ALL PRIVILEGES' || $show_grants_str == 'CREATE' || strpos($show_grants_str, 'CREATE,') !== false) { if ($show_grants_dbname == '*') { // a global CREATE privilege $GLOBALS['is_create_db_priv'] = true; $GLOBALS['is_reload_priv'] = true; $GLOBALS['db_to_create'] = ''; $GLOBALS['dbs_where_create_table_allowed'][] = '*'; // @todo we should not break here, cause GRANT ALL *.* // could be revoked by a later rule like GRANT SELECT ON db.* break; } else { // this array may contain wildcards $GLOBALS['dbs_where_create_table_allowed'][] = $show_grants_dbname; $dbname_to_test = PMA_backquote($show_grants_dbname); if ($GLOBALS['is_create_db_priv']) { // no need for any more tests if we already know this continue; } if (preg_match('/' . $re0 . '%|_/', $show_grants_dbname) && !preg_match('/\\\\%|\\\\_/', $show_grants_dbname) || !PMA_DBI_try_query('USE ' . preg_replace('/' . $re1 . '(%|_)/', '\\1\\3', $dbname_to_test)) && substr(PMA_DBI_getError(), 1, 4) != 1044) { if ($GLOBALS['cfg']['SuggestDBName']) { $GLOBALS['db_to_create'] = preg_replace('/' . $re0 . '_/', '\\1?', $show_grants_dbname); $GLOBALS['db_to_create'] = preg_replace('/' . $re0 . '%/', '\\1...', $GLOBALS['db_to_create']); $GLOBALS['db_to_create'] = preg_replace('/' . $re1 . '(%|_)/', '\\1\\3', $GLOBALS['db_to_create']); } $GLOBALS['is_create_db_priv'] = true; /** * @todo collect $GLOBALS['db_to_create'] into an array, to display a * drop-down in the "Create new database" dialog */ // we don't break, we want all possible databases //break; } // end if } // end elseif } // end if } // end while PMA_DBI_free_result($rs_usr); // must also PMA_cacheUnset() them in libraries/auth/cookie.auth.lib.php PMA_cacheSet('is_create_db_priv', $GLOBALS['is_create_db_priv'], true); PMA_cacheSet('is_process_priv', $GLOBALS['is_process_priv'], true); PMA_cacheSet('is_reload_priv', $GLOBALS['is_reload_priv'], true); PMA_cacheSet('db_to_create', $GLOBALS['db_to_create'], true); PMA_cacheSet('dbs_where_create_table_allowed', $GLOBALS['dbs_where_create_table_allowed'], true); }
/** * returns true (int > 0) if current user is superuser * otherwise 0 * * @uses $_SESSION['is_superuser'] for caching * @uses $GLOBALS['userlink'] * @uses $GLOBALS['server'] * @uses PMA_DBI_try_query() * @uses PMA_DBI_QUERY_STORE * @return integer $is_superuser */ function PMA_isSuperuser() { if (PMA_cacheExists('is_superuser', true)) { return PMA_cacheGet('is_superuser', true); } // with mysql extension, when connection failed we don't have // a $userlink if (isset($GLOBALS['userlink'])) { $r = (bool) PMA_DBI_try_query('SELECT COUNT(*) FROM mysql.user', $GLOBALS['userlink'], PMA_DBI_QUERY_STORE); PMA_cacheSet('is_superuser', $r, true); } else { PMA_cacheSet('is_superuser', false, true); } return PMA_cacheGet('is_superuser', true); }
sort($mysql_collations_flat, SORT_STRING); foreach ($mysql_collations AS $key => $value) { sort($mysql_collations[$key], SORT_STRING); reset($mysql_collations[$key]); } unset($key, $value); PMA_cacheSet('mysql_charsets', $GLOBALS['mysql_charsets'], true); PMA_cacheSet('mysql_charsets_descriptions', $GLOBALS['mysql_charsets_descriptions'], true); PMA_cacheSet('mysql_charsets_count', $GLOBALS['mysql_charsets_count'], true); PMA_cacheSet('mysql_charsets_available', $GLOBALS['mysql_charsets_available'], true); PMA_cacheSet('mysql_collations', $GLOBALS['mysql_collations'], true); PMA_cacheSet('mysql_default_collations', $GLOBALS['mysql_default_collations'], true); PMA_cacheSet('mysql_collations_flat', $GLOBALS['mysql_collations_flat'], true); PMA_cacheSet('mysql_collations_count', $GLOBALS['mysql_collations_count'], true); PMA_cacheSet('mysql_collations_available', $GLOBALS['mysql_collations_available'], true); } else { $GLOBALS['mysql_charsets'] = PMA_cacheGet('mysql_charsets', true); $GLOBALS['mysql_charsets_descriptions'] = PMA_cacheGet('mysql_charsets_descriptions', true); $GLOBALS['mysql_charsets_count'] = PMA_cacheGet('mysql_charsets_count', true); $GLOBALS['mysql_charsets_available'] = PMA_cacheGet('mysql_charsets_available', true); $GLOBALS['mysql_collations'] = PMA_cacheGet('mysql_collations', true); $GLOBALS['mysql_default_collations'] = PMA_cacheGet('mysql_default_collations', true); $GLOBALS['mysql_collations_flat'] = PMA_cacheGet('mysql_collations_flat', true); $GLOBALS['mysql_collations_count'] = PMA_cacheGet('mysql_collations_count', true); $GLOBALS['mysql_collations_available'] = PMA_cacheGet('mysql_collations_available', true); } define('PMA_CSDROPDOWN_COLLATION', 0); define('PMA_CSDROPDOWN_CHARSET', 1);
/** * returns true (int > 0) if current user is superuser * otherwise 0 * * @return bool Whether use is a superuser */ function PMA_isSuperuser() { if (PMA_cacheExists('is_superuser', true)) { return PMA_cacheGet('is_superuser', true); } // when connection failed we don't have a $userlink if (isset($GLOBALS['userlink'])) { if (PMA_DRIZZLE) { // Drizzle has no authorization by default, so when no plugin is // enabled everyone is a superuser // Known authorization libraries: regex_policy, simple_user_policy // Plugins limit object visibility (dbs, tables, processes), we can // safely assume we always deal with superuser $r = true; } else { // check access to mysql.user table $r = (bool) PMA_DBI_try_query('SELECT COUNT(*) FROM mysql.user', $GLOBALS['userlink'], PMA_DBI_QUERY_STORE); } PMA_cacheSet('is_superuser', $r, true); } else { PMA_cacheSet('is_superuser', false, true); } return PMA_cacheGet('is_superuser', true); }
/** * checks whether the necessary plugins for BLOBStreaming exist * * @access public * @return boolean */ function checkBLOBStreamingPlugins() { if (PMA_cacheGet('skip_blobstreaming', true) === true) { return false; } // load PMA configuration $PMA_Config = $GLOBALS['PMA_Config']; // return if unable to load PMA configuration if (empty($PMA_Config)) { return false; } // If we don't know that we can skip blobstreaming, we continue // verifications; anyway, in case we won't skip blobstreaming, // we still need to set some variables in non-persistent settings, // which is done via $PMA_Config->set(). /** Retrieve current server configuration; * at this point, $PMA_Config->get('Servers') contains the server parameters * as explicitely defined in config.inc.php, so it cannot be used; it's * better to use $GLOBALS['cfg']['Server'] which contains the explicit * parameters merged with the default ones * */ $serverCfg = $GLOBALS['cfg']['Server']; // return if unable to retrieve current server configuration if (!$serverCfg) { return false; } // if PHP extension in use is 'mysql', specify element 'PersistentConnections' if ($serverCfg['extension'] == "mysql") { $serverCfg['PersistentConnections'] = $PMA_Config->settings['PersistentConnections']; } // if connection type is TCP, unload socket variable if (strtolower($serverCfg['connect_type']) == "tcp") { $serverCfg['socket'] = ""; } $has_blobstreaming = PMA_cacheGet('has_blobstreaming', true); if ($has_blobstreaming === null) { if (!PMA_DRIZZLE && PMA_MYSQL_INT_VERSION >= 50109) { // Retrieve MySQL plugins $existing_plugins = PMA_DBI_fetch_result('SHOW PLUGINS'); foreach ($existing_plugins as $one_existing_plugin) { // check if required plugins exist if (strtolower($one_existing_plugin['Library']) == 'libpbms.so' && $one_existing_plugin['Status'] == "ACTIVE") { $has_blobstreaming = true; break; } } unset($existing_plugins, $one_existing_plugin); } else { if (PMA_DRIZZLE) { $has_blobstreaming = (bool) PMA_DBI_fetch_result("SELECT 1\n FROM data_dictionary.plugins\n WHERE module_name = 'PBMS'\n AND is_active = true\n LIMIT 1"); } } PMA_cacheSet('has_blobstreaming', $has_blobstreaming, true); } // set variable indicating BS plugin existence $PMA_Config->set('BLOBSTREAMING_PLUGINS_EXIST', $has_blobstreaming); if (!$has_blobstreaming) { PMA_cacheSet('skip_blobstreaming', true, true); return false; } if ($has_blobstreaming) { $bs_variables = PMA_BS_GetVariables(); // if no BS variables exist, set plugin existence to false and return if (count($bs_variables) == 0) { $PMA_Config->set('BLOBSTREAMING_PLUGINS_EXIST', false); PMA_cacheSet('skip_blobstreaming', true, true); PMA_cacheSet('has_blobstreaming', false, true); return false; } // end if (count($bs_variables) <= 0) // Check that the required pbms functions exist: if (function_exists("pbms_connect") == false || function_exists("pbms_error") == false || function_exists("pbms_close") == false || function_exists("pbms_is_blob_reference") == false || function_exists("pbms_get_info") == false || function_exists("pbms_get_metadata_value") == false || function_exists("pbms_add_metadata") == false || function_exists("pbms_read_stream") == false) { // We should probably notify the user that they need to install // the pbms client lib and PHP extension to make use of blob streaming. $PMA_Config->set('BLOBSTREAMING_PLUGINS_EXIST', false); PMA_cacheSet('skip_blobstreaming', true, true); PMA_cacheSet('has_blobstreaming', false, true); return false; } if (function_exists("pbms_connection_pool_size")) { if (isset($PMA_Config->settings['pbms_connection_pool_size'])) { $pool_size = $PMA_Config->settings['pbms_connection_pool_size']; if ($pool_size == "") { $pool_size = 1; } } else { $pool_size = 1; } pbms_connection_pool_size($pool_size); } // get BS server port $BS_PORT = $bs_variables['pbms_port']; // if no BS server port or 'pbms' database exists, // set plugin existance to false and return if (!$BS_PORT || !initPBMSDatabase()) { $PMA_Config->set('BLOBSTREAMING_PLUGINS_EXIST', false); PMA_cacheSet('skip_blobstreaming', true, true); return false; } // end if (!$BS_PORT) // Ping PBMS: the database doesn't need to exist for this to work. if (pbms_connect($serverCfg['host'], $BS_PORT, "anydb") == false) { $PMA_Config->set('BLOBSTREAMING_PLUGINS_EXIST', false); PMA_cacheSet('skip_blobstreaming', true, true); return false; } pbms_close(); if (function_exists("pbms_pconnect")) { $PMA_Config->set('PBMS_PCONNECT_EXISTS', true); } else { $PMA_Config->set('PBMS_PCONNECT_EXISTS', false); } // add selected BS, CURL and fileinfo library variables to PMA configuration $PMA_Config->set('BLOBSTREAMING_PORT', $BS_PORT); $PMA_Config->set('BLOBSTREAMING_HOST', $serverCfg['host']); $PMA_Config->set('BLOBSTREAMING_SERVER', $serverCfg['host'] . ':' . $BS_PORT); $PMA_Config->set('PHP_PBMS_EXISTS', false); $PMA_Config->set('FILEINFO_EXISTS', false); // check if PECL's fileinfo library exist $finfo = null; if (function_exists("finfo_open")) { $finfo = finfo_open(FILEINFO_MIME); } // fileinfo library exists, set necessary variable and close resource if (!empty($finfo)) { $PMA_Config->set('FILEINFO_EXISTS', true); finfo_close($finfo); } // end if (!empty($finfo)) } else { PMA_cacheSet('skip_blobstreaming', true, true); return false; } // end if ($has_blobstreaming) return true; }
/** * Test clearing user cache */ public function testClearUserCache() { $GLOBALS['server'] = 'server'; PMA_cacheSet('is_superuser', 'yes', true); $this->assertEquals('yes', $_SESSION['cache']['server_server']['is_superuser']); PMA_clearUserCache(); $this->assertArrayNotHasKey('is_superuser', $_SESSION['cache']['server_server']); }
/** * checks whether the necessary plugins for BLOBStreaming exist * * @access public * @uses PMA_Config::get() * @uses PMA_Config::settings() * @uses PMA_Config::set() * @uses PMA_BS_SetVariables() * @uses PMA_BS_GetVariables() * @uses PMA_BS_SetFieldReferences() * @uses PMA_cacheSet() * @uses PMA_cacheGet() * @return boolean */ function checkBLOBStreamingPlugins() { // load PMA configuration $PMA_Config = $_SESSION['PMA_Config']; // return if unable to load PMA configuration if (empty($PMA_Config)) { return FALSE; } // At this point we might already know that plugins do not exist // because this was recorded in the session (cache). if (PMA_cacheGet('skip_blobstreaming', true)) { return false; } // If we don't know that we can skip blobstreaming, we continue // verifications; anyway, in case we won't skip blobstreaming, // we still need to set some variables in non-persistent settings, // which is done via $PMA_Config->set(). /** Retrieve current server configuration; * at this point, $PMA_Config->get('Servers') contains the server parameters * as explicitely defined in config.inc.php, so it cannot be used; it's * better to use $GLOBALS['cfg']['Server'] which contains the explicit * parameters merged with the default ones * */ $serverCfg = $GLOBALS['cfg']['Server']; // return if unable to retrieve current server configuration if (!$serverCfg) { return FALSE; } // if PHP extension in use is 'mysql', specify element 'PersistentConnections' if ($serverCfg['extension'] == "mysql") { $serverCfg['PersistentConnections'] = $PMA_Config->settings['PersistentConnections']; } // if connection type is TCP, unload socket variable if (strtolower($serverCfg['connect_type']) == "tcp") { $serverCfg['socket'] = ""; } $allPluginsExist = false; if (PMA_MYSQL_INT_VERSION >= 50109) { $PMA_Config->set('PBXT_NAME', 'pbxt'); $PMA_Config->set('PBMS_NAME', 'pbms'); $required_plugins[$PMA_Config->get('PBXT_NAME')]['Library'] = 'libpbxt.so'; $required_plugins[$PMA_Config->get('PBMS_NAME')]['Library'] = 'libpbms.so'; $number_of_required_plugins_found = 0; // Retrieve MySQL plugins $existing_plugins = PMA_DBI_fetch_result('SHOW PLUGINS'); foreach ($existing_plugins as $one_existing_plugin) { // check if required plugins exist foreach ($required_plugins as $one_required_plugin) { if (strtolower($one_existing_plugin['Library']) == strtolower($one_required_plugin['Library']) && $one_existing_plugin['Status'] == "ACTIVE") { $number_of_required_plugins_found++; } } if (2 == $number_of_required_plugins_found) { $allPluginsExist = true; break; } } unset($required_plugins, $existing_plugins, $one_required_plugin, $one_existing_plugin, $number_of_required_plugins_found); } // set variable indicating BS plugin existence $PMA_Config->set('BLOBSTREAMING_PLUGINS_EXIST', $allPluginsExist); if ($allPluginsExist) { // retrieve BS variables from PMA configuration $bs_set_variables = array(); $bs_set_variables[$PMA_Config->get('PBMS_NAME') . '_garbage_threshold'] = isset($serverCfg['bs_garbage_threshold']) ? $serverCfg['bs_garbage_threshold'] : NULL; $bs_set_variables[$PMA_Config->get('PBMS_NAME') . '_repository_threshold'] = isset($serverCfg['bs_repository_threshold']) ? $serverCfg['bs_repository_threshold'] : NULL; $bs_set_variables[$PMA_Config->get('PBMS_NAME') . '_temp_blob_timeout'] = isset($serverCfg['bs_temp_blob_timeout']) ? $serverCfg['bs_temp_blob_timeout'] : NULL; $bs_set_variables[$PMA_Config->get('PBMS_NAME') . '_temp_log_threshold'] = isset($serverCfg['bs_temp_log_threshold']) ? $serverCfg['bs_temp_log_threshold'] : NULL; // set BS variables to PMA configuration defaults PMA_BS_SetVariables($bs_set_variables); // retrieve updated BS variables (configurable and unconfigurable) $bs_variables = PMA_BS_GetVariables(); // if no BS variables exist, set plugin existence to false and return if (count($bs_variables) <= 0) { $PMA_Config->set('BLOBSTREAMING_PLUGINS_EXIST', FALSE); PMA_cacheSet('skip_blobstreaming', true, true); return FALSE; } // end if (count($bs_variables) <= 0) // switch on BS field references if (strtolower($bs_variables[$PMA_Config->get('PBMS_NAME') . '_field_references']) == "off") { if (!PMA_BS_SetFieldReferences('ON')) { PMA_cacheSet('skip_blobstreaming', true, true); return FALSE; } } // get BS server port $BS_PORT = $bs_variables[$PMA_Config->get('PBMS_NAME') . '_port']; // if no BS server port exists, set plugin existance to false and return if (!$BS_PORT) { $PMA_Config->set('BLOBSTREAMING_PLUGINS_EXIST', FALSE); PMA_cacheSet('skip_blobstreaming', true, true); return FALSE; } // end if (!$BS_PORT) // add selected BS, CURL and fileinfo library variables to PMA configuration $PMA_Config->set('BLOBSTREAMING_PORT', $BS_PORT); $PMA_Config->set('BLOBSTREAMING_HOST', $serverCfg['host']); $PMA_Config->set('BLOBSTREAMING_SERVER', $serverCfg['host'] . ':' . $BS_PORT); $PMA_Config->set('CURL_EXISTS', FALSE); $PMA_Config->set('FILEINFO_EXISTS', FALSE); // check if CURL exists if (function_exists("curl_init")) { // initialize curl handler $curlHnd = curl_init(); // CURL exists, set necessary variable and close resource if (!empty($curlHnd)) { $PMA_Config->set('CURL_EXISTS', TRUE); curl_close($curlHnd); } // end if (!empty($curlHnd)) } // end if (function_exists("curl_init")) // check if PECL's fileinfo library exist $finfo = NULL; if (function_exists("finfo_open")) { $finfo = finfo_open(FILEINFO_MIME); } // fileinfo library exists, set necessary variable and close resource if (!empty($finfo)) { $PMA_Config->set('FILEINFO_EXISTS', TRUE); finfo_close($finfo); } // end if (!empty($finfo)) } else { PMA_cacheSet('skip_blobstreaming', true, true); return FALSE; } // end if ($allPluginsExist) $bs_tables = array(); // specify table structure for BS reference table $bs_tables[$PMA_Config->get('PBMS_NAME') . '_reference'] = array(); $bs_tables[$PMA_Config->get('PBMS_NAME') . '_reference']['struct'] = <<<EOD CREATE TABLE {$PMA_Config->get('PBMS_NAME')}_reference ( Table_name CHAR(64) COMMENT 'The name of the referencing table', Blob_id BIGINT COMMENT 'The BLOB reference number - part of the BLOB URL', Column_name CHAR(64) COMMENT 'The column name of the referencing field', Row_condition VARCHAR(255) COMMENT 'This condition identifies the row in the table', Blob_url VARCHAR(200) COMMENT 'The BLOB URL for HTTP GET access', Repository_id INT COMMENT 'The repository file number of the BLOB', Repo_blob_offset BIGINT COMMENT 'The offset in the repository file', Blob_size BIGINT COMMENT 'The size of the BLOB in bytes', Deletion_time TIMESTAMP COMMENT 'The time the BLOB was deleted', Remove_in INT COMMENT 'The number of seconds before the reference/BLOB is removed perminently', Temp_log_id INT COMMENT 'Temporary log number of the referencing deletion entry', Temp_log_offset BIGINT COMMENT 'Temporary log offset of the referencing deletion entry' ) ENGINE=PBMS; EOD; // specify table structure for BS repository table $bs_tables[$PMA_Config->get('PBMS_NAME') . '_repository'] = array(); $bs_tables[$PMA_Config->get('PBMS_NAME') . '_repository']['struct'] = <<<EOD CREATE TABLE {$PMA_Config->get('PBMS_NAME')}_repository ( Repository_id INT COMMENT 'The repository file number', Repo_blob_offset BIGINT COMMENT 'The offset of the BLOB in the repository file', Blob_size BIGINT COMMENT 'The size of the BLOB in bytes', Head_size SMALLINT UNSIGNED COMMENT 'The size of the BLOB header - proceeds the BLOB data', Access_code INT COMMENT 'The 4-byte authorisation code required to access the BLOB - part of the BLOB URL', Creation_time TIMESTAMP COMMENT 'The time the BLOB was created', Last_ref_time TIMESTAMP COMMENT 'The last time the BLOB was referenced', Last_access_time TIMESTAMP COMMENT 'The last time the BLOB was accessed (read)', Content_type CHAR(128) COMMENT 'The content type of the BLOB - returned by HTTP GET calls', Blob_data LONGBLOB COMMENT 'The data of this BLOB' ) ENGINE=PBMS; EOD; // specify table structure for BS custom content type table $bs_tables[$PMA_Config->get('PBMS_NAME') . '_custom_content_type'] = array(); $bs_tables[$PMA_Config->get('PBMS_NAME') . '_custom_content_type']['struct'] = <<<EOD CREATE TABLE {$PMA_Config->get('PBMS_NAME')}_custom_content_type ( Blob_url VARCHAR(200) COMMENT 'The BLOB URL for HTTP GET access', Content_type VARCHAR(255) COMMENT 'The custom MIME type for a given BLOB reference as specified by the user', PRIMARY KEY(Blob_url) ); EOD; // add BS tables to PMA configuration $PMA_Config->set('BLOBSTREAMING_TABLES', $bs_tables); return TRUE; }