<?php


/***********************************************************************
    Copyright (c) 2008 Alexander Breckel

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.
***********************************************************************/


define('NAME''LiteAdmin');
define('VERSION''0.1');
define('HOMEPAGE''http://aneas.org/projects/liteadmin');


/***********************************************************************
 * CONFIGURATION *******************************************************
 **********************************************************************/


// please don't change the syntax, as this will be automatically parsed
define('USERNAME''');
define('PASSWORD''');
define('DEFAULT_DATABASE''');
define('SEARCH_FOR_DATABASES'true);
define('SEARCH_DEPTH', -1);


/***********************************************************************
 * NOT INTERESTING *****************************************************
 **********************************************************************/


//set_time_limit(0);
error_reporting(E_ALL);
session_name('sid');
session_start();


// remove magic quotes
function stripslashes_deep($value) {
    return 
is_array($value) ? array_map('stripslashes_deep'$value) : stripslashes($value); // keys won't! be stripped
}

if(
get_magic_quotes_gpc()) {
    
$_POST array_map('stripslashes_deep'$_POST);
    
$_GET array_map('stripslashes_deep'$_GET);
    
$_COOKIE array_map('stripslashes_deep'$_COOKIE);
    
$_REQUEST array_map('stripslashes_deep'$_REQUEST);
    
ini_set('magic_quotes_gpc'false); // disable it for later use in parse_str
}

magic_quotes_runtime(0);


// login procedure
if((USERNAME != '' || PASSWORD != '') && (!isset($_SESSION['s_logged_in']) || $_SESSION['s_logged_in'] !== true) && (!isset($_REQUEST['action']) || $_REQUEST['action'] !== 'login'))
    
redirect('login');


// open a db connection
unset($db$database);
if(isset(
$_REQUEST['database'])) {
    
$database $_REQUEST['database'];
    try {
        
$db open_database($database);
    } catch(
Exception $e) {
        
error('could not open database "' htmlspecialchars($database) . '"');
        
redirect();
    }
}


// front controller
if(isset($_REQUEST['action']) && function_exists('action_' $_REQUEST['action']))
    
call_user_func('action_' $_REQUEST['action']);
else {
    if(isset(
$_REQUEST['action']) && $_REQUEST['action'] !== '')
        
notice('Unknown action "' htmlspecialchars($_REQUEST['action']) . '", redirecting...');
    
action_default();
}


/***********************************************************************
 * ACTIONS *************************************************************
 **********************************************************************/


// index page with db select and various functions
function action_default() {
    
$path = isset($_REQUEST['path']) ? $_REQUEST['path'] : './';

    if(
is_file($path))
        
redirect('database', array('database' => $path));
    elseif(
strlen($path) > && $path[strlen($path) - 1] != '/')
        
$path .= '/';

    
$directories = array();
    
$files = array();
    
$directory dir($path);
    while((
$entry $directory->read()) !== false) {
        if(
$entry === '.')
            continue;
        elseif(
is_dir($path $entry))
            
$directories[] = $path $entry;
        else
            
$files[] = $path $entry;
    }
    
natcasesort($directories);
    
natcasesort($files);

    
$layout = new Layout;
    
$layout->header();

    echo 
'<strong>Location:</strong> ';
    
$pos1 0;
    while((
$pos2 strpos($path'/'$pos1)) !== false) {
        echo 
'<a href="' url('default', array('path' => substr($path0$pos2))) . '">' htmlspecialchars(substr($path$pos1$pos2 $pos1)) . '</a> / ';
        
$pos1 $pos2 1;
    }

    echo 
'<table class="files" cellspacing="0">';
    echo 
'<thead>';
        echo 
'<tr>';
            echo 
'<th>Name</th>';
            echo 
'<th>Size</th>';
            echo 
'<th>Rights</th>';
        echo 
'</tr>';
    echo 
'</thead>';
    echo 
'<tbody>';

    if(!empty(
$directories)) {
        
$i 0;
        foreach(
$directories as $entry) {
            echo 
'<tr class="directory ' . ($i++ % == 'even' 'odd') . '">';
                echo 
'<td><a href="' url('default', array('path' => $entry)) . '">' basename($entry) . '</a></td>';
                echo 
'<td>&nbsp;</td>';
                echo 
'<td>' format_fileperms(fileperms($entry)) . '</td>';
            echo 
'</tr>';
        }
        echo 
'<tr class="divider"><td colspan="3"></td></tr>';
    }

    if(!empty(
$files)) {
        
$i 0;
        foreach(
$files as $entry) {
            echo 
'<tr class="file ' . ($i++ % == 'even' 'odd') . '">';
                echo 
'<td><a href="' url('default', array('path' => $entry)) . '">' basename($entry) . '</a></td>';
                echo 
'<td class="filesize">' format_filesize(filesize($entry)) . '</td>';
                echo 
'<td class="fileperms">' format_fileperms(fileperms($entry)) . '</td>';
            echo 
'</tr>';
        }
    }

    echo 
'</tbody>';
    echo 
'</table>';

    
$layout->footer();
}


function 
action_create_database() {
    if(isset(
$_REQUEST['filename'])) {
        if(empty(
$_REQUEST['filename']))
            
error('empty filename');
        elseif(
file_exists($_REQUEST['filename']))
            
error('file "' $_REQUEST['filename'] . '" already exists');
        elseif(
sqlite_open($_REQUEST['filename'], 0666$error_message) === false)
            
error($error_message);
        else {
            
notice('created database "' htmlspecialchars($_REQUEST['filename']) . '"');
            
redirect('database', array('database' => $_REQUEST['filename']));
        }
    }

    
$layout = new Layout;
    
$layout->set_title('create db');
    
$layout->add_location('create database');
    
$layout->header();

    
?>
        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="create_database" />
            <div class="form_line"><label for="filename">Filename:</label> <input type="text" class="text" name="filename" id="filename" value="<?php echo @htmlspecialchars($_REQUEST['filename']); ?>" /></div>
            <div class="submit"><input type="submit" value="create" /></div>
        </form>
    <?php

    $layout
->footer();
}


function 
action_database() {
    global 
$db$database;

    
$layout = new Layout;
    
$layout->set_title('db ' basename($database));
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->header();

    echo 
'<strong>Tables:</strong>';
    echo 
'<table class="tables" cellspacing="0">';
    echo 
'<thead>';
        echo 
'<tr>';
            echo 
'<th>Name</th>';
            echo 
'<th>Rows</th>';
            echo 
'<th>&nbsp;</th>';
        echo 
'</tr>';
    echo 
'</thead>';
    echo 
'<tbody>';
        
$result $db->query('SELECT name FROM sqlite_master WHERE type="table" ORDER BY name');
        
$i 0;
        while(
$row $result->fetch()) {
            echo 
'<tr class="' . ($i++ % == 'even' 'odd') . '">';
            echo 
'<td><a href="' url('table', array('database' => $database'table' => $row['name'])) . '">' $row['name'] . '</a></td>';
            echo 
'<td class="number">' row_count($db$row['name']) . '</td>';
            echo 
'<td>';
                echo 
'<a href="' url('table', array('database' => $database'table' => $row['name'])) . '">structure</a>, ';
                echo 
'<a href="' url('show_table', array('database' => $database'table' => $row['name'])) . '">browse</a>, ';
                echo 
'<a href="' url('query', array('database' => $database'table' => $row['name'])) . '">query</a>, ';
                echo 
'<a href="' url('truncate', array('database' => $database'table' => $row['name'])) . '">truncate</a>, ';
                echo 
'<a href="' url('drop_table', array('database' => $database'table' => $row['name'])) . '">drop</a>';
            echo 
'</td>';
            echo 
'</tr>';
        }
    echo 
'</tbody>';
    echo 
'</table>';

    
$layout->footer();
}


function 
action_create_table() {
    global 
$db$database;

    
$column_types = array('INTEGER''INTEGER PRIMARY KEY''VARCHAR''TEXT''DATETIME''REAL''BLOB');

    if(isset(
$_REQUEST['name'], $_REQUEST['columns'])) {
        if(empty(
$_REQUEST['name']))
            
error('empty table name');
        elseif(!
is_array($_REQUEST['columns']))
            
error('empty table columns');
        elseif(
table_exists($db$_REQUEST['name']))
            
error('table "' htmlspecialchars($_REQUEST['name']) . '" already exists');
        else {
            
$query_columns '';
            foreach(
$_REQUEST['columns'] as $column) {
                if(empty(
$column['name']))
                    continue;

                if(
$query_columns !== '')
                    
$query_columns .= ', ';

                
$query_columns .= '"' sqlite_escape_string($column['name']) . '"';
                if(
in_array($column['type'], $column_types))
                    
$query_columns .= ' ' $column['type'];
            }

            
$query 'CREATE TABLE ';
            if(@
$_REQUEST['if_not_exists'] == 1)
                
$query .= 'IF NOT EXISTS ';
            
$query .= '"' sqlite_escape_string($_REQUEST['name']) . '" (' $query_columns ')';

            if(!@
$db->queryExec($query)) {
                
error_query($query);
                
error(sqlite_error_string($db->lastError()));
            }
            else {
                
notice('created table "' htmlspecialchars($_REQUEST['name']) . '"');
                
notice_query($query'using this query:');
                
redirect('table', array('database' => $database'table' => $_REQUEST['name']));
            }
        }
    }

    
$layout = new Layout;
    
$layout->set_title('create table');
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location('create table');
    
$layout->header();

    
?>
        <form method="get" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="create_table" />
            <input type="hidden" name="database" value="<?php echo @htmlspecialchars($database); ?>" />
            <div class="form_line"><label for="name">Name:</label> <input type="text" class="text" name="name" id="name" value="<?php echo @htmlspecialchars($_REQUEST['name']); ?>" /></div>
            <div id="table_columns">
                <?php
                
if(isset($_REQUEST['columns'])) {
                    for(
$i 0$i count($_REQUEST['columns']); $i++) {
                        echo 
'<div class="table_column">';
                        echo 
'<input type="text" class="text" name="columns[' $i '][name]" value="' . @htmlspecialchars($_REQUEST['columns'][$i]['name']) . '" />';
                        echo 
'<select name="columns[' $i '][type]">';
                        foreach(
$column_types as $type)
                            echo 
'<option' . (@$_REQUEST['columns'][$i]['type'] == $type ' selected="selected"' '') . '>' $type '</option>';
                        echo 
'</select>';
                        echo 
'</div>';
                    }
                }
                
?>
            </div>
            <script type="text/javascript">
                var next_table_column_id = <?php echo (int)@count($_REQUEST['columns']); ?>;
                function new_table_column() {
                    var html = '<div class="table_column">';
                    html += '<input type="text" class="text" name="columns[' + next_table_column_id + '][name]" />';
                    html += '<select name="columns[' + next_table_column_id + '][type]">';
                    html += '<option><?php echo join('</option><option>'$column_types); ?></option>';
                    html += '</select>';
                    html += '</div>';
                    document.getElementById('table_columns').innerHTML += html;
                    next_table_column_id++;
                }
                <?php if(!isset($_REQUEST['columns'])) { ?>
                for(var i = 0; i < 8; i++)
                    new_table_column();
                <?php ?>
            </script>
            <a href="#" onclick="new_table_column(); return false;">new table column</a>
            <div class="form_line"><input type="checkbox" class="checkbox" name="if_not_exists" id="if_not_exists" value="1" <?php if(@$_REQUEST['if_not_exists'] == 1) echo ' checked="checked"'?> /> <label for="if_not_exists">IF NOT EXISTS</label></div>
            <div class="submit"><input type="submit" value="create" /></div>
        </form>
    <?php

    $layout
->footer();
}


function 
action_create_index() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);

    if(@empty(
$_REQUEST['index']))
        
error('empty index name');
    elseif(!@
is_array($_REQUEST['columns']))
        
error('empty index columns');
    elseif(
table_exists($db$_REQUEST['index']))
        
error('a table called "' htmlspecialchars($_REQUEST['index']) . '" already exists');
    elseif(
index_exists($db$_REQUEST['index']))
        
error('an index called "' htmlspecialchars($_REQUEST['index']) . '" already exists');
    else {
        
$query 'CREATE INDEX "' sqlite_escape_string($_REQUEST['index']) . '" ON "' sqlite_escape_string($_REQUEST['table']) . '" (';
        
$i 0;
        foreach(
$_REQUEST['columns'] as $column)
            if(!empty(
$column))
                
$query .= ($i++ > ', ' '') . '"' sqlite_escape_string($column) . '"';
        
$query .= ')';

        if(!@
$db->queryExec($query)) {
            
error_query($query);
            
error(sqlite_error_string($db->lastError()));
        }
        else {
            
notice('created index "' htmlspecialchars($_REQUEST['index']) . '"');
            
notice_query($query'using this query:');
        }
    }
    
redirect('table', array('database' => $database'table' => $table));
}


function 
action_table() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);

    
$layout = new Layout;
    
$layout->set_title('table ' $table);
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location($tableurl('table', array('database' => $database'table' => $table)));
    
$layout->header();

    echo 
row_count($db$table) . ' rows';
    echo 
'<br /><br />';

    echo 
'<strong>Columns:</strong>';
    echo 
'<form method="post" action="' $_SERVER['PHP_SELF'] . '">';
    echo 
'<input type="hidden" name="action" value="create_index" />';
    echo 
'<input type="hidden" name="database" value="' . @htmlspecialchars($database) . '" />';
    echo 
'<input type="hidden" name="table" value="' . @htmlspecialchars($table) . '" />';
    echo 
'<table class="columns" cellspacing="0">';
    echo 
'<thead>';
        echo 
'<tr>';
            echo 
'<th>&nbsp;</th>';
            echo 
'<th>Name</th>';
            echo 
'<th>Type</th>';
            echo 
'<th>NULL</th>';
            echo 
'<th>Default</th>';
        echo 
'</tr>';
    echo 
'</thead>';
    echo 
'<tbody>';
        
$columns column_list($db$table);
        
$i 0;
        foreach(
$columns as $column) {
            echo 
'<tr class="' . ($i++ % == 'even' 'odd') . '">';
                echo 
'<td><input type="checkbox" name="columns[]" value="' htmlspecialchars($column['name']) . '" /></td>';
                echo 
'<td>' htmlspecialchars($column['name']) . '</td>';
                echo 
'<td>' htmlspecialchars($column['type']) . ($column['pk'] ? ' PRIMARY KEY' '') . '</td>';
                echo 
'<td>' . ($column['notnull'] ? 'no' 'yes') . '</td>';
                echo 
'<td>' htmlspecialchars($column['dflt_value']) . '</td>';
            echo 
'</tr>';
        }
    echo 
'</tbody>';
    echo 
'</table>';
    echo 
'create an index called <input type="text" class="text" name="index" /> <input type="submit" value="create" />';
    echo 
'</form>';
    echo 
'<br />';

    
$indices index_list($db$table);
    echo 
'<strong>Indices:</strong>';
    echo 
'<table class="indices" cellspacing="0">';
    echo 
'<thead>';
        echo 
'<tr>';
            echo 
'<th>Name</th>';
            echo 
'<th>Unique</th>';
            echo 
'<th>Columns</th>';
            echo 
'<th>&nbsp;</th>';
        echo 
'</tr>';
    echo 
'</thead>';
    echo 
'<tbody>';
        
$i 0;
        foreach(
$indices as $index) {
            echo 
'<tr class="' . ($i++ % == 'even' 'odd') . '">';
                echo 
'<td>' htmlspecialchars($index['name']) . '</td>';
                echo 
'<td>' . ($index['unique'] ? 'no' 'yes') . '</td>';
                echo 
'<td>' htmlspecialchars(join(', '$index['columns'])) . '</td>';
                echo 
'<td><a href="' url('drop_index', array('database' => $database'table' => $table'index' => $index['name'])) . '">drop</a></td>';
            echo 
'</tr>';
        }
    echo 
'</tbody>';
    echo 
'</table>';
    echo 
'<br />';

    echo 
'<strong>SQL used to create:</strong>';
    echo 
'<div class="query">';
    
$result $db->query('SELECT sql FROM sqlite_master WHERE type="table" AND name="' sqlite_escape_string($table) . '"');
    echo 
highlight_sql($result->fetchSingle() . ';') . '<br />';
    
$result $db->query('SELECT sql FROM sqlite_master WHERE type="index" AND tbl_name="' sqlite_escape_string($table) . '"');
    while(
$row $result->fetch())
        echo 
highlight_sql($row['sql'] . ';') . '<br />';
    echo 
'</div>';

    
$layout->footer();
}


function 
action_show_table() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);

    
$layout = new Layout;
    
$layout->set_title('table ' $table);
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location($tableurl('table', array('database' => $database'table' => $table)));
    
$layout->add_location('browse'url('show_table', array('database' => $database'table' => $table)));
    
$layout->header();

    if(
has_primary_key($db$table)) {
        
$query 'SELECT * FROM "' sqlite_escape_string($table) . '"';
        
$primary_key get_primary_key($db$table);
    }
    else {
        
$query 'SELECT _ROWID_, * FROM "' sqlite_escape_string($table) . '"';
        
$primary_key '_ROWID_';
    }

    echo 
'<div class="query">' highlight_sql($query) . '</div>';
    echo 
'<br />';

    
$begin microtime(true);
    
$result $db->query($query);
    
$end microtime(true);

    echo 
$result->numRows() . ' rows, ' sprintf('%f'$end $begin) . ' seconds';

    
$fields $result->numFields();
    echo 
'<table class="result" cellspacing="0">';
        echo 
'<thead>';
            echo 
'<tr>';
                echo 
'<th>&nbsp;</th>';
                for(
$i 0$i $fields$i++)
                    echo 
'<th>' htmlspecialchars($result->fieldName($i)) . '</th>';
            echo 
'</tr>';
        echo 
'</thead>';
        echo 
'<tbody>';
            
$j 0;
            while(
$row $result->fetch()) {
                echo 
'<tr class="' . ($j++ % == 'even' 'odd') . '">';
                echo 
'<td>';
                    echo 
'<a href="' url('update_row', array('database' => $database'table' => $table'rowid' => $row[$primary_key])) . '">[U]</a> ';
                    echo 
'<a href="' url('delete_row', array('database' => $database'table' => $table'rowid' => $row[$primary_key])) . '">[D]</a>';
                echo 
'</td>';
                for(
$i 0$i $fields$i++)
                    echo 
'<td>' htmlspecialchars($row[$i]) . '</td>';
                echo 
'</tr>';
            }
        echo 
'</tbody>';
    echo 
'</table>';

    
$layout->footer();
}


function 
action_query() {
    global 
$db$database;

    if(isset(
$_REQUEST['table'])) {
        
$table $_REQUEST['table'];
        if(!
table_exists($db$table)) {
            
error('table `' htmlspecialchars($table) . '` does not exist');
            
redirect('database', array('database' => $database));
        }
    }

    if(isset(
$_REQUEST['query'])) {
        
$result = @$db->query($_REQUEST['query'], SQLITE_NUM$error_message);
        if(
$result === false)
            
error($error_message);
    }

    
$layout = new Layout;
    if(isset(
$_REQUEST['table']))
        
$layout->set_title('query ' $table);
    else
        
$layout->set_title('query ' basename($database));
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    if(isset(
$_REQUEST['table'])) {
        
$layout->add_location($tableurl('table', array('database' => $database'table' => $table)));
        if(isset(
$_REQUEST['query']))
            
$layout->add_location('query'url('query', array('database' => $database'table' => $table'query' => $_REQUEST['query'])));
        else
            
$layout->add_location('query'url('query', array('database' => $database'table' => $table)));
    }
    else {
        if(isset(
$_REQUEST['query']))
            
$layout->add_location('query'url('query', array('database' => $database'query' => $_REQUEST['query'])));
        else
            
$layout->add_location('query'url('query', array('database' => $database)));
    }
    
$layout->header();

    
?>
        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="query" />
            <input type="hidden" name="database" value="<?php echo @htmlspecialchars($database); ?>" />
            <?php if(isset($_REQUEST['table'])) echo '<input type="hidden" name="table" value="' htmlspecialchars($table) . '" />'?>
            <textarea class="query" name="query" id="query"><?php echo (isset($_REQUEST['query']) || !isset($table)) ? @htmlspecialchars($_REQUEST['query']) : 'SELECT * FROM "' htmlspecialchars($table) . '" WHERE 1'?></textarea>
            <div class="submit"><input type="submit" value="query" /></div>
        </form>
    <?php

    
if(isset($_REQUEST['query'])) {
        if(@
$result->numRows() > 0) {
            echo 
'<br />';
            echo 
'<table class="result" cellspacing="0">';

            echo 
'<thead>';
            echo 
'<tr>';
            
$fields $result->numFields();
            for(
$i 0$i $fields$i++)
                echo 
'<th>' htmlspecialchars($result->fieldName($i)) . '</th>';
            echo 
'</tr>';
            echo 
'</thead>';

            echo 
'<tbody>';
            
$j 0;
            while(
$row $result->fetch()) {
                echo 
'<tr class="' . ($j++ % == 'even' 'odd') . '">';
                for(
$i 0$i $fields$i++)
                    echo 
'<td>' htmlspecialchars($row[$i]) . '</td>';
                echo 
'</tr>';
            }
            echo 
'</tbody>';

            echo 
'</table>';
        }
        else {
            echo 
'empty';
        }
    }

    
$layout->footer();
}


function 
action_truncate() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);

    
$query 'DELETE FROM "' sqlite_escape_string($table) . '";';

    if(isset(
$_REQUEST['sure'])) {
        if(!@
$db->queryExec($query)) {
            
error_query($query);
            
error(sqlite_error_string($db->lastError()));
        }
        else {
            
notice('truncated "' htmlspecialchars($table) . '"');
            
notice_query($query'using this query:');
            
redirect('table', array('database' => $database'table' => $table));
        }
    }

    
$layout = new Layout;
    
$layout->set_title('truncate table');
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location($tableurl('table', array('database' => $database'table' => $table)));
    
$layout->add_location('truncate'url('truncate', array('database' => $database'table' => $table)));
    
$layout->header();

    
?>
        This will be executed:<br />
        <div class="query"><?php echo highlight_sql($query); ?></div>
        <br />

        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="truncate" />
            <input type="hidden" name="database" value="<?php echo @htmlspecialchars($database); ?>" />
            <input type="hidden" name="table" value="<?php echo @htmlspecialchars($table); ?>" />
            <input type="hidden" name="sure" value="1" />
            <div class="submit">Are you sure? <input type="submit" value="yes, delete all content" /></div>
        </form>
    <?php

    $layout
->footer();
}


function 
action_vacuum() {
    global 
$db$database;

    
$query 'VACUUM;';

    if(isset(
$_REQUEST['sure'])) {
        
$old_size filesize($database);

        if(!@
$db->queryExec($query)) {
            
error_query($query);
            
error(sqlite_error_string($db->lastError()));
        }
        else {
            
$new_size filesize($database);

            
notice('vacuumed "' basename($database) . '"');
            
notice_query($query'using this query:');
            
notice('filesize reduced from ' format_filesize($old_size) . ' to ' format_filesize($new_size) . ' by ' format_filesize($old_size $new_size) . ' (' number_format(100 * ((float)($old_size $new_size) / $old_size), 1) . '%)');
            
redirect('database', array('database' => $database));
        }
    }

    
$layout = new Layout;
    
$layout->set_title('vacuum database');
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location('vacuum'url('vacuum', array('database' => $database)));
    
$layout->header();

    
?>
        This will be executed:<br />
        <div class="query"><?php echo highlight_sql($query); ?></div>
        <br />

        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="vacuum" />
            <input type="hidden" name="database" value="<?php echo @htmlspecialchars($database); ?>" />
            <input type="hidden" name="table" value="<?php echo @htmlspecialchars($table); ?>" />
            <input type="hidden" name="sure" value="1" />
            <div class="submit">Are you sure? <input type="submit" value="yes, vacuum the database" /></div>
        </form>
    <?php

    $layout
->footer();
}


function 
action_drop_table() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);

    
$query 'DROP TABLE "' sqlite_escape_string($table) . '";';

    if(isset(
$_REQUEST['sure'])) {
        if(!@
$db->queryExec($query)) {
            
error_query($query);
            
error(sqlite_error_string($db->lastError()));
        }
        else {
            
notice('dropped table "' htmlspecialchars($table) . '"');
            
notice_query($query'using this query:');
            
redirect('database', array('database' => $database));
        }
    }

    
$layout = new Layout;
    
$layout->set_title('drop table');
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location($tableurl('table', array('database' => $database'table' => $table)));
    
$layout->add_location('drop'url('drop_table', array('database' => $database'table' => $table)));
    
$layout->header();

    
?>
        This will be executed:<br />
        <div class="query"><?php echo highlight_sql($query); ?></div>
        <br />

        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="drop_table" />
            <input type="hidden" name="database" value="<?php echo @htmlspecialchars($database); ?>" />
            <input type="hidden" name="table" value="<?php echo @htmlspecialchars($table); ?>" />
            <input type="hidden" name="sure" value="1" />
            <div class="submit">Are you sure? <input type="submit" value="yes, drop the table" /></div>
        </form>
    <?php

    $layout
->footer();
}


function 
action_drop_index() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);
    
$index = @validate_index($db$_REQUEST['table'], $_REQUEST['index']);

    
$query 'DROP INDEX "' sqlite_escape_string($index) . '";';

    if(isset(
$_REQUEST['sure'])) {
        if(!@
$db->queryExec($query)) {
            
error_query($query);
            
error(sqlite_error_string($db->lastError()));
        }
        else {
            
notice('dropped index "' htmlspecialchars($table) . '"');
            
notice_query($query'using this query:');
            
redirect('table', array('database' => $database'table' => $table));
        }
    }

    
$layout = new Layout;
    
$layout->set_title('drop index');
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location($tableurl('table', array('database' => $database'table' => $table)));
    
$layout->add_location('drop'url('drop_index', array('database' => $database'table' => $table'index' => $index)));
    
$layout->header();

    
?>
        This will be executed:<br />
        <div class="query"><?php echo highlight_sql($query); ?></div>
        <br />

        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="drop_index" />
            <input type="hidden" name="database" value="<?php echo @htmlspecialchars($database); ?>" />
            <input type="hidden" name="table" value="<?php echo @htmlspecialchars($table); ?>" />
            <input type="hidden" name="index" value="<?php echo @htmlspecialchars($index); ?>" />
            <input type="hidden" name="sure" value="1" />
            <div class="submit">Are you sure? <input type="submit" value="yes, drop the index" /></div>
        </form>
    <?php

    $layout
->footer();
}


function 
action_insert_row() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);

    
$columns column_list($db$table);

    if(isset(
$_REQUEST['columns'])) {
        
$query 'INSERT INTO "' sqlite_escape_string($table) . '" (';
        
$i 0;
        foreach(
$columns as $column) {
            if(
$_REQUEST['columns'][$column['cid']]['special'] != 'default') {
                
$query .= ($i++ > ', ' '');
                
$query .= '"' sqlite_escape_string($column['name']) . '"';
            }
        }
        
$query .= ') VALUES (';
        
$i 0;
        foreach(
$columns as $column) {
            if(
$_REQUEST['columns'][$column['cid']]['special'] != 'default') {
                
$query .= ($i++ > ', ' '');
                
$query .= format_insert_function($_REQUEST['columns'][$column['cid']]['value'], $_REQUEST['columns'][$column['cid']]['special']);
            }
        }
        
$query .= ')';

        if(!@
$db->queryExec($query)) {
            
error_query($query);
            
error(sqlite_error_string($db->lastError()));
        }
        else {
            
notice('inserted row with rowid ' $db->lastInsertRowid() . ' into the table "' htmlspecialchars($table) . '"');
            
notice_query($query'using this query:');

            
$query 'DELETE FROM "' sqlite_escape_string($table) . '" WHERE _ROWID_="' $db->lastInsertRowid() . '"';
            
notice_query($query'use this query to delete it again:');

            
redirect('show_table', array('database' => $database'table' => $table));
        }
    }

    
$layout = new Layout;
    
$layout->set_title('insert row ' $table);
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location($tableurl('table', array('database' => $database'table' => $table)));
    
$layout->add_location('insert row'url('insert_row', array('database' => $database'table' => $table)));
    
$layout->header();

    
?>
        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="insert_row" />
            <input type="hidden" name="database" value="<?php echo @htmlspecialchars($database); ?>" />
            <input type="hidden" name="table" value="<?php echo @htmlspecialchars($table); ?>" />

            <script type="text/javascript">
                function on_value_entered(cid) {
                    var select = document.getElementById('special_' + cid);
                    var special = select.options[select.selectedIndex].value;
                    if(special == 'default')
                        select.selectedIndex = 1;
                }
            </script>

            <table class="insert_row" cellspacing="0">
            <thead>
                <tr>
                    <th>Column</th>
                    <th>Value</th>
                    <th>Special</th>
                </tr>
            </thead>
            <tbody>
            <?php
            $i 
0;
            foreach(
$columns as $column) {
                
$value = @$_REQUEST['columns'][$column['cid']]['value'];
                
$special = @$_REQUEST['columns'][$column['cid']]['special'];

                
$onchange ' onchange="on_value_entered(' $column['cid'] . ');"';

                echo 
'<tr class="' . ($i++ % == 'even' 'odd') . '">';
                echo 
'<td><label for="field_' $column['cid'] . '">' htmlspecialchars($column['name']) . '</label></td>';
                switch(
strtolower($column['type'])) {
                    case 
'integer': case 'int': case 'bigint': case 'real': case 'float': case 'double': case 'decimal': case 'numeric':
                        echo 
'<td><input type="text" class="number"' $onchange ' name="columns[' $column['cid'] . '][value]" id="field_' $column['cid'] . '" value="' . @htmlspecialchars($value) . '" /></td>';
                        break;

                    default: case 
'varchar': case 'char': case 'string':
                        echo 
'<td><input type="text" class="text"' $onchange ' name="columns[' $column['cid'] . '][value]" id="field_' $column['cid'] . '" value="' . @htmlspecialchars($value) . '" /></td>';
                        break;

                    case 
'text': case 'shorttext': case 'mediumtext': case 'longtext':
                        echo 
'<td><textarea' $onchange ' name="columns[' $column['cid'] . '][value]" id="field_' $column['cid'] . '">' . @htmlspecialchars($value) . '</textarea></td>';
                        break;
                }
                echo 
'<td>';
                    echo 
'<select name="columns[' $column['cid'] . '][special]" id="special_' $column['cid'] . '">';
                        if(
$column['pk'])
                            echo 
'<option value="default">Default Primary Key</option>';
                        elseif(!empty(
$column['dflt_value']))
                            echo 
'<option value="default">Default "' htmlspecialchars($column['dflt_value']) . '"</option>';
                        else
                            echo 
'<option value="default">Default</option>';
                        echo 
'<option value="value" ' . ($special == 'value' ' selected="selected"' '') . '>Value</option>';
                        echo 
'<option value="value">--</option>';
                        
print_insert_functions($special);
                    echo 
'</select>';
                echo 
'</td>';
                echo 
'</tr>';
            }
            
?>
            </tbody>
            </table>

            <input type="submit" value="insert" />
        </form>
    <?php

    $layout
->footer();
}


function 
action_update_row() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);
    
$rowid = @validate_rowid($db$table$_REQUEST['rowid']);

    
$columns column_list($db$table);

    
$result $db->query('SELECT * FROM "' sqlite_escape_string($table) . '" WHERE _ROWID_="' sqlite_escape_string($rowid) . '"');
    
$old_values $result->fetch(); // we validated rowid earlier!

    
if(isset($_REQUEST['columns'])) {
        
$query 'UPDATE "' sqlite_escape_string($table) . '" SET ';
        
$revert_query 'UPDATE "' sqlite_escape_string($table) . '" SET ';
        
$i 0;
        foreach(
$columns as $column) {
            if(
$_REQUEST['columns'][$column['cid']]['special'] != 'old_value') {
                
$query .= ($i ', ' '');
                
$query .= '"' sqlite_escape_string($column['name']) . '"=';
                
$query .= format_insert_function($_REQUEST['columns'][$column['cid']]['value'], $_REQUEST['columns'][$column['cid']]['special']);

                
$revert_query .= ($i ', ' '');
                
$revert_query .= '"' sqlite_escape_string($column['name']) . '"=\'' sqlite_escape_string($old_values[$column['name']]) . '\'';

                
$i++;
            }
        }
        if(
$i == 0) {
            
notice('no values changed so nothing updated');
            
redirect('show_table', array('database' => $database'table' => $table));
        }
        
$query .= ' WHERE _ROWID_="' sqlite_escape_string($rowid) . '"';
        
$revert_query .= ' WHERE _ROWID_="' sqlite_escape_string($rowid) . '"';

        if(!@
$db->queryExec($query)) {
            
error_query($query);
            
error(sqlite_error_string($db->lastError()));
        }
        else {
            
notice('updated row with rowid ' $rowid ' in ' htmlspecialchars($table));
            
notice_query($query'with this query:');
            
notice_query($revert_query'use this query to revert to old values:');
            
redirect('show_table', array('database' => $database'table' => $table));
        }
    }
    else {
        
$_REQUEST['columns'] = array();
        foreach(
$columns as $column)
            
$_REQUEST['columns'][$column['cid']] = array('value' => $old_values[$column['name']], 'special' => 'old_value');
    }

    
$layout = new Layout;
    
$layout->set_title('update row ' $rowid);
    
$layout->add_location(basename($database), url('database', array('database' => $database)));
    
$layout->add_location($tableurl('table', array('database' => $database'table' => $table)));
    
$layout->add_location('update row'url('update_row', array('database' => $database'table' => $table'rowid' => $rowid)));
    
$layout->header();

    
?>
        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="update_row" />
            <input type="hidden" name="database" value="<?php echo @htmlspecialchars($database); ?>" />
            <input type="hidden" name="table" value="<?php echo @htmlspecialchars($table); ?>" />
            <input type="hidden" name="rowid" value="<?php echo (int)$rowid?>" />

            <script type="text/javascript">
                function on_value_entered(cid) {
                    var select = document.getElementById('special_' + cid);
                    var special = select.options[select.selectedIndex].value;
                    if(special == 'old_value')
                        select.selectedIndex = 1;
                }
            </script>

            <table class="update_row" cellspacing="0">
            <thead>
                <tr>
                    <th>Column</th>
                    <th>Value</th>
                    <th>Special</th>
                </tr>
            </thead>
            <tbody>
            <?php
            $i 
0;
            foreach(
$columns as $column) {
                
$value = @$_REQUEST['columns'][$column['cid']]['value'];
                
$special = @$_REQUEST['columns'][$column['cid']]['special'];

                
$onchange ' onchange="on_value_entered(' $column['cid'] . ');"';

                echo 
'<tr class="' . ($i++ % == 'even' 'odd') . '">';
                echo 
'<td><label for="field_' $column['cid'] . '">' htmlspecialchars($column['name']) . '</label></td>';
                switch(
strtolower($column['type'])) {
                    case 
'integer': case 'int': case 'bigint': case 'real': case 'float': case 'double': case 'decimal': case 'numeric':
                        echo 
'<td><input type="text" class="number"' $onchange ' name="columns[' $column['cid'] . '][value]" id="field_' $column['cid'] . '" value="' . @htmlspecialchars($value) . '" /></td>';
                        break;

                    default: case 
'varchar': case 'char': case 'string':
                        echo 
'<td><input type="text" class="text"' $onchange ' name="columns[' $column['cid'] . '][value]" id="field_' $column['cid'] . '" value="' . @htmlspecialchars($value) . '" /></td>';
                        break;

                    case 
'text': case 'shorttext': case 'mediumtext': case 'longtext':
                        echo 
'<td><textarea' $onchange ' name="columns[' $column['cid'] . '][value]" id="field_' $column['cid'] . '">' . @htmlspecialchars($value) . '</textarea></td>';
                        break;
                }
                echo 
'<td>';
                    echo 
'<select name="columns[' $column['cid'] . '][special]" id="special_' $column['cid'] . '">';
                        echo 
'<option value="old_value">Old Value</option>';
                        echo 
'<option value="value" ' . ($special == 'value' ' selected="selected"' '') . '>Value</option>';
                        echo 
'<option value="value">--</option>';
                        
print_insert_functions($special);
                    echo 
'</select>';
                echo 
'</td>';
                echo 
'</tr>';
            }
            
?>
            </tbody>
            </table>

            <input type="submit" value="update" />
        </form>
    <?php

    $layout
->footer();
}


function 
action_delete_row() {
    global 
$db$database;

    
$table = @validate_table($db$_REQUEST['table']);
    
$rowid = @validate_rowid($db$table$_REQUEST['rowid']);

    
$columns $db->fetchColumnTypes($table);

    
$result $db->query('SELECT * FROM "' sqlite_escape_string($table) . '" WHERE _ROWID_="' sqlite_escape_string($rowid) . '"');
    
$old_values $result->fetch(); // we validated rowid earlier!

    
$query 'DELETE FROM "' sqlite_escape_string($table) . '" WHERE _ROWID_="' sqlite_escape_string($rowid) . '"';
    if(!@
$db->queryExec($query)) {
        
error_query($query);
        
error(sqlite_error_string($db->lastError()));
    }
    else {
        
notice('deleted row with rowid ' $rowid ' from ' htmlspecialchars($table));
        
notice_query($query'with this query:');

        
$query 'INSERT INTO "' sqlite_escape_string($table) . '" (_ROWID_';
        foreach(
$columns as $name => $type)
            
$query .= ', "' sqlite_escape_string($name) . '"';
        
$query .= ') VALUES (';
        foreach(
$columns as $name => $type)
            
$query .= ', \'' sqlite_escape_string($old_values[$name]) . '\'';
        
$query .= ')';

        
notice_query($query'use this query to insert the old values:');
        
redirect('show_table', array('database' => $database'table' => $table));
    }
}


// displays the login form and checks the input
function action_login() {
    if(
USERNAME === '' && PASSWORD === '')
        
redirect();

    if(isset(
$_REQUEST['username'], $_REQUEST['password'])) {
        if(
$_REQUEST['username'] === USERNAME && $_REQUEST['password'] === PASSWORD) {
            
$_SESSION['s_logged_in'] = true;
            
redirect();
        }
        else
            
error('Wrong login data.');
    }

    
$layout = new Layout;
    
$layout->set_title('login');
    
$layout->header();

    
?>
        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
            <input type="hidden" name="action" value="login" />
            <div class="username"><label for="username">Username:</label> <input type="text" class="text" name="username" id="username" value="<?php echo @htmlspecialchars($_REQUEST['username']); ?>" /></div>
            <div class="password"><label for="password">Password:</label> <input type="password" class="password" name="password" id="password" value="<?php echo @htmlspecialchars($_REQUEST['password']); ?>" /></div>
            <div class="submit"><input type="submit" value="login" /></div>
        </form>
    <?php

    $layout
->footer();
}


// logout and redirect to login form
function action_logout() {
    unset(
$_SESSION['s_logged_in']);
    
notice('Logged out.');
    
redirect('login');
}


/***********************************************************************
 * LAYOUT **************************************************************
 **********************************************************************/


class Layout {
    var 
$title '';
    var 
$location = array();

    function 
set_title($title) {
        
$this->title $title;
    }

    function 
add_location($name$url null) {
        
$this->location[] = array($name$url);
    }

    function 
header() {
        global 
$db$database;

        
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
        <html>
            <head>
                <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
                <title><?php echo htmlspecialchars($this->title); ?></title>
                <style type="text/css">
                    * { padding: 0; margin: 0; font-size: 100%; }
                    a { color: #000099; }
                    a:hover { color: #0000FF; }
                    body { font: 12px Arial, Helvetica; }
                    #header { line-height: 40px; background-color: #c7d4dd; border-bottom: 2px solid #677477; padding: 0 10px; }
                    #logo { font-size: 150%; margin-right: 5px; }
                    #logout { float: right; }
                    #version { float: right; font-weight: bold; margin-left: 10px; }
                    #navigation { float: left; width: 150px; margin: 10px 0 0 10px; }
                    #content { margin: 10px 10px 0 170px; }
                    #footer { clear: left; margin-left: 170px; font-size: 85%; margin-top: 30px; }

                    #navigation .title { display: block; font-weight: bold; }
                    #navigation .action { display: block; margin-left: 10px; }
                    #navigation .table { }
                    #navigation .active { font-weight: bold; }

                    div.query { border: 1px solid #606060; background-color: #eeeeee; padding: 10px; font-family: monospace; margin: 3px 0; }
                    .sql_comment { color: #009900; }
                    .sql_string { color: #990000; }
                    .sql_identifier { color: #994400; }
                    .sql_keyword { color: #000099; font-weight: bold; }

                    table { border: 1px solid #606060; border-collapse: collapse; margin: 3px 0; }
                    tr.odd { background-color: #eeeeee; }
                    tr.divider { background-color: #c7d4dd; }
                    td { padding: 1px 3px; border: 1px solid #606060; }
                    th { padding: 4px 3px; border: 1px solid #606060; background-color: #c7d4dd; color: black; font-weight: bold; }

                    .notices { padding-bottom: 10px; border-bottom: 1px solid #808080; margin-bottom: 20px; }
                    .notice_title { font-weight: bold; }
                    .notice { margin-bottom: 10px; padding: 10px; }
                    .notice_notice { font-weight: bold; border: 1px solid #003300; background-color: #006600; color: white; }
                    .notice_error { font-weight: bold; border: 1px solid #330000; background-color: #660000; color: white; }
                    .notice_query { border: 1px solid #606060; background-color: #eeeeee; font-family: monospace; }
                    .notice_error_query { border: 1px solid #600000; background-color: #ffdddd; font-family: monospace; }

                    textarea.query { width: 100%; height: 150px; }

                    td.filesize, td.fileperms, td.number { text-align: right; }
                </style>
                <script type="text/javascript">

                </script>
            </head>

            <body class="body_<?php echo $_REQUEST['action']; ?>">
                <div id="header">
                    <a id="version" href="<?php echo HOMEPAGE?>">v<?php echo VERSION?></a>
                    <?php
                    
if(isset($_SESSION['s_logged_in']) && $_SESSION['s_logged_in'] === true)
                        echo 
'<a id="logout" href="' url('logout') . '">logout</a>';
                    
?>
                    <a id="logo" href="<?php echo url(); ?>"><?php echo NAME?></a>

                    <?php
                    
foreach($this->location as $location) {
                        echo 
' - ';
                        if(
is_null($location[1]))
                            echo 
'<span class="location">' htmlspecialchars($location[0]) . '</span>';
                        else
                            echo 
'<a class="location" href="' htmlspecialchars($location[1]) . '">' htmlspecialchars($location[0]) . '</a>';
                    }
                    
?>
                </div>

                <div id="navigation">
                    <?php
                    
if(isset($_REQUEST['table'])) {
                        echo 
'<div class="title"><a href="' url('table', array('database' => $database'table' => $_REQUEST['table'])) . '">' htmlspecialchars($_REQUEST['table']) . '</a></div>';
                        echo 
'<div class="action"><a' . ($_REQUEST['action'] == 'show_table' ' class="active"' '') . ' href="' url('show_table', array('database' => $database'table' => $_REQUEST['table'])) . '">browse</a></div>';
                        echo 
'<div class="action"><a' . ($_REQUEST['action'] == 'query' ' class="active"' '') . ' href="' url('query', array('database' => $database'table' => $_REQUEST['table'])) . '">query</a></div>';
                        echo 
'<div class="action"><a' . ($_REQUEST['action'] == 'insert_row' ' class="active"' '') . ' href="' url('insert_row', array('database' => $database'table' => $_REQUEST['table'])) . '">insert row</a></div>';
                        echo 
'<div class="action"><a' . ($_REQUEST['action'] == 'truncate' ' class="active"' '') . ' href="' url('truncate', array('database' => $database'table' => $_REQUEST['table'])) . '">truncate</a></div>';
                        echo 
'<div class="action"><a' . ($_REQUEST['action'] == 'drop_table' ' class="active"' '') . ' href="' url('drop_table', array('database' => $database'table' => $_REQUEST['table'])) . '">drop</a></div>';
                        echo 
'<br />';
                    }
                    elseif(isset(
$database)) {
                        echo 
'<div class="title"><a href="' url('database', array('database' => $database)) . '">' htmlspecialchars(basename($database)) . '</a></div>';
                        echo 
'<div class="action"><a' . ($_REQUEST['action'] == 'query' ' class="active"' '') . ' href="' url('query', array('database' => $database)) . '">query</a></div>';
                        echo 
'<div class="action"><a' . ($_REQUEST['action'] == 'create_table' ' class="active"' '') . ' href="' url('create_table', array('database' => $database)) . '">create table</a></div>';
                        echo 
'<div class="action"><a' . ($_REQUEST['action'] == 'vacuum' ' class="active"' '') . ' href="' url('vacuum', array('database' => $database)) . '">vacuum</a></div>';
                        echo 
'<br />';
                    }
                    else {
                        echo 
'<div class="action"><a' . (@$_REQUEST['action'] == 'create_database' ' class="active"' '') . ' href="' url('create_database') . '">create database</a></div>';
                    }

                    if(isset(
$database)) {
                        
$result $db->query('SELECT name FROM sqlite_master WHERE type="table" ORDER BY name');
                        while(
$row $result->fetch()) {
                            echo 
'<div class="table"><a href="' url('show_table', array('database' => $database'table' => $row['name'])) . '">[B]</a> <a' . (@$_REQUEST['table'] == $row['name'] ? ' class="active"' '') . ' href="' url('table', array('database' => $database'table' => $row['name'])) . '">' $row['name'] . '</a></div>';
                        }
                    }
                    
?>
                </div>

                <div id="content">
                    <?php
                    
if(notice_exists()) {
                        echo 
'<div class="notices">';
                        while(
notice_exists()) {
                            
$notice get_notice();
                            if(
$notice['type'] == 'error_query' || $notice['type'] == 'query')
                                
$notice['message'] = highlight_sql($notice['message']);
                            if(!empty(
$notice['title']))
                                echo 
'<div class="notice_title">' $notice['title'] . '</div>';
                            echo 
'<div class="notice notice_' $notice['type'] . '">' $notice['message'] . '</div>';
                        }
                        echo 
'</div>';
                    }
                    
?>

        <?php
    
}

    function 
footer() {
        
?>
                </div>

                <div id="footer">
                    <?php echo date('Y-m-d H:i:s'); ?><?php echo time(); ?>
                </div>
            </body>
        </html>
        <?php
    
}
}


/***********************************************************************
 * DATABASE FUNCTIONS **************************************************
 **********************************************************************/


function open_database($filename) {
    
$db sqlite_factory($_REQUEST['database'], 0666$error_message);
    if(
is_null($db)) {
        
error($error_message);
        
redirect();
    }
    return 
$db;
}


function 
table_exists(&$db$table) {
    
$result $db->query('SELECT 1 FROM sqlite_master WHERE type="table" AND name="' sqlite_escape_string($table) . '"');
    return (
$result->numRows() > 0);
}


function 
rowid_exists(&$db$table$rowid) {
    
$result $db->query('SELECT 1 FROM "' sqlite_escape_string($table) . '" WHERE _ROWID_="' sqlite_escape_string($rowid) . '"');
    return (
$result->numRows() > 0);
}


function 
index_exists(&$db$index) {
    
$result $db->query('SELECT 1 FROM sqlite_master WHERE type="index" AND name="' sqlite_escape_string($index) . '"');
    return (
$result->numRows() > 0);
}


function 
row_count(&$db$table) {
    
$result $db->query('SELECT COUNT(*) FROM "' sqlite_escape_string($table) . '"');
    return 
$result->fetchSingle();
}


function 
column_list(&$db$table) {
    
$result $db->query('PRAGMA table_info("' sqlite_escape_string($table) . '")');
    return 
$result->fetchAll(SQLITE_ASSOC);
}


function 
index_list(&$db$table) {
    
$result $db->query('PRAGMA index_list("' sqlite_escape_string($table) . '")');
    
$indices = array();
    while(
$row $result->fetch()) {
        
$row['columns'] = array();
        
$result2 $db->query('PRAGMA index_info("' sqlite_escape_string($row['name']) . '")');
        while(
$row2 $result2->fetch())
            
$row['columns'][] = $row2['name'];
        
$indices[] = $row;
    }
    return 
$indices;
}


function 
get_primary_key(&$db$table) {
    
$result $db->query('PRAGMA table_info("' sqlite_escape_string($table) . '")');
    while(
$row $result->fetch())
        if(
$row['pk'])
            return 
$row['name'];
    return 
'_ROWID_';
}


function 
has_primary_key(&$db$table) {
    
$result $db->query('PRAGMA table_info("' sqlite_escape_string($table) . '")');
    while(
$row $result->fetch())
        if(
$row['pk'])
            return 
true;
    return 
false;
}


/***********************************************************************
 * VALIDATORS **********************************************************
 **********************************************************************/


function validate_table(&$db$table) {
    if(
is_null($table)) {
        
error('no table specified');
        
redirect('database', array('database' => $database));
    }
    if(!
table_exists($db$table)) {
        
error('table `' htmlspecialchars($table) . '` does not exist');
        
redirect('database', array('database' => $database));
    }
    return 
$table;
}


function 
validate_rowid(&$db$table$rowid) {
    if(
is_null($rowid)) {
        
error('no rowid specified');
        
redirect('table', array('database' => $database'table' => $table));
    }
    if(!
rowid_exists($db$table$rowid)) {
        
error('rowid `' htmlspecialchars($rowid) . '` does not exist in table `' htmlspecialchars($table) . '`');
        
redirect('table', array('database' => $database'table' => $table));
    }
    return 
$rowid;
}


function 
validate_index(&$db$table$index) {
    if(
is_null($index)) {
        
error('no index specified');
        
redirect('table', array('database' => $database'table' => $table));
    }
    
$result $db->query('SELECT 1 FROM sqlite_master WHERE type="index" AND name="' sqlite_escape_string($index) . '" AND tbl_name="' sqlite_escape_string($table) . '"');
    if(
$result->numRows() == 0) {
        
error('index `' htmlspecialchars($index) . '` does not exist in table `' htmlspecialchars($table) . '`');
        
redirect('table', array('database' => $database'table' => $table));
    }
    return 
$index;
}


/***********************************************************************
 * UTILITY FUNCTIONS ***************************************************
 **********************************************************************/


function print_insert_functions($selected_function) {
    
$functions = array(
        
'null'      => 'NULL',
        
'datetime'  => 'now [YYYY-mm-dd HH:ii:ss]',
        
'date'      => 'now [YYYY-mm-dd]',
        
'time'      => 'now [HH:ii:ss]',
        
'timestamp' => 'now [unix timestamp]',
        
'trim'      => 'trim($value)',
        
'md5'       => 'md5($value)',
    );
    foreach(
$functions as $key => $label)
        echo 
'<option value="' $key '" ' . ($selected_function == $key ' selected="selected"' '') . '>' htmlspecialchars($label) . '</option>';
}


function 
format_insert_function($value$function) {
    switch(
$function) {
        default:
        case 
'null':      return 'NULL';
        case 
'value':     return '\'' sqlite_escape_string($value) . '\'';
        case 
'date':      return 'date(\'now\')';
        case 
'time':      return 'time(\'now\')';
        case 
'datetime':  return 'datetime(\'now\')';
        case 
'timestamp': return '\'' time() . '\'';
        case 
'trim':      return '\'' sqlite_escape_string(trim($value)) . '\'';
        case 
'md5':       return '\'' sqlite_escape_string(md5($value)) . '\'';
    }
}


function 
highlight_sql_callback($matches) {
    if(
$matches[0][0] == '-' || $matches[0][0] == '/')
        return 
'<span class="sql_comment">' $matches[0] . '</span>';
    elseif(
$matches[0][0] == '\'')
        return 
'<span class="sql_string">' $matches[0] . '</span>';
    elseif(
$matches[0][0] == '"')
        return 
'<span class="sql_identifier">' $matches[0] . '</span>';
    else
        return 
'<span class="sql_keyword">' $matches[0] . '</span>';
}


function 
highlight_sql($sql) {
    
$sqlite_keywords = array(
            
'ABORT''ADD''AFTER''ALL''ALTER''ANALYZE''AND''AS''ASC''ATTACH''AUTOINCREMENT',
            
'BEFORE''BEGIN''BETWEEN''BY''CASCADE''CASE''CAST''CHECK''COLLATE''COLUMN''COMMIT',
            
'CONFLICT''CONSTRAINT''CREATE''CROSS''CURRENT_DATE''CURRENT_TIME''CURRENT_TIMESTAMP',
            
'DATABASE''DEFAULT''DEFERRABLE''DEFERRED''DELETE''DESC''DETACH''DISTINCT''DROP',
            
'EACH''ELSE''END''ESCAPE''EXCEPT''EXCLUSIVE''EXISTS''EXPLAIN''FAIL''FOR''FOREIGN',
            
'FROM''FULL''GLOB''GROUP''HAVING''IF''IGNORE''IMMEDIATE''IN''INDEX''INDEXED',
            
'INITIALLY''INNER''INSERT''INSTEAD''INTERSECT''INTO''IS''ISNULL''JOIN''KEY''LEFT',
            
'LIKE''LIMIT''MATCH''NATURAL''NOT''NOTNULL''NULL''OF''OFFSET''ON''OR''ORDER',
            
'OUTER''PLAN''PRAGMA''PRIMARY''QUERY''RAISE''REFERENCES''REGEXP''REINDEX''RENAME',
            
'REPLACE''RESTRICT''RIGHT''ROLLBACK''ROW''SELECT''SET''TABLE''TEMP''TEMPORARY',
            
'THEN''TO''TRANSACTION''TRIGGER''UNION''UNIQUE''UPDATE''USING''VACUUM''VALUES',
            
'VIEW''VIRTUAL''WHEN''WHERE'
        
);

    
$sql str_replace(array('<''>'), array('&lt;''&gt;'), $sql);
    return 
preg_replace_callback('%--.*?$|/\*.*\*/|\'[^\']*\'|"[^"]*"|\\b' join('\\b|\\b'$sqlite_keywords) . '\\b%ism''highlight_sql_callback'$sql);
}


function 
url($action ''$arguments = array()) {
    
$url $_SERVER['PHP_SELF'];
    if(
$action !== '')
        
$url .= '?action=' urlencode($action);
    elseif(!empty(
$arguments))
        
$url .= '?';
    foreach(
$arguments as $key => $value)
        
$url .= '&' urlencode($key) . '=' urlencode($value);
    return 
$url;
}


function 
redirect($action ''$arguments = array()) {
    
header('Location: ' url($action$arguments));
    exit;
}


function 
notice($message$type 'notice'$title '') {
    
$_SESSION['s_notice'][] = array('message' => $message'type' => $type'title' => $title);
}


function 
notice_query($message$title '') {
    
$_SESSION['s_notice'][] = array('message' => $message'type' => 'query''title' => $title);
}


function 
error($message$title '') {
    
$_SESSION['s_notice'][] = array('message' => $message'type' => 'error''title' => $title);
}


function 
error_query($message$title '') {
    
$_SESSION['s_notice'][] = array('message' => $message'type' => 'error_query''title' => $title);
}


function 
get_notice() {
    if(empty(
$_SESSION['s_notice']))
        return 
false;
    return 
array_shift($_SESSION['s_notice']);
}


function 
notice_exists($type false) {
    if(
$type) {
        foreach(
$_SESSION['s_notice'] as $notice)
            if(
$notice['type'] == $type)
                return 
true;
        return 
false;
    }
    return !empty(
$_SESSION['s_notice']);
}


function 
format_filesize($value) {
    if(
$value >= 1073741824)
        return 
number_format((float)$value 10737418241) . ' GB';
    if(
$value >= 1048576)
        return 
number_format((float)$value 10485761) . ' MB';
    if(
$value >= 1024)
        return 
number_format((float)$value 10241) . ' kB';
    return 
number_format($value0) . ' B';
}


function 
format_fileperms($perms) {
        if((
$perms 0xC000) == 0xC000$info 's'// Socket
    
elseif(($perms 0xA000) == 0xA000$info 'l'// Symbolic Link
    
elseif(($perms 0x8000) == 0x8000$info '-'// Regular
    
elseif(($perms 0x6000) == 0x6000$info 'b'// Block special
    
elseif(($perms 0x4000) == 0x4000$info 'd'// Directory
    
elseif(($perms 0x2000) == 0x2000$info 'c'// Character special
    
elseif(($perms 0x1000) == 0x1000$info 'p'// FIFO pipe
    
else                                $info 'u'// Unknown

    
$info .= (($perms 0x0100) ? 'r' '-');
    
$info .= (($perms 0x0080) ? 'w' '-');
    
$info .= (($perms 0x0040) ? (($perms 0x0800) ? 's' 'x' ) : (($perms 0x0800) ? 'S' '-'));

    
$info .= (($perms 0x0020) ? 'r' '-');
    
$info .= (($perms 0x0010) ? 'w' '-');
    
$info .= (($perms 0x0008) ? (($perms 0x0400) ? 's' 'x' ) : (($perms 0x0400) ? 'S' '-'));

    
$info .= (($perms 0x0004) ? 'r' '-');
    
$info .= (($perms 0x0002) ? 'w' '-');
    
$info .= (($perms 0x0001) ? (($perms 0x0200) ? 't' 'x' ) : (($perms 0x0200) ? 'T' '-'));

    return 
$info;
}