Is it possible to get the full structure of a mySQL database in json or xml format?
what I'm looking for is a way to get the schema (stored data doesn't matter) to use it to create a backend/crud for the application.
This is not a fully comprehensive answer to the question, as it doesn't return a json. But it's a simple class that gives all relevant info about a table as an object. This could easily be transformed to return a json.
The class relies on having passed a db object that implements a rawQuery method, as PHP-Mysqli-Database-Class does. But you could easily rewrite the method extractTableInfo if you need.
<?php
Class dbHelper {
private $db;
public function __construct($db) {
$this->db = $db;
}
public function extractTableInfo($tableName) {
$result = $this->db->rawQuery("DESCRIBE `".$tableName."`");
$tableInfo = array();
foreach ($result as $key => $value) {
$info = new \stdClass();
$info->name = $value['Field'];
$info->type = $this->_getColumnType($value['Type']);
$info->length = $this->_getLength($value['Type']);
$info->hasNull = $this->_getNull($value['Null']);
$info->default = $this->_getDefault($value['Default']);
$tableInfo[] = $info;
}
return $tableInfo;
}
public function getIndexes($tableName) {
$result = $this->db->rawQuery("SHOW INDEX FROM `".$tableName."`");
return $result;
}
private function _getLength($info) {
$pattern = '/\({1}([\d\W]*)\){1}/';
preg_match($pattern, $info, $matches);
return isset($matches[1]) ? $matches[1] : NULL;
}
private function _getColumnType($info) {
$pattern = '/([\w]*)(\([\d\W]*\))*/';
preg_match($pattern, $info, $matches);
return isset($matches[1]) ? $matches[1] : NULL;
}
private function _getNull($info) {
if($info==='NO') {
return false;
} else {
return true;
}
}
private function _getDefault($info) {
if($info>='') {
return $info;
} else {
return NULL;
}
}
}
Usage:
$db = YOUR DATABASE OBJECT/CLASS;
$dbHelper = new dbHelper($db);
$tableName = "test";
$tableInfo = $dbHelper->extractTableInfo($tableName);
echo json_encode($tableInfo);
To get a list of all tables in a database you'll need:
SHOW TABLES [in dbname]
or follow this question
Still, there are many alternatives with different benefits/outputs:
using mysql workbench
using phpmyadmin
using command line mysqldump -u root -p --no-data dbname > schema.sql
Related
Here is my php code, the test method not giving wanted output, and the other weird thing is var_dump('a') print 3 times;
my wanted output is array('qtggccc','qtff23sdf');
public function main()
{
$serverIds = array('ff23sdf','ggccc');
$res = $this->test($serverIds);
var_dump($res);
}
public function test($serverIds,$imgArray = array())
{
if(count($serverIds) > 0){
$media_id = array_pop($serverIds);
$imgUrl= $this->hh($media_id);
array_push($imgArray,$imgUrl);
var_dump($serverIds);
var_dump($imgArray);
$this->test($serverIds,$imgArray);
}
var_dump('a');
return $imgArray;
}
public function hh($m)
{
return 'qt'.$m;
}
Try this:
class MyClass{
private $imgArray = array();
public function main(){
$serverIds = array('ff23sdf','ggccc');
$res = $this->test($serverIds);
print_r($this->imgArray);
}
public function test($serverIds){
if(count($serverIds) > 0){
$media_id = end($serverIds);
$imgUrl= $this->hh($media_id);
array_push($this->imgArray,$imgUrl);
//remove last element
array_pop($serverIds);
$this->test($serverIds);
}
return;
}
public function hh($m){
return 'qt'.$m;
}
}
$obj = new MyClass();
echo '<pre>';
$obj->main();
Why use recursion? You are using a complicated solution for a simple problem.
public function main()
{
$serverIds = array('ff23sdf','ggccc');
$res = array();
//These three lines replace an entire recursive function, making the code easier and saving a chunk of memory once you start using real arrays
foreach ($serverIds as $media_id){
array_unshift($res, $this->hh($media_id));
}
var_dump($res);
}
public function hh($m)
{
return 'qt'.$m;
}
I have a DB class that I've created several functions in to return various values. One of the functions returns (or is supposed to) a "user" class object that represents a logged in user for the application.
class user {
public $guid = '';
public $fname = '';
public $lname = '';
public function __construct() {}
public function print_option() {
return "<option value='$this->guid'>$this->name</option>";
}
}
In the DB class I have the following 2 functions:
public function get_user($uid) {
$sql = '';
$usr = new user();
$sql = "SELECT guid, fname, lname FROM ms.users WHERE guid=?";
if($sth = $this->conn->prepare($sql)) {
$sth->bind_param('s', $uid);
if($sth->execute()) {
$sth->bind_result($usr->guid, $usr->fname, $usr->lname);
$sth->fetch();
print_r($usr); // PRINTS OUT CORRECTLY
return $usr;
}
else {return null;}
}
else {return null;}
}
public function get_practice_user_list($pguid) {
$ret = '';
$sql = "SELECT user_guid FROM ms.perm WHERE p_guid=?";
if($sth = $this->conn->prepare($sql)) {
$sth->bind_param('s', $pguid);
if($sth->execute()) {
$usr = new user();
$guid = '';
$sth->bind_result($guid);
while($sth->fetch()) {
print_r($guid); // PRINTS GUID correctly
$usr = $this->get_user($guid);
print_r($usr); // PRINTS NOTHING object is null so prints "error" two lines later.
if($usr != null) $ret .= $usr->print_option();
else print "error";
}
return $ret;
}
else {return null;}
}
else {return null;}
}
I'm just not understanding why the "user" object is not returning in this instance. Others calls to the get_user function work just fine and return the user class object pertaining to that user.
TIA
I guess you guid may be an integer so
$sth->bind_param('s', $uid);
bind_param's first param should be 'i' not 's';
http://www.php.net/manual/en/mysqli-stmt.bind-param.php
The problem was with the query. Since the code was just looping through one query (get_practice_user_list), then calling the get_user function and attempting a second query MySQL came back with an error of out of sync message. When I looked that up, I was able to fix it by doing a fetch_all on the first query then looping through that array to get the users.
I'm trying to learn how to print results from a query, but I'm getting confused.
Config Table:
site_id | site_name | site_description
1 Test Testing
Config:
private $hostname = 'localhost';
private $username = 'blah';
private $password = 'blah';
private $database = 'blah';
public function __construct()
{
$this->connection = new mysqli($this->hostname,$this->username,$this->password,$this->database);
if($this->connection->connect_errno)
{
die('Error: ' . $this->connection->error);
}
}
public function query($query)
{
return $this->connection->query($query);
}
public function __destruct()
{
$this->connection->close();
}
Code #1:
public function __construct()
{
$this->db = new Config;
$si = $this->db->query('SELECT * FROM config');
while($site_if = $si->fetch_array())
{
$this->site_info[] = $site_if;
}
}
public function getSiteName()
{
echo $this->site_info['site_name'];
}
This prints nothing.
Code #2:
public function __construct()
{
$this->db = new Config;
$si = $this->db->query('SELECT * FROM config');
while($site_if = $si->fetch_array())
{
$this->site_name_info = $site_if['site_name'];
}
}
public function getSiteName()
{
echo $this->site_name_info;
}
This prints the info, but is it the correct approach? Is there a way to print with Code #1?
All I want to do is echo site name. There is only one site name.
Without more info about your config table design the only think I can suggest is something like that:
while($site_if = $si->fetch_array())
{
$this->site_info[$site_if["NAME_COLUMN_NAME"]] = $site_if["VALUE_COLUMN_NAME"];
}
NAME_COLUMN_NAME and VALUE_COLUMN_NAME have to be replaced with column names from your table design.
After that you'll be able to get custom config parameter from $this->site_info array by it's name, eg.
public function getSiteName()
{
echo $this->site_info['site_name'];
}
In example #1, $this->site_info contains an array of arrays. To simply see the contents:
print_r($this->site_info);
To loop over the contents, printing the names of each row:
foreach ($this->site_info as $row){
echo $row['site_name'];
}
I am developing a project in which two portions of webpage frequently change and fetch recent data. I have some confusion about whether to use mysql_connect or mysql_pconnect? I have one config file that is being included in every page. There is one database connection object which I use for queries. Even when approximately 70 users are online it shows 20,000 connections on my server. Please suggest me the best way to keep a single connection alive from a single user, so there should be 70 connections when there are 70 users online. Currently I'm not using mysql_close method to close connection. Is this the reason it shows these many connections? Your advice will really be appreciated.
A common pattern used in this case is the singleton pattern, here's some rough code.
class DB_Instance
{
private static $db;
public static function getDB()
{
if (!self::$db)
self::$db = new Database();
return self::$db;
}
}
function getSomething()
{
$conn = DB_Instance::getDB();
.
.
.
}
Some examples/references
http://tutorialpedia.org/tutorials/Singleton+pattern+in+PHP.html
http://www.ricocheting.com/static/code/php/mysql-v3/Database.singleton.phps
http://netlinxinc.com/netlinx-blog/53-php/7-applying-the-singleton-pattern-to-database-connections-in-php.html
Here you have my implementation maybe it is useful for you
<?php
class Utils_Sql{
private $count = 0;
private static $sqlObj = null;
/**
* #return Utils_Sql
*/
public static function getSql(){
if(self::$sqlObj===null){self::$sqlObj = new Utils_Sql();}
return self::$sqlObj;
}
private $db;
private function __construct(){
$this->db = mysql_connect(MYSQL_SERVER,DB_LOGIN,DB_PASS);
if($this->db === false){
Utils_Logging_Logger::getLogger()->log(
array("Unable to connect to DB on Mysql_Server:".MYSQL_SERVER." with login:".DB_LOGIN." and pass:".DB_PASS."!")
,Utils_Logging_Logger::TYPE_ERROR
);
}else{
if (!mysql_select_db ( DB_NAME , $this->db )) {
$sql = "CREATE DATABASE " . DB_NAME;
$this->qry($sql);
if (!mysql_select_db ( DB_NAME , $this->db )) {
Utils_Logging_Logger::getLogger()->log(
array("DB: ".DB_NAME." not found"),
Utils_Logging_Logger::TYPE_ERROR
);
}
}
}
mysql_set_charset ('utf8',$this->getConnection());
}
public function getConnection(){return $this->db;}
public function qry($sql,$errType,$errMsg=""){
$this->count++;
// Utils_Logging_Logger::getLogger()->log("<br>$sql<br>",Utils_Logging_Logger::TYPE_LOG);
$ret = mysql_query($sql,$this->getConnection());
if(mysql_error($this->getConnection())){
//Error
$msgs = array(
"mysql_error: (".mysql_error($this->getConnection()).")",
"qry: \"$sql\""
);
if($errMsg!==""){$msgs[]="$errMsg";}
Utils_Logging_Logger::getLogger()->log($msgs,$errType);
}
return $ret;
}
public function getData($sql,$errType=Utils_Logging_Logger::TYPE_ERROR){
$r = $this->qry($sql,$errType);
if($r === false){
Utils_Logging_Logger::getLogger()->log("No Sql Resource, Illegal Query!",$errType);
return false;
}
$ret = array();
while(($data = mysql_fetch_assoc($r))!==false){
$ret[] = $data;
}
if(count($ret)===1){return $ret[0];}
else if(count($ret)>1){return $ret;}
else{
$msgs = array(
"No resulset found.",
"qry: \"$sql\""
);
Utils_Logging_Logger::getLogger()->log($msgs,$errType|Utils_Logging_Logger::TYPE_WARNING);
return false;
}
}
public function getInsertId($sql,$errType=Utils_Logging_Logger::TYPE_ERROR){
$this->qry($sql,$errType);
$ret = mysql_insert_id($this->getConnection());
if(!is_numeric($ret)){Utils_Logging_Logger::getLogger()->log("mysql_insert_id is not numeric!",$errType);}
return $ret;
}
public function getDbName(){return DB_NAME;}
public function __destruct(){
// Utils_Logging_Logger::getLogger()->log("Querys count: '$this->count'",Utils_Logging_Logger::TYPE_LOG);
}
}
Interstellar_Coder is correct, you want to use a singleton/factory solution for your db connection handling. We use here at work and it serves us well.
While Interstallar_Coder's solution is valid, I wrote up a more flexible solution in response to another post.
Destroy db connections:
public function __destruct()
{
foreach (self::$dbos as $key => $dbo) {
self::$dbos[$key] = null;
}
}
More info about PDO connection management.
I have a connection class for MySQL that looks like this:
class MySQLConnect
{
private $connection;
private static $instances = 0;
function __construct()
{
if(MySQLConnect::$instances == 0)
{
//Connect to MySQL server
$this->connection = mysql_connect(MySQLConfig::HOST, MySQLConfig::USER, MySQLConfig::PASS)
or die("Error: Unable to connect to the MySQL Server.");
MySQLConnect::$instances = 1;
}
else
{
$msg = "Close the existing instance of the MySQLConnector class.";
die($msg);
}
}
public function singleQuery($query, $databasename)
{
mysql_select_db(MySQLConfig::DB, $this->connection)
or die("Error: Could not select database " . MySQLConfig::DB . " from the server.");
$result = mysql_query($query) or die('Query failed.');
return $result;
}
public function createResultSet($query, $databasename)
{
$rs = new MySQLResultSet($query, MySQLConfig::DB, $this->connection ) ;
return $rs;
}
public function close()
{
MySQLConnect::$instances = 0;
if(isset($this->connection) ) {
mysql_close($this->connection) ;
unset($this->connection) ;
}
}
public function __destruct()
{
$this->close();
}
}
The MySQLResultSet class looks like this:
class MySQLResultSet implements Iterator
{
private $query;
private $databasename;
private $connection;
private $result;
private $currentRow;
private $key = 0;
private $valid;
public function __construct($query, $databasename, $connection)
{
$this->query = $query;
//Select the database
$selectedDatabase = mysql_select_db($databasename, $connection)
or die("Error: Could not select database " . $this->dbname . " from the server.");
$this->result = mysql_query($this->query) or die('Query failed.');
$this->rewind();
}
public function getResult()
{
return $this->result;
}
// public function getRow()
// {
// return mysql_fetch_row($this->result);
// }
public function getNumberRows()
{
return mysql_num_rows($this->result);
}
//current() returns the current row
public function current()
{
return $this->currentRow;
}
//key() returns the current index
public function key()
{
return $this->key;
}
//next() moves forward one index
public function next()
{
if($this->currentRow = mysql_fetch_array($this->result) ) {
$this->valid = true;
$this->key++;
}else{
$this->valid = false;
}
}
//rewind() moves to the starting index
public function rewind()
{
$this->key = 0;
if(mysql_num_rows($this->result) > 0)
{
if(mysql_data_seek($this->result, 0) )
{
$this->valid = true;
$this->key = 0;
$this->currentRow = mysql_fetch_array($this->result);
}
}
else
{
$this->valid = false;
}
}
//valid returns 1 if the current position is a valid array index
//and 0 if it is not valid
public function valid()
{
return $this->valid;
}
}
The following class is an example of how I am accessing the database:
class ImageCount
{
public function getCount()
{
$mysqlConnector = new MySQLConnect();
$query = "SELECT * FROM images;";
$resultSet = $mysqlConnector->createResultSet($query, MySQLConfig::DB);
$mysqlConnector->close();
return $resultSet->getNumberRows();
}
}
I use the ImageCount class like this:
if(!ImageCount::getCount())
{
//Do something
}
Question: Is this an okay way to access the database? Could anybody recommend an alternative method if it is bad?
Thank-you.
Hey Mike, there's nothing wrong with implementing your own classes to handle database connection, what you have so far is fine, however PHP already provides an interface for handling DB connections regardless of the database manager you are connecting to. I'd recommend you to take a look at it http://www.php.net/manual/en/book.pdo.php since it has mostly all the functionality needed for handling queries, statements, resultsets, errors, and so forth.
Cheers,
M.
I'm not sure that having a class called "ImageCount" is really necessary. If you're going to be working with images - I would simply have a class called "Image" with a static function to get the count of all images, and some other functions to deal with images.
Also, if you try to create a new instance when one exists - how about returning the existing instance instead of using die() to stop the program.