Initial-Final Commit
commit
d9b752dc9e
|
@ -0,0 +1,5 @@
|
|||
# DB-Xplorer
|
||||
|
||||
### A minimal, unsafe and maybe usefull sql database explorer
|
||||
|
||||
Please don't use that *really*
|
|
@ -0,0 +1,4 @@
|
|||
<?php return array(
|
||||
'limit_size' => 10,
|
||||
'display_length' => 50
|
||||
);
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
session_start();
|
||||
|
||||
$_page = isset($_GET['page']) ? htmlspecialchars($_GET['page']) : 'index';
|
||||
$_schema = isset($_GET['schema']) ? htmlspecialchars($_GET['schema']) : null;
|
||||
$_table = isset($_GET['table']) ? htmlspecialchars($_GET['table']) : null;
|
||||
$_offset = isset($_GET['offset']) ? intval(htmlspecialchars($_GET['offset'])) : 0;
|
||||
|
||||
$config=include('config.php');
|
||||
include('model.php');
|
||||
include('router.php');
|
||||
?>
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
$_loginFields = array("db_string", "db_name", "db_user", "db_password");
|
||||
$logable = true;
|
||||
foreach ($_loginFields as $key) {
|
||||
if(!isset($_SESSION[$key]))
|
||||
$logable = false;
|
||||
}
|
||||
if($logable){
|
||||
try {
|
||||
$db = new PDO($_SESSION['db_string'].';dbname='.$_SESSION['db_name'],
|
||||
$_SESSION['db_user'],
|
||||
$_SESSION['db_password'],
|
||||
array(
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
|
||||
));
|
||||
} catch (PDOException $e) {
|
||||
$_error = $e->getMessage();
|
||||
$_page = 'fail';
|
||||
}
|
||||
}else{
|
||||
if($_page != 'disconnect')
|
||||
$_page = 'connect';
|
||||
}
|
||||
|
||||
function getQuery($query){
|
||||
global $db;
|
||||
return $db->query($query)->fetchall();
|
||||
}
|
||||
|
||||
function getPrepareQuery($query, $args){
|
||||
global $db;
|
||||
$sth = $db->prepare($query);
|
||||
$sth->execute($args);
|
||||
return $sth->fetchAll();
|
||||
}
|
||||
|
||||
function getSchemasList(){
|
||||
$schemas = array();
|
||||
foreach (getQuery('SELECT schema_name FROM information_schema.schemata') as $schema) {
|
||||
$schemas[] = $schema['schema_name'];
|
||||
}
|
||||
return $schemas;
|
||||
}
|
||||
|
||||
function getTablesList(){
|
||||
global $db;
|
||||
return $db->query("SELECT table_schema, table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema')")->fetchall();
|
||||
}
|
||||
|
||||
function getTablesListBySchema($schema){
|
||||
$tables = array();
|
||||
foreach (getPrepareQuery("SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = ?", array($schema)) as $table) {
|
||||
$tables[] = $table['table_name'];
|
||||
}
|
||||
return $tables;
|
||||
}
|
||||
|
||||
function getTableColumnsList($schema, $table){
|
||||
return getPrepareQuery("SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, numeric_precision, numeric_scale, datetime_precision FROM information_schema.columns WHERE table_schema = ? AND table_name = ? ORDER BY ordinal_position", array($schema, $table));
|
||||
}
|
||||
|
||||
function getTableColumnsNames($schema, $table){
|
||||
$columns = array();
|
||||
foreach (getPrepareQuery("SELECT column_name FROM information_schema.columns WHERE table_schema = ? AND table_name = ? ORDER BY ordinal_position", array($schema, $table)) as $column) {
|
||||
$columns[] = $column['column_name'];
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
function getTableContentList($schema, $table, $offset = 0){
|
||||
global $config;
|
||||
//Note: check schema and table before !!!
|
||||
return getPrepareQuery("SELECT * FROM \"$schema\".\"$table\" LIMIT ".$config["limit_size"]." OFFSET ?", array($offset));
|
||||
}
|
||||
|
||||
function getTableCount($schema, $table){
|
||||
//Note: check schema and table before !!!
|
||||
return getQuery("SELECT COUNT(*) count FROM \"$schema\".\"$table\"")[0]["count"];
|
||||
}
|
||||
|
||||
function insertTableLine($schema, $table, $data){
|
||||
//REALLY UNSAFE
|
||||
//Note: check schema and table before !!!
|
||||
global $db;
|
||||
$sql = "INSERT INTO \"$schema\".\"$table\"(";
|
||||
$first = key($data);
|
||||
foreach ($data as $key => $value) {
|
||||
if($key !== $first) $sql .= ", ";
|
||||
$sql .= "\"$key\"";
|
||||
}
|
||||
$sql .= ") VALUES (";
|
||||
foreach ($data as $key => $value) {
|
||||
if($key !== $first) $sql .= ", ";
|
||||
$sql .= $db->quote($value);
|
||||
}
|
||||
$sql .= ")";
|
||||
return getQuery($sql);
|
||||
}
|
||||
|
||||
//render
|
||||
function printAssocTable($data, $fn){
|
||||
$str = '<table>';
|
||||
$str .= '<tr><th>'.implode('</th><th>', array_keys($data[0])).'</th></tr>';
|
||||
foreach($data as $row){
|
||||
$str .= '<tr>'.($fn != null ? fn($row) : '<td>'.implode('</td><td>', $row).'</td>').'</tr>';
|
||||
}
|
||||
return $str.'</table>';
|
||||
}
|
||||
|
||||
function checkSchema($schema){
|
||||
if($schema == null)
|
||||
return '<p class="error">Any schema selected</p>';
|
||||
|
||||
if(!in_array($schema, getSchemasList()))
|
||||
return '<p class="error">Unknown schema</p>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkTable($schema, $table){
|
||||
$check_schema = checkSchema($schema);
|
||||
if($check_schema !== true)
|
||||
return $check_schema;
|
||||
|
||||
if ($table == null)
|
||||
return '<p class="error">Any base selected</p>';
|
||||
|
||||
if (!in_array($table, getTablesListBySchema($schema)))
|
||||
return '<p class="error">Unknown base</p>';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function printCheck($check){
|
||||
if($check !== true)
|
||||
echo $check;
|
||||
|
||||
return $check === true;
|
||||
}
|
||||
|
||||
|
||||
function endsWith($haystack, $needle)
|
||||
{
|
||||
$length = strlen($needle);
|
||||
|
||||
return $length === 0 ||
|
||||
(substr($haystack, -$length) === $needle);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
if(!empty($_POST)){
|
||||
foreach ($_loginFields as $key) {
|
||||
if(isset($_POST[$key]))
|
||||
$_SESSION[$key] = $_POST[$key];
|
||||
}
|
||||
header("Location: .");
|
||||
}
|
||||
?>
|
||||
<h2>Connect</h2>
|
||||
<form action="." method="post">
|
||||
<p>
|
||||
<label for="string">String</label>
|
||||
<input type="text" name="db_string" id="string" placeholder="pgsql:host=localhost">
|
||||
</p>
|
||||
<p>
|
||||
<label for="name">Database</label>
|
||||
<input type="text" name="db_name" id="name">
|
||||
</p>
|
||||
<p>
|
||||
<label for="user">User</label>
|
||||
<input type="text" name="db_user" id="user">
|
||||
</p>
|
||||
<p>
|
||||
<label for="password">Password</label>
|
||||
<input type="password" name="db_password" id="password">
|
||||
</p>
|
||||
<p>
|
||||
<input type="submit" value="Go">
|
||||
</p>
|
||||
</form>
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
foreach ($_loginFields as $key)
|
||||
unset($_SESSION[$key]);
|
||||
?>
|
||||
<h2>Disconnected</h2>
|
|
@ -0,0 +1,2 @@
|
|||
<h2 class="error">Connection failed: <?= $_error ?></h2>
|
||||
<p><a href="?page=disconnect">Try reconnect</a></p>
|
|
@ -0,0 +1,10 @@
|
|||
<h2>Schema</h2>
|
||||
<?php if(printCheck(checkSchema($_schema))): ?>
|
||||
<p><?= $_schema ?></p>
|
||||
<table>
|
||||
<tr><th>Table</th></tr>
|
||||
<?php foreach(getTablesListBySchema($_schema) as $table):?>
|
||||
<tr><td><a href="?page=table&schema=<?= $_schema ?>&table=<?= $table ?>"><?= $table ?></a></td></tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
<?php endif ?>
|
|
@ -0,0 +1,7 @@
|
|||
<h2>Schemas</h2>
|
||||
<table>
|
||||
<tr><th>Schema</th></tr>
|
||||
<?php foreach(getSchemasList() as $schema):?>
|
||||
<tr><td><a href="?page=schema&schema=<?= $schema ?>"><?= $schema ?></a></td></tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
|
@ -0,0 +1,13 @@
|
|||
<h2>SQL</h2>
|
||||
<?php if(isset($_POST['sql'])):
|
||||
try{
|
||||
echo printAssocTable(getQuery($_POST['sql']), null);
|
||||
}catch(Exception $e){
|
||||
echo "<p class=\"error\">".$e->getMessage()."</p>";
|
||||
} ?>
|
||||
<?php else: ?>
|
||||
<form action="?page=sql" method="post">
|
||||
<p><textarea name="sql" id="sql" cols="30" rows="10" placeholder="SELECT * FROM ..."></textarea></p>
|
||||
<p><input type="submit" value="Run"></p>
|
||||
</form>
|
||||
<?php endif ?>
|
|
@ -0,0 +1,19 @@
|
|||
<h2>Table</h2>
|
||||
<?php if(printCheck(checkTable($_schema, $_table))): ?>
|
||||
<p><?= $_schema ?> : <?= $_table ?></p>
|
||||
<table>
|
||||
<tr><th>Column</th><th>Type</th><th>Nullable</th><th>Default</th></tr>
|
||||
<?php foreach (getTableColumnsList($_schema, $_table) as $column): ?>
|
||||
<tr>
|
||||
<td><?= $column['column_name'] ?></td>
|
||||
<td><?= $column['data_type'] //character_maximum_length, numeric_precision, numeric_scale, datetime_precision ?></td>
|
||||
<td><?= $column['is_nullable'] ?></td>
|
||||
<td><?= $column['column_default'] ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
<ul class="nav">
|
||||
<li><a href="?page=table_display&schema=<?= $_schema ?>&table=<?= $_table ?>">Display</a></li>
|
||||
<li><a href="?page=table_insert&schema=<?= $_schema ?>&table=<?= $_table ?>">Insert</a></li>
|
||||
</ul>
|
||||
<?php endif ?>
|
|
@ -0,0 +1,35 @@
|
|||
<h2>Table Display</h2>
|
||||
<?php if(printCheck(checkTable($_schema, $_table))):
|
||||
$pageCount = ceil(getTableCount($_schema, $_table) / $config['limit_size']);
|
||||
if($_offset < 0 || $_offset > $pageCount): ?>
|
||||
<p class="error">Offset out of range</p>
|
||||
<?php else: ?>
|
||||
<p><?= $_schema ?> : <?= $_table ?></p>
|
||||
<div>
|
||||
<p><?php if($_offset > 0): ?>
|
||||
<a href="?page=table_display&schema=<?= $_schema ?>&table=<?= $_table ?>&offset=<?= $_offset-1 ?>"><</a>
|
||||
<?php endif;
|
||||
echo ($_offset+1)." / ".($pageCount);
|
||||
if($_offset < $pageCount-1): ?>
|
||||
<a href="?page=table_display&schema=<?= $_schema ?>&table=<?= $_table ?>&offset=<?= $_offset+1 ?>">></a>
|
||||
<?php endif ?>
|
||||
</p>
|
||||
</div>
|
||||
<table>
|
||||
<?php $content = getTableContentList($_schema, $_table, $_offset*$config["limit_size"]); ?>
|
||||
<tr><th><?= implode('</th><th>', array_keys($content[0])) ?></th></tr>
|
||||
<?php foreach($content as $row): ?>
|
||||
<tr>
|
||||
<?php foreach ($row as $value): ?>
|
||||
<td><?= is_null($value) ? "<span class=\"null-val\">NULL</span>" : substr($value, 0, $config["display_length"]).(strlen($value) > $config["display_length"] ? '...' : '') ?></td>
|
||||
<?php endforeach
|
||||
/*<td><a href="?page=table_edit&schema=<?= $_schema ?>&table=<?= $_table ?>">✎</a></td>
|
||||
<td><a href="?page=table_remove&schema=<?= $_schema ?>&table=<?= $_table ?>">❌</a></td> */ ?>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
<ul class="nav">
|
||||
<li><a href="?page=table&schema=<?= $_schema ?>&table=<?= $_table ?>">Back</a></li>
|
||||
<li><a href="?page=table_insert&schema=<?= $_schema ?>&table=<?= $_table ?>">Insert</a></li>
|
||||
</ul>
|
||||
<?php endif; endif ?>
|
|
@ -0,0 +1,38 @@
|
|||
<h2>Table Insert</h2>
|
||||
<?php if(printCheck(checkTable($_schema, $_table))):
|
||||
$columns = getTableColumnsNames($_schema, $_table); ?>
|
||||
<p><?= $_schema ?> : <?= $_table ?></p>
|
||||
<?php if(!empty($_POST)):
|
||||
try{
|
||||
$data = array();
|
||||
foreach ($_POST as $key => $value) {
|
||||
if(!endsWith($key, "-null")){
|
||||
if(!in_array($key, $columns))
|
||||
throw new Exception("Wrong column name : ".htmlspecialchars($key));
|
||||
|
||||
if(!isset($_POST[$key.'-null']))
|
||||
$data[$key] = $value;
|
||||
}
|
||||
}
|
||||
insertTableLine($_schema, $_table, $data);
|
||||
echo "<p>Insertion complete</p>";
|
||||
}catch(Exception $e){
|
||||
echo "<p class=\"error\">".$e->getMessage()."</p>";
|
||||
} ?>
|
||||
<?php else: ?>
|
||||
<form action="?page=table_insert&schema=<?= $_schema ?>&table=<?= $_table ?>" method="post">
|
||||
<?php foreach ($columns as $column): ?>
|
||||
<p>
|
||||
<label for="<?= $column ?>"><?= $column ?></label>
|
||||
<input type="text" name="<?= $column ?>" id="<?= $column ?>">
|
||||
<br><input type="checkbox" name="<?= $column ?>-null"> NULL
|
||||
</p>
|
||||
<?php endforeach ?>
|
||||
<input type="submit" value="Save">
|
||||
</form>
|
||||
<?php endif ?>
|
||||
<ul class="nav">
|
||||
<li><a href="?page=table&schema=<?= $_schema ?>&table=<?= $_table ?>">Back</a></li>
|
||||
<li><a href="?page=table_display&schema=<?= $_schema ?>&table=<?= $_table ?>">Display</a></li>
|
||||
</ul>
|
||||
<?php endif ?>
|
|
@ -0,0 +1,10 @@
|
|||
<h2>Tables</h2>
|
||||
<table border="1">
|
||||
<tr><th>Schema</th><th>Table</th></tr>
|
||||
<?php foreach (getTablesList() as $table): ?>
|
||||
<tr>
|
||||
<td><a href="?page=schema&schema=<?= $table['table_schema'] ?>"><?= $table['table_schema'] ?></a></td>
|
||||
<td><a href="?page=table&schema=<?= $table['table_schema'] ?>&table=<?= $table['table_name'] ?>"><?= $table['table_name'] ?></a></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>DB Xplorer - <?= $_page ?></title>
|
||||
</head>
|
||||
<body><div id="content">
|
||||
<header>
|
||||
<?php if(!empty($_SESSION)): ?><p class="logout"><a href="?page=disconnect">🚪</a></p><?php endif ?>
|
||||
<h1><a href="./">DB Xplorer</a></h1>
|
||||
</header>
|
||||
<nav>
|
||||
<p><ul>
|
||||
<li><a href="?page=schemas">Schemas</a></li>
|
||||
<li><a href="?page=tables">Tables</a></li>
|
||||
<li><a href="?page=sql">SQL</a></li>
|
||||
</ul></p>
|
||||
</nav>
|
||||
<section>
|
||||
<?php
|
||||
|
||||
if(in_array($_page, array('sql', 'connect', 'disconnect', 'fail', 'schemas', 'schema', 'tables', 'table', 'table_display', 'table_insert')))
|
||||
include("pages/$_page.php");
|
||||
else
|
||||
echo "<p>A minimal, unsafe and maybe usefull sql database explorer</p>";
|
||||
?>
|
||||
</section>
|
||||
<footer>
|
||||
<p>2018 © Bois Clément</p>
|
||||
</footer>
|
||||
</div></body>
|
||||
</html>
|
|
@ -0,0 +1,99 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.null-val {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
header, footer, nav {
|
||||
background: #333;
|
||||
padding: 10px;
|
||||
color: white;
|
||||
}
|
||||
header a, footer a, nav a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
header .logout {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
nav {
|
||||
border-top: 2px solid #555;
|
||||
}
|
||||
nav ul, section .nav {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0 10%;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
section {
|
||||
flex: 1;
|
||||
margin: 20px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
section a {
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
section p {
|
||||
margin: 5px;
|
||||
}
|
||||
section a:hover {
|
||||
text-decoration-style: dashed;
|
||||
}
|
||||
section table{
|
||||
margin: 20px auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
section td, section th {
|
||||
border: 1px solid black;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
section label {
|
||||
display: inline-block;
|
||||
min-width: 10%;
|
||||
text-align: right;
|
||||
padding: 2px;
|
||||
}
|
||||
section [type="submit"] {
|
||||
padding: 2px 10px;
|
||||
}
|
||||
section .nav{
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
section .nav:before{
|
||||
content: "";
|
||||
flex: 1;
|
||||
}
|
Reference in New Issue