316 lines
9.0 KiB
PHP
316 lines
9.0 KiB
PHP
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Execute Query</title>
|
||
<style>
|
||
:root {
|
||
--bg: #f6f7fb;
|
||
--card: #fff;
|
||
--border: #e5e7eb;
|
||
--text: #0f172a;
|
||
--muted: #64748b;
|
||
--accent: #2563eb;
|
||
}
|
||
|
||
html, body {
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
font: 14px/1.5 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
|
||
margin: 0;
|
||
}
|
||
|
||
.page {
|
||
max-width: 1100px;
|
||
margin: 28px auto; /* page margin */
|
||
padding: 0 18px;
|
||
}
|
||
|
||
.card {
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: 12px;
|
||
box-shadow: 0 1px 3px rgba(0,0,0,.04);
|
||
padding: 16px;
|
||
}
|
||
|
||
h2, h3 { margin: 0 0 12px; }
|
||
|
||
/* Query area layout */
|
||
.query-wrap { display: grid; gap: 12px; }
|
||
.toolbar {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
gap: 12px;
|
||
justify-content: space-between; /* left/right split */
|
||
}
|
||
.toolbar-left { display: flex; align-items: center; gap: 12px; }
|
||
.toolbar-right { display: flex; align-items: center; gap: 10px; }
|
||
|
||
textarea#query {
|
||
width: 100%;
|
||
min-height: 160px;
|
||
resize: vertical;
|
||
box-sizing: border-box;
|
||
padding: 12px 14px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
background: #fff;
|
||
font: 13px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||
}
|
||
|
||
.btn {
|
||
display: inline-block;
|
||
padding: 8px 14px;
|
||
border-radius: 10px;
|
||
border: 1px solid var(--border);
|
||
background: var(--accent);
|
||
color: #fff;
|
||
cursor: pointer;
|
||
}
|
||
.btn.secondary {
|
||
background: #fff;
|
||
color: var(--text);
|
||
}
|
||
|
||
label.small { color: var(--muted); font-size: 13px; user-select: none; }
|
||
|
||
/* Saved queries */
|
||
.query-select {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
padding: 10px 12px;
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
background: #fff;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* Results */
|
||
.results { margin-top: 16px; }
|
||
.results-header {
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
margin: 4px 0 12px;
|
||
}
|
||
.results-meta { color: var(--muted); font-size: 13px; }
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
border: 1px solid var(--border);
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
background: #fff;
|
||
font-size: 13px;
|
||
}
|
||
th, td { padding: 8px 10px; border-bottom: 1px solid var(--border); text-align: left; }
|
||
th { background: #f2f4f7; }
|
||
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
||
|
||
.csv-box {
|
||
width: 100%; height: 360px; resize: vertical;
|
||
white-space: pre; overflow: auto;
|
||
font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||
background: #0b1020; color: #e5e7eb;
|
||
border: 1px solid #111827; border-radius: 10px; padding: 12px;
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
// JavaScript function to populate the textarea with the clicked query
|
||
function populateQuery(query) {
|
||
document.getElementById('query').value = query;
|
||
}
|
||
function copyCsv(id) {
|
||
const ta = document.getElementById(id);
|
||
ta.focus();
|
||
ta.select();
|
||
document.execCommand('copy');
|
||
}
|
||
</script>
|
||
</head>
|
||
<body>
|
||
|
||
<?php
|
||
// Allowed IP address
|
||
$allowed_ip1 = '47.45.92.162';
|
||
$ip2 = '207.62.201.30';
|
||
$ip3 = '192.168.1.70';
|
||
|
||
function get_client_ip() {
|
||
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||
// It may contain multiple IPs separated by commas, so we take the first one
|
||
$ip_list = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
|
||
$ip = trim($ip_list[0]);
|
||
} elseif (isset($_SERVER['HTTP_X_REAL_IP'])) {
|
||
// Some proxies may use this header
|
||
$ip = $_SERVER['HTTP_X_REAL_IP'];
|
||
} else {
|
||
// Fallback to REMOTE_ADDR
|
||
$ip = $_SERVER['REMOTE_ADDR'];
|
||
}
|
||
return $ip;
|
||
}
|
||
|
||
// Get client IP address
|
||
$client_ip = get_client_ip();
|
||
|
||
// Check if the incoming IP address matches the allowed IP
|
||
if ($client_ip !== $allowed_ip1 && $client_ip !== $ip2 && $client_ip !== $ip3) {
|
||
die("Access denied. Unauthorized IP address.");
|
||
}
|
||
?>
|
||
|
||
<div class="page">
|
||
<div class="card">
|
||
<h2>Execute Query</h2>
|
||
|
||
<form method="post" action="" class="query-wrap">
|
||
<textarea id="query" name="query" placeholder="Enter your MySQL query here"><?php
|
||
echo isset($_POST['query']) ? htmlspecialchars($_POST['query']) : '';
|
||
?></textarea>
|
||
|
||
<div class="toolbar">
|
||
<div class="toolbar-left">
|
||
<label class="small">
|
||
<input type="checkbox" name="csv_output" value="1" <?php
|
||
echo !empty($_POST['csv_output']) ? 'checked' : '';
|
||
?>> CSV output
|
||
</label>
|
||
</div>
|
||
|
||
<div class="toolbar-right">
|
||
<button type="submit" name="submit" class="btn">Execute Query</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="card" style="margin-top:16px;">
|
||
<h3>Available Queries</h3>
|
||
<?php
|
||
$file = 'queries.txt';
|
||
if (file_exists($file)) {
|
||
$queries = file($file, FILE_IGNORE_NEW_LINES);
|
||
echo '<select id="querySelect" class="query-select" onchange="populateQuery(this.value)">';
|
||
echo '<option value="">Select a query...</option>';
|
||
foreach ($queries as $line) {
|
||
list($label, $q) = explode('|', $line, 2);
|
||
echo '<option value="' . htmlspecialchars($q) . '">' . htmlspecialchars($label) . '</option>';
|
||
}
|
||
echo '</select>';
|
||
} else {
|
||
echo "<p>{$file} file not found.</p>";
|
||
}
|
||
?>
|
||
|
||
<div class="results">
|
||
<?php
|
||
if (isset($_POST['submit'])) {
|
||
// Connection parameters (adjust for your MySQL server)
|
||
include_once("peter_db.php");
|
||
$peter_db = new peter_db();
|
||
$conn = $peter_db->getConnection();
|
||
|
||
if ($conn->connect_error) {
|
||
die("Connection failed: " . $conn->connect_error);
|
||
}
|
||
|
||
$query = $_POST['query'] ?? '';
|
||
$as_csv = !empty($_POST['csv_output']);
|
||
|
||
// Helper: CSV line builder (RFC 4180 style quoting)
|
||
$csv_line = function(array $vals): string {
|
||
$out = [];
|
||
foreach ($vals as $v) {
|
||
if ($v === null) {
|
||
$out[] = '';
|
||
continue;
|
||
}
|
||
$s = (string)$v;
|
||
// Normalize line breaks
|
||
$s = str_replace(["\r\n", "\r"], "\n", $s);
|
||
// Escape double quotes by doubling them
|
||
if (strpbrk($s, ",\"\n") !== false) {
|
||
$s = '"' . str_replace('"', '""', $s) . '"';
|
||
}
|
||
$out[] = $s;
|
||
}
|
||
return implode(',', $out);
|
||
};
|
||
|
||
// Split on semicolons (simple splitter; won’t handle semicolons inside strings)
|
||
$queries = array_filter(array_map('trim', explode(';', $query)));
|
||
|
||
foreach ($queries as $sql) {
|
||
if ($sql === '') { continue; }
|
||
|
||
echo "<p><code>" . htmlspecialchars($sql) . "</code></p>";
|
||
|
||
$result = $conn->query($sql);
|
||
|
||
if ($result === FALSE) {
|
||
echo "<p>Error: " . htmlspecialchars($conn->error) . "</p>";
|
||
} elseif ($result === TRUE) {
|
||
echo "<p>Query executed successfully.</p>";
|
||
} else {
|
||
// SELECT-like result
|
||
if ($as_csv) {
|
||
// Build header
|
||
$fields = $result->fetch_fields();
|
||
$headers = array_map(fn($f) => $f->name, $fields);
|
||
$csv = [];
|
||
$csv[] = $csv_line($headers);
|
||
|
||
// Rows
|
||
while ($row = $result->fetch_assoc()) {
|
||
// Preserve column order per $headers
|
||
$vals = [];
|
||
foreach ($headers as $h) { $vals[] = $row[$h]; }
|
||
$csv[] = $csv_line($vals);
|
||
}
|
||
|
||
$csv_text = implode("\n", $csv) . "\n";
|
||
|
||
// Show in a textarea for easy copy without HTML escaping issues
|
||
// Adjust rows/cols as you like
|
||
$rows = min(40, max(10, count($csv) + 2));
|
||
echo '<textarea readonly rows="' . $rows . '" cols="120">'
|
||
. htmlspecialchars($csv_text)
|
||
. '</textarea><br><br>';
|
||
} else {
|
||
// HTML table
|
||
echo "<table border='1'><tr>";
|
||
$fields = $result->fetch_fields();
|
||
foreach ($fields as $field) {
|
||
echo "<th>" . htmlspecialchars($field->name) . "</th>";
|
||
}
|
||
echo "</tr>";
|
||
|
||
while ($row = $result->fetch_assoc()) {
|
||
echo "<tr>";
|
||
foreach ($row as $value) {
|
||
echo "<td>" . htmlspecialchars((string)$value) . "</td>";
|
||
}
|
||
echo "</tr>";
|
||
}
|
||
echo "</table><br><br>";
|
||
}
|
||
}
|
||
}
|
||
|
||
$conn->close();
|
||
}
|
||
?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function populateQuery(q) { document.getElementById('query').value = q; }
|
||
</script>
|
||
</body>
|
||
</html>
|