#!/usr/local/bin/perl
# ==============================================================
# -------------
# MysqlMan
# -------------
# Web: http://www.gossamer-threads.com/
# Support: support@gossamer-threads.com
#
# COPYRIGHT NOTICE:
#
# Copyright 2000 Gossamer Threads Inc. All Rights Reserved.
#
# By using this program you agree to indemnify Gossamer Threads
# Inc. from any liability.
#
# Please see the README for full license details.
# ==============================================================
use CGI ();
use CGI::Carp qw/fatalsToBrowser/;
use lib 'G:/mysqlman';
use vars qw(%browse_cmd %change_cmd %config $in $dbh);
# Command Hash
# --------------------------------------------------------
# Hashes that check the type of queries from SQL Monitor so that
# appropriate actions can be taken;
%browse_cmd = (
explain => 1,
select => 1,
show => 1,
describe => 1,
desc => 1,
);
# Required Librariers
# --------------------------------------------------------
# Make sure we are using perl 5.003 and load other required files.
eval {
require DBI;
require DBD::mysql;
require strict;
require GT_Template; # Template module
require 5.003; # We need at least Perl 5.003
require "html.pl"; # HTML File
require "mysql.cfg"; # Configuration File
};
if ($@) { &cgierr("Error loading required libraries.\nCheck that they exist, permissions are set correctly and that they compile.\nReason: $@"); }
# Run the program and trap fatal errors.
# --------------------------------------------------------
eval { &main; } or &cgierr("fatal undef error: $@", 1); # Trap any fatal errors so the program hopefully
# never produces that nasty 500 server error page.
# The main program.
# ---------------------------------------------------
sub main {
# Initilize for mod_perl
$dbh = undef;
my $in = new CGI;
my $level;
if (defined ($in->param('db_user')) || defined ($in->param('db_host'))) { &do_login($in); }
else {
$level = $in->param("do") || '';
if ($level eq "logout") { &do_logout($in); return 1; }
if ($level ne "login") { &assign_url_cookie($in); }
else { print $in->header(); }
if (!$level) { &show_dbs($in); } # Diplay the database list.
elsif ($level eq "database") { &modify_db($in); } # Create or drop a database.
elsif ($level eq "login") { &html_login($in); } # Prompt the log-in page when needed.
elsif ($level eq "store_cookie") { &store_auth_cookie($in); } # Assign new values to the cookies used in the script.
elsif ($level eq "tables") { &show_tables($in); } # Display the list of tables.
elsif ($level eq "browse") { &table_browse($in); } # Do a general browse.
elsif ($level eq "select") { &table_select($in); } # Compose query criteria for browse.
elsif ($level eq "insert") { &html_insert($in); } # Input value for insert.
elsif ($level eq "insert_record") { &insert_record($in); } # Insert the value input into table.
elsif ($level eq "property") { &table_property($in); } # Display column spec's of the current table.
elsif ($level eq "modify") { &table_modify($in); } # Modify the table contents.
elsif ($level eq "create") { &html_table_def($in,'create'); } # Construct the specifications of the new table.
elsif ($level eq "create_table") { &create_table($in); } # Create a new table according to the specification.
elsif ($level eq "alter_table") { &alter_table($in); } # Change the structure of a table.
elsif ($level eq "add_col") { &html_table_def($in,'add_col'); } # Add new column(s) to a table.
elsif ($level eq "sql_monitor") { &sql_monitor($in); } # Process query entered in SQL Monitor.
elsif ($level eq "import") { &import_record($in); } # Do import from file.
elsif ($level eq "export") { &export_record($in); } # Do export to file.
elsif ($level eq "top_level_op") { &top_level_op($in); } # Create db/create table/SQL Monitor/import/export/
# add fields/rename table.
else { &cgierr("fatal error: $@"); } # Display error message if error occurs.
if ( $config{'debug'} ) {&cgierr("debug");}
if ($dbh) {$dbh->disconnect();}
}
return 1;
}
sub show_dbs {
# ---------------------------------------------------
# Diplays all the databases in MySQL. The function will
# take the output of "show databases" query and list all
# the databases in MySQL. Each name is a link to the table
# list of the database and a "drop" link is also created here
# with each database for each management.
my ($in, $feedback) = @_;
my ($db, $dsn, $db_table, $database_list, $db_table_rows, $drop_cmd);
if (!$dbh) {&connect_db($in) or return undef; }
$query = "SHOW DATABASES";
$sth = &exec_query($query) or return undef;
$database_list = '';
$drop_cmd = '';
while (($db) = $sth->fetchrow_array) {
if ($config{'demo_mode'}) {
if ($db eq $config{'demo_db'}) {
$database_list = qq~$db\n~;
$drop_cmd = qq~Drop\n~;
$db_table_rows .= qq~
~;
if ($config{'demo_mode'} && !$database_list) { $db_table = '
Demo Database Specified is not in MySQL
' }
&html_database($in, $dsn, $db_table, $feedback);
}
#=================================================#
# DATABASE MANAGEMENT #
#=================================================#
sub modify_db{
# ---------------------------------------------------
# Then function will determine whether to create a new
# database or drop a existing one.
my $in = shift;
my $action = $in->param('action') || '';
if ($action eq 'drop_db') { &drop_db($in); }
elsif ($action eq 'create_db') { &create_db($in); }
else {&cgierr("database modify action cannot be identified.");}
}
sub drop_db{
# ---------------------------------------------------
# Here a "drop database db_name" query is executed. If
# the confirmed flag is not on then the user will be brought
# to a confirmation page. If the action is confirmed, the
# database specified will be dropped and the user will be brought
# back to the database list page.
# It is disabled in demo mode.
my $in = shift;
my $db = $in->param('db') || '';
my ($query, $sth);
$query = "DROP DATABASE $db";
if ( $in->param('comfirmed') ){
if ($config{'demo_mode'}) { return &html_demo_prompt($in, "Database $db would have been dropped"); }
else{
if (!$dbh) {&connect_db($in) or return undef; }
$sth = &exec_query($query) or return undef;
$sth->finish;
$message = "Database $db Dropped.";
&show_dbs($in, $message);
}
}
else { &html_confirm_action($in, $query); }
}
sub create_db {
# ---------------------------------------------------
# Before a new database is created, the name specified will
# be tested to see if it is a valid one. If it is, then the
# table will be created and the user will be brought back to the
# database list.
# It is disabled in demo mode.
my $in = shift;
my $db = $in->param('db') || '';
my ($query, $sth);
&valid_name_check($db) or return undef;
if ($config{'demo_mode'}) { return &html_demo_prompt($in, "New database $db would have been created"); }
else{
if (!$dbh) {&connect_db($in) or return undef; }
$query = "CREATE DATABASE $db";
$sth = &exec_query($query) or return undef;
$sth->finish;
$message = "New Database $db Created";
&show_dbs($in, $message);
}
}
#=================================================#
# TABLE MANAGEMENT #
#=================================================#
# ================= #
# Table Display #
# ================= #
sub show_tables {
# ---------------------------------------------------
# Shows all the tables in the database chosen. Browse/Select
# /Properties/Insert/Drop/Empty links are also created with
# each table name.
my ($in, $feedback) = @_;
my ($query, $sth, $table_tables, $table);
my $data_source = $in->param("data_source") || '';
if (!$dbh) {&connect_db($in) or return undef; }
$query = "show tables";
$sth = &exec_query($query) or return undef;
$table_tables = '';
while (($table) = $sth->fetchrow_array()) {
$table_tables .=
qq~
~;
}
}
$example_esc = $in->escapeHTML($example);
$where_esc = $in->escapeHTML($where);
$query_esc = $in->escapeHTML($query);
# Display the contents in the table selected.
$table_records = '';
my $counter = 0;
# Display the resulting set of records. The result is divided into pages and the page
# by the length specified in mysql.cfg.
#
# From "Browse" or "Select/Search"
# Then LIMIT clause of the query limits the records to display, so we display all.
# From "SQL Monitor"
# Records between $start_row and $start_row+$config{'page_length'} will be displayed.
#
while ( @ary = $sth->fetchrow_array() ) {
if ($action ne 'monitor' || ($counter >= $start_row && $counter < ($config{'page_length'} + $start_row))) {
$record = '';
@record_modify = ();
for (my $i = 0; $i < $sth->{NUM_OF_FIELDS}; $i++) {
if ($i < $sth->{NUM_OF_FIELDS} - $pri_key_count) {
$ary[$i] =~ s/(\r|\n)+/ \n/g;
if (defined($ary[$i])) {
if ($ary[$i] ne '') { $record .= "
$ary[$i]
"; }
# put a space in the cell for display purpose.
else { $record .= "
\n~; }
}
$counter++;
}
if (!$record) { $empty_set = 1; }
else { $empty_set = 0; }
$sth->finish();
&html_table_browse($in, $table, $page_jump, $page_link, $col_name, $table_records, $query, $empty_set, $pri_key, $query_printed, $total_rec_num);
}
sub table_select {
# ---------------------------------------------------
# This function gives the critetria for a select query (search).
# A quick select query is executed first to get the field names.
# Field names are in check boxes and "query by example" input
# fields are created with the check boxes.
my $in = shift;
my ($prep, $query, $select_fields, $example_fields, $select_table, $example_table, @type_ary);
my $data_source = $in->param("data_source") || '';
my $table = $in->param("table") || '';
my $page = $in->param("page") || 1;
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) { &connect_db($in) or return undef; }
# do a quick select statement so that we can get the name of the columns.
$query = "SELECT * FROM $table LIMIT 1";
$prep = &exec_query($query) or return undef;
$select_fields = '';
$example_fields = '';
# fields selection (for SELECT)
@type_ary = &get_col_type($table);
for (my $i = 0; $i < $prep->{'NUM_OF_FIELDS'}; $i++) {
# make the first field checked to avoid error message due to empty select clause.
if ($i==0) { $select_fields .= qq~\n$prep->{NAME}->[$i] ~; }
else { $select_fields .= qq~\n$prep->{NAME}->[$i] ~; }
# output the check boxes such that there are 5 rows in a column.
if ( ($i+1)%5 == 0 ) { $select_fields .= "
";
$prep->finish();
&html_table_select($in, $select_table, $example_table);
}
sub table_property{
# ---------------------------------------------------
# The function outputs the result of "describe table_name"
# query. It reads the output row by row and create
# Change/Drop/Primary/Index/Unique links with each field.
my ($in, $feedback) = @_;
my ($page, $query, $sth, @ary, $table_property, $table_property_row);
my $data_source = $in->param("data_source") || '';
my $table = $in->param("table") || '';
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) { &connect_db($in) or return undef; }
$query = "describe $table";
$sth = &exec_query($query) or return undef;
# Display the contents in the table selected.
while ( @ary = $sth->fetchrow_array() ) {
$table_property_row .= "\n
";
$sth->finish();
&html_property($in, $table_property, $feedback);
}
# ===================== #
# Insert New Record #
# ===================== #
sub insert_record{
# ---------------------------------------------------
# This function insert a new record into the table specified.
my $in = shift;
my $table = $in->param('table') || '';
my $feedback;
my ($query, $sth, @insert_fields, $new_record);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
# Make the input from the from into a string to fit in the query.
@insert_fields = &compose_new_condition($in);
$new_record = join ",", @insert_fields;
$query = "INSERT INTO $table SET $new_record";
$sth = &exec_query($query) or return undef;
$sth->finish();
$feedback = 'Record Inserted.';
if ($config{'insert_origin'} eq 'table') { &show_tables($in, $feedback); }
else { &html_insert($in, $feedback) }
}
# ====================== #
# Create New Table #
# ====================== #
sub create_table{
# ---------------------------------------------------
# This function takes in the input from the create table
# form and put them together to produce a create table
# query.
my $in = shift;
my $table = $in->param('table') || '';
my (@field_list, $col_spec, @primary_list, @index_list, @unique_list, $fields, $primary, $index, $unique, $sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
for (my $i = 0; $i < $in->param('num_of_fields'); $i++) {
# Make the text input fields into a string to fit in the query.
$col_spec = &concate_col_spec($in, $i);
push (@field_list, "$col_spec");
# Check index fields.
if ( $in->param("primary_$i") ) { push (@primary_list, $in->param("field_$i")); }
if ( $in->param("index_$i") ) { push (@index_list, $in->param("field_$i")); }
if ( $in->param("unique_$i") ) { push (@unique_list, $in->param("field_$i")); }
}
$fields = join ",", @field_list;
$primary = join ",", @primary_list;
$index = join ",", @index_list;
$unique = join ",", @unique_list;
$query = "CREATE TABLE $table($fields";
if ($primary){ $query .= ", PRIMARY KEY ($primary)" }
if ($index) { $query .= ", INDEX ($index)" }
if ($unique) { $query .= ", UNIQUE ($unique)" }
$query .= ')';
$sth = &exec_query($query) or return undef;
$sth->finish();
&show_tables($in, "Table $table Created.");
}
# ====================== #
# Table Modification #
# ====================== #
sub table_modify{
# ---------------------------------------------------
# Determine modify action.
my $in = shift;
my $action = $in->param('action') || '';
if ($action eq 'drop_table') { &drop_table($in); }
elsif ($action eq 'empty_table') { &empty_table($in); }
elsif ($action eq 'delete_record'){ &delete_record($in); }
elsif ($action eq 'edit_record') { &edit_record_html($in); }
elsif ($action eq 'update') { &update_record($in) }
else { &cgierr("modify action cannot be idenfied"); }
}
sub drop_table{
# ---------------------------------------------------
# The function drops the table specified if the confirmed
# flag is on.
my $in = shift;
my $table = $in->param('table') || '';
my ($query, $sth);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
$query = "DROP TABLE $table";
if ( $in->param('comfirmed') ){
if (!$dbh) {&connect_db($in) or return undef; }
$sth = &exec_query($query) or return undef;
&show_tables($in, "Table $table dropped!")
}
else { &html_confirm_action($in, $query); }
}
sub empty_table{
# ---------------------------------------------------
# The function deletes all the records in the table specified
# if the confirmed flag is on.
my $in = shift;
my ($table, $query, $sth);
$table = $in->param('table') || '';
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
$query = "DELETE FROM $table";
if ( $in->param('comfirmed') ){
if (!$dbh) {&connect_db($in) or return undef; }
$sth = &exec_query($query) or return undef;
&show_tables($in, "Table $table emptied!")
}
else { &html_confirm_action($in, $query); }
}
sub delete_record{
# ---------------------------------------------------
# $record_modify consists the primary key(s) value of
# the record being deleted.
my $in = shift;
my $table = $in->param('table') || '';
my $record_modify = $in->param('record_modify') || '';
my ($sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
$query = "DELETE FROM $table WHERE $record_modify LIMIT 1";
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_browse($in);
}
sub edit_record_html{
# ---------------------------------------------------
# Pre-processing stage before the edit record form is
# displayed. $record_modify consists the primary key(s)
# value of the record being edited.
my $in = shift;
my $table = $in->param('table') || '';
my $record_modify = $in->param('record_modify') || '';
my ($sth, $query, @record, $update, $update_fields);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
# Query for the record with the primary key field(s) equal
# to $record_modify.
$query = "SELECT * FROM $table WHERE $record_modify";
$sth = &exec_query($query) or return undef;
@record = $sth->fetchrow_array;
my $row = $sth->rows;
$sth->finish();
# create the the edit record form table.
$update_fields = &form_fields($in, 1, @record);
&html_update($in, $update_fields);
}
sub update_record{
# ---------------------------------------------------
# Take in the input from the edit table form and update
# the record specified.
my $in = shift;
my $table = $in->param('table') || '';
my $record_modify = $in->param('record_modify') || '';
my ($sth, $query, $update, @fields);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
# Get the updated values in each field. Each element in the
# field is in the form "field = value".
@fields = &compose_new_condition($in);
$update = join ",", @fields;
$query = "UPDATE $table SET $update WHERE $record_modify";
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_browse($in);
}
# ====================== #
# Table Alteration #
# ====================== #
sub alter_table{
# ---------------------------------------------------
# Identify alter table action.
my $in = shift;
my $action = $in->param('action') || '';
if ($action eq 'alter_col') { &alter_col_html($in); }
elsif ($action eq 'do_alter_col') { &alter_col($in); }
elsif ($action eq 'drop_col') { &drop_col($in); }
elsif ($action eq 'set_primary') { &set_primary($in); }
elsif ($action eq 'set_index') { &set_index($in); }
elsif ($action eq 'set_unique') { &set_unique($in); }
elsif ($action eq 'drop_key') { &drop_key($in); }
elsif ($action eq 'add_col') { &add_col($in);}
elsif ($action eq 'rename_table') { &rename_table($in);}
else { &cgierr("Alter Table action cannot be idenfied"); }
}
sub alter_col_html{
# ---------------------------------------------------
# The function first reads in the spec's of the column
# chosen in the current table. Then the type/length_set
# /attribute are is identified individually.
my $in = shift;
my $table = $in->param('table') || '';
my $col = $in->param('col') || '';
my ($field, $type, $null, $key, $default, $extra);
my ($sth, $query, $length_set, @length_set, $attributes, $dump, @type_field, $type_name,
$new_length_set, @new_length_set);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
# Get column specification.
if (!$dbh) {&connect_db($in) or return undef; }
$col = $dbh->quote($col);
$query = "SHOW COLUMNS FROM $table LIKE $col";
$sth = &exec_query($query) or return undef;
($field, $type, $null, $key, $default, $extra) = $sth->fetchrow_array;
$sth->finish();
# Get column type.
($type_name, $dump) = split /([(])/, $type, 2;
# Get length/set
($dump,$dump,$length_set,$dump,$dump) = split /([()])/, $type,5;
# Get Attribute.
@type_field = split / /, $type;
if ( ($type_field[0] ne $type_field[$#type_field]) && ( ($type_name ne 'set') && ($type_name ne 'enum') )) { $attributes = $type_field[$#type_field] }
# Get the elements in length/set.
@length_set = split /,/,$length_set;
foreach (@length_set) {
if ($_ ne "''") { $_ =~ s/''/\\'/g; }
push(@new_length_set, $_ );
}
$new_length_set = join ",", @new_length_set;
&html_alter_col($in, $field, $type_name, $new_length_set, $attributes, $null, $default, $extra);
}
sub alter_col{
# ---------------------------------------------------
# Updates the column specification. The input from the
# alter column is taken in and made into a string to be
# fit as part of the query string. Then the user is
# brought back to the property page.
my $in = shift;
my $table = $in->param('table') || '';
my $col = $in->param('col') || '';
my ($col_spec, $sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
# Get the updated column specs in string format.
$col_spec = &concate_col_spec($in, 0);
$query = "ALTER TABLE $table CHANGE $col $col_spec";
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_property($in, "Specification of Column $col of Table $table Has Been Changed.")
}
sub drop_col{
# ---------------------------------------------------
# The function drops the column/field specified
# if the confirmed flag is on.
my $in = shift;
my $table = $in->param('table') || '';
my $col = $in->param('col') || '';
my ($col_spec, $sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
$query = "ALTER TABLE $table DROP $col";
if ( $in->param('comfirmed') ){
if (!$dbh) {&connect_db($in) or return undef; }
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_property($in, "Column $col of Table $table Has Been Dropped.");
}
else { &html_confirm_action($in, $query); }
}
sub set_primary{
# ---------------------------------------------------
# The function will first set the column not nullable
# and then set the column as primary key. Note that an
# error will occur if all there already exists a primary key.
my $in = shift;
my $table = $in->param('table') || '';
my $col = $in->param('col') || '';
my ($sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
$query = "ALTER TABLE $table ADD PRIMARY KEY ($col)";
# Set the column not nullable
&set_col_not_null($in);
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_property($in, "Column $col set as primary key.");
}
sub set_index{
# ---------------------------------------------------
# The function will first set the column not nullable
# and then set the column as index. Note that an
# error will occur if all there already exists a primary key.
my $in = shift;
my $table = $in->param('table') || '';
my $col = $in->param('col') || '';
my ($sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
$query = "ALTER TABLE $table ADD INDEX ($col)";
if (!$dbh) {&connect_db($in) or return undef; }
# Set the column not nullable.
&set_col_not_null($in);
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_property($in, "Column $col set as index.");
}
sub set_unique{
# ---------------------------------------------------
# The function will first set the column not nullable
# and then set the column as unique. Note that an
# error will occur if all there already exists a primary key.
my $in = shift;
my $table = $in->param('table') || '';
my $col = $in->param('col') || '';
my ($sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
$query = "ALTER TABLE $table ADD UNIQUE ($col)";
if (!$dbh) {&connect_db($in) or return undef; }
# Set the column not nullable.
&set_col_not_null($in);
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_property($in, "Column $col set as unique.");
}
sub drop_key{
# ---------------------------------------------------
# Drops the key specified.
my $in = shift;
my $table = $in->param('table') || '';
my $key_name = $in->param('key_name') || '';
my ($sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if ( $key_name eq 'PRIMARY') { $query = "ALTER TABLE $table DROP PRIMARY KEY"; }
else { $query = "ALTER TABLE $table DROP INDEX $key_name"; }
if (!$dbh) {&connect_db($in) or return undef; }
$sth = &exec_query($query) or return undef;
$sth->finish();
if ( $key_name eq 'PRIMARY' ) { &table_property($in, "Primary Key of Table $table Has Been Dropped."); }
else { &table_property($in, "Index $key_name of Table $table Has Been Dropped."); }
}
sub add_col{
# ---------------------------------------------------
# Adds new columns to the table specified.
my $in = shift;
my $table = $in->param('table') || '';
my (@field_list, $col_spec, @primary_list, @index_list, @unique_list, $fields, $primary, $index, $unique, $sth, $query);
if ($config{'demo_mode'}) { &alias_name_check($table, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
for (my $i = 0; $i < $in->param('num_of_fields'); $i++) {
$col_spec = 'ADD ' . &concate_col_spec($in, $i);
push (@field_list, "$col_spec");
if ( $in->param("primary_$i") ) { push (@primary_list, $in->param("field_$i")); }
if ( $in->param("index_$i") ) { push (@index_list, $in->param("field_$i")); }
if ( $in->param("unique_$i") ) { push (@unique_list, $in->param("field_$i")); }
}
# elements in @field_list are in the form "ADD field_name field_spec".
$fields = join ",", @field_list;
$primary = join ",", @primary_list;
$index = join ",", @index_list;
$unique = join ",", @unique_list;
$query = "ALTER TABLE $table $fields";
if ($primary){ $query .= ", ADD PRIMARY KEY ($primary)" }
if ($index) { $query .= ", ADD INDEX ($index)" }
if ($unique) { $query .= ", ADD UNIQUE ($unique)" }
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_property($in, "Column(s) added to Table $table");
}
sub rename_table{
# ---------------------------------------------------
# Renames the table chosen to a new name specified.
# The name entered will be checked to see if it is a
# valid one. If it is, then the table will be renamed
# and the user will be brought back to the table property
# page.
my $in = shift;
my $new_name = $in->param('table') || '';
my $old_table = $in->param('old_table') || '';
my ($query, $sth, @name);
&valid_name_check($in->param('table')) or return undef;
if ($config{'demo_mode'}) { &alias_name_check($new_name, $in); }
if (!$dbh) {&connect_db($in) or return undef; }
$query = "ALTER TABLE $old_table RENAME AS $new_name";
$sth = &exec_query($query) or return undef;
$sth->finish();
&table_property($in, "Table $old_table Renamed to $new_name.");
}
#=================================================#
# Top Level Operations #
#=================================================#
sub top_level_op{
# ---------------------------------------------------
# Determine which top level operation page to display.
my $in = shift;
$action = $in->param('action') || '';
if ($action eq 'create_db') {&html_create_db($in)}
elsif ($action eq 'sql_monitor') {&html_sql_monitor($in)}
elsif ($action eq 'create_table') {&html_create_table($in)}
elsif ($action eq 'import') {&html_import($in)}
elsif ($action eq 'export') {&html_export($in)}
elsif ($action eq 'add_fields') {&html_add_fields($in)}
elsif ($action eq 'rename_table') {&html_rename_table($in)}
else {&cgi_err("Action cannot be identified in top level operation.")}
}
#=================================================#
# SQL Monitor #
#=================================================#
sub sql_monitor{
# ---------------------------------------------------
# The monitor will be enabled when a database is selected
# from the database list page. It will take in the input
# from the text box and send it to mysql. The query will
# first be determined if it is of a "browse" one. If it is,
# the result will be displayed using &table_browse.
# It is disabled in demo mode.
my $in = shift;
my $query = $in->param('query') || '';
my (@query, $command, $sth, $rows, $message);
if ($config{'demo_mode'}) { return &html_demo_prompt($in, 'The monitor is disabled in the demo'); }
else{
# strips out the beginning and ending spaces.
$query =~ s/^\s+//;
$query =~ s/\s+$//;
$query =~ s/(\r|\n)+/ /g;
@query = split / /, $query;
$command = lc($query[0]);
# display the result if the query of a browse one.
# else execute the query and return the number of
# rows affect.
if ($browse_cmd{$command}) { &table_browse($in); }
else{
if (!$dbh) {&connect_db($in) or return undef; }
$rows = $dbh->do($query) or return &sqlerr("$DBI::errstr.
Query: $query");
$rows += 0;
$message = "$rows row(s) affected";
&html_sql_monitor($in, $message);
}
}
}
#=================================================#
# Import / Export #
#=================================================#
sub import_record{
# ---------------------------------------------------
# Import records to the table specified from a delimited
# text file.
# It is disabled in demo mode.
my $in = shift;
my $delimiter = defined ($in->param('delimiter')) ? $in->param('delimiter') : '';
my $rec_del = defined ($in->param('rec_del')) ? $in->param('rec_del') : '';
my $table = $in->param('table') || '';
my $file = $in->param('file') || '';
my $local = $in->param('local') || '';
my $replace_op = $in->param('replace_op') || '';
my $replace_act = $in->param('replace_act') || '';
my $escape_char = defined ($in->param('escape_char')) ? $in->param('escape_char') : '';
my $ignore_line = $in->param('ignore_line') || 0;
my ($query, $sth, $file_q, $delimiter_q, $rec_del_q, $escape_char_q, $field_op);
if ($config{'demo_mode'}) { return &html_demo_prompt($in, 'Import is disabled in the demo'); }
else{
if (!$dbh) {&connect_db($in) or return undef; }
# quote the inputs
$file_q = $dbh->quote($file);
$delimiter_q = $dbh->quote($delimiter);
$rec_del_q = "'" . $rec_del . "'";
$escape_char_q = $dbh->quote($escape_char);
if (!$replace_op) { $replace_act = ''; }
$query = qq~LOAD DATA $local INFILE $file_q $replace_act
INTO TABLE $table
FIELDS
TERMINATED BY $delimiter_q
ESCAPED BY $escape_char_q
LINES TERMINATED BY $rec_del_q
IGNORE $ignore_line LINES~;
$sth = &exec_query($query) or return undef;
$sth->finish();
&show_tables($in, "File Imported Successfully.");
}
}
sub export_record{
# ---------------------------------------------------
# Exort records from the table specified and produce a
# delimited text file.
# It is disabled in demo mode.
my $in = shift;
my $delimiter = defined ($in->param('delimiter')) ? $in->param('delimiter') : '';
my $rec_del = defined ($in->param('rec_del')) ? $in->param('rec_del') : '';
my $table = $in->param('table') || '';
my $file = $in->param('file') || '';
my $escape_char = defined ($in->param('escape_char')) ? $in->param('escape_char') : '';
my ($query, $sth, $file_q, $delimiter_q, $rec_del_q, $escape_char_q);
if ($config{'demo_mode'}) { return &html_demo_prompt($in, 'Export is disabled in the demo'); }
else{
if (!$dbh) {&connect_db($in) or return undef; }
# quote the parameters.
$file_q = $dbh->quote($file);
$delimiter_q = $dbh->quote($delimiter);
$rec_del_q = "'" . $rec_del . "'";
$escape_char_q = $dbh->quote($escape_char);
$query = qq~SELECT *
INTO OUTFILE $file_q
FIELDS
TERMINATED BY $delimiter_q
ESCAPED BY $escape_char_q
LINES TERMINATED BY $rec_del_q
FROM $table~;
$sth = &exec_query($query) or return undef;
$sth->finish();
&show_tables($in, "File Exported Successfully.");
}
}
#=================================================#
# UTILITIES #
#=================================================#
sub set_col_not_null{
# ---------------------------------------------------
# Takes in a table name and the column name. Then
# function will make the column specified not nullable.
# It will first read in the current spec of the column
# and then reconstruct the spec to set the column not null.
my $in = shift;
my $table = $in->param('table') || '';
my $col = $in->param('col') || '';
my ($sth, $query, @attr, $new_spec, $col_q);
$col_q = $dbh->quote($col);
if (!$dbh) {&connect_db($in) or return undef; }
$query = "SHOW COLUMNS FROM $table LIKE $col_q";
$sth = &exec_query($query) or return undef;
@attr = $sth->fetchrow_array();
# reconstruct spec and set column not null.
for (my $i=0; $i < $sth->{NUM_OF_FIELDS}; $i++) {
if ($i == 2) {$new_spec .= ' NOT NULL ';}
elsif ( ($i == 4) && (defined($attr[$i])) ) {$new_spec .= " DEFAULT " . $dbh->quote($attr[$i]);}
elsif (($i == 3) || ($i == 6)) {}
else {$new_spec .= " $attr[$i] ";}
}
$sth->finish();
$query = "ALTER TABLE $table CHANGE $col $new_spec";
$sth = &exec_query($query) or return undef;
$sth->finish();
}
sub get_pri_key{
# ---------------------------------------------------
# Gets the primary key of the table specified.
my $table = shift;
my ($sth, $query, @ary, @pri_key);
@pri_key = ();
$query = "DESCRIBE $table";
$sth = &exec_query($query) or return undef;
while (@ary = $sth->fetchrow_array) {
if ($ary[3] eq 'PRI') { push(@pri_key, $ary[0]); }
}
$sth->finish();
return @pri_key;
}
sub get_table_list{
# ---------------------------------------------------
# Gets the list of tables which the query input is querying
# from. Since the function is only used in "sub table_browse";
# therefore, only commands in %browse_cmd is considered.
my $query = shift;
my (@query, $token, $flag, @table_list, $cur_token, $pre_token, $stop, $cmd, $explain_select, $got_list);
#strip beginning and endding space.
$query =~ s/^\s+//;
$query =~ s/\s+$//;
$query =~ s/(\r|\n)+/ /g;
@query = split /([ ,])/, $query;
$cmd = lc($query[0]);
# find table list from:
# 1. describe / desc
# 2. explain table
if (($cmd eq 'describe') || ($cmd eq 'desc') || ($cmd eq 'explain')) {
@table_list = ();
$flag = 0;
for (my $i=1; $i<=$#query;$i++){
if (defined($query[$i])){
if (($query[$i] ne '') && ($query[$i] ne ' ') && ($query[$i] ne ',') ){
# get the first name after the command.
if ($flag == 0) {
push (@table_list, $query[$i]);
my $tmp = lc($query[$i]);
if ($tmp eq 'select') { $explain_select = 1 }
$flag = 1;
}
}
}
}
$got_list = 1;
}
# find table list from queries like:
# 1. select queries
# 2. show queries
# 3. explain select ....
if (!$got_list || $explain_select) {
@table_list = ();
$flag = 0;
$stop = 0;
$pre_token = '';
foreach (@query) {
if (($_ ne '') && ($_ ne ' ')) {
$token = lc($_);
if ($flag == 1) {
# determine the type of the current token.
if ($token ne ',') { $cur_token = 'word' }
else { $cur_token = 'comma' }
# stop then the "from" clause ends
if (($cur_token eq 'word') && ($cur_token eq $pre_token) ) { $stop = 1; }
if (!$stop && $token ne ',') { push (@table_list, $_) }
$pre_token = $cur_token;
}
if ($token eq 'from') { $flag = 1; }
}
}
}
return @table_list;
}
sub form_fields{
# ---------------------------------------------------
# Create a form input table for insert and edit. $update
# is a flag indicating whether or not it is from edit. @value
# consists the list of original values (in order) in the
# record being updated. Note that in order to set a field
# to be null, the input value has to be null. In other words,
# if there is value in input field and null checkbox is checked,
# the null option will be overwritten and the value in the input
# field will be taken.
my($in, $update, @value) = @_;
my $table = $in->param('table') || '';
my ($query, $sth, $form_table, @ary, @type, @domain, @domain_new, %domain_h, $value_unquote,
$flag, $double_comma);
if (!$dbh) {&connect_db($in) or return undef; }
$query = "DESCRIBE $table";
$sth = &exec_query($query) or return undef;
$form_table = "
Fields
Type
Function
Value
";
if ($config{'insert_null'}) { $form_table .= "
Null
"; }
else {$form_table .= "";}
my $k = 0; # Value counter. Used to identify which element in @value is considered.
while (@ary = $sth->fetchrow_array) {
@type = split /[(),]/, $ary[1];
# Handle type 'Enum'
if ($type[0] eq 'enum') {
$form_table .= qq~\n
$ary[0]
enum
~ . &function_select($ary[0]) . qq~
~; }
else {$form_table .= qq~\n
~; }
}
else { $form_table .= qq~\n
~; }
}
}
# Handle type 'Set'
elsif($type[0] eq 'set'){
my $j = 0;
$form_table .= qq~\n
$ary[0]
set
~ . &function_select($ary[0]) . qq~
~;
# For update, check if '' is in the set.
@domain = split /(,)/, $value[$k];
foreach (@domain) {
if ($_ ne ',') {
if ($_ ne '') {push (@domain_new, $_) }
else {push (@domain_new, "''")}
}
}
if ($domain[$#domain] eq ',') { push (@domain_new, "''"); }
%domain_h = map{$_ => 1} @domain_new;
for (my $i=1; $i < ($#type + 1); $i++) {
if (defined($type[$i]) && $type[$i] ne '') {
if ($type[$i] ne "''") { ($value_unquote) = $type[$i] =~ m{^\'(([^\']|\'\')+)\'}; }
else { $value_unquote = $type[$i]; }
if ($value_unquote ne "''") { $value_unquote =~ s/''/'/g; }
# Create checkboxes for each element in the set. Checkboxes are checked if
# value is selected in the original set.
if ($domain_h{$value_unquote}){
$form_table .= qq~\n$value_unquote ~;
$j++;
}
else {
$form_table .= qq~\n$value_unquote ~;
$j++;
}
}
}
if ($config{'insert_null'}) {
if ($ary[2] eq 'YES') {
if ( !defined($value[$k]) && $update) {$form_table .= qq~
~; }
else{$form_table .= qq~\n
~;}
}
else { $form_table .= qq~
~; }
}
}
# Handle all other types
else {
$form_table .= qq~\n
$ary[0]
$ary[1]
~ . &function_select($ary[0]) . qq~
~;
if ($config{'insert_null'}) {
if ($ary[2] eq 'YES') {
if ( !defined($value[$k]) && $update) {$form_table .= qq~
~; }
else { $form_table .= qq~
~; }
}
else { $form_table .= qq~
~; }
}
}
$k++;
}
$form_table .= "
";
$sth->finish();
return $form_table;
}
sub compose_new_condition{
# ---------------------------------------------------
# Reconstructs the input from "sub form_fields" to an array
# of "field = value" pairs.
my $in = shift;
my $table = $in->param('table') || '';
my ($query, $prep, $sth, @ary, $value, @insert_fields, @type, @set, $new_record, $value_unquote);
$query = "DESCRIBE $table";
$prep = &exec_query($query) or return undef;
while (@ary = $prep->fetchrow_array) {
@type = split /[(),]/, $ary[1];
# Handle columns of type 'SET'
if ($type[0] eq 'set') {
my $j = 0; # checkbox counter
my $k = 0; # counter for how many checkboxes are checked.
# check each checkbox box to see if they are check.
for (my $i=1; $i < ($#type + 1); $i++) {
($value_unquote) = $type[$i] =~ m{^\'(([^\']|\'\')+)\'};
if (defined($type[$i])) {
if ( defined($in->param("*insert*_$ary[0]_set_$j")) ) {
if ( $in->param("*insert*_$ary[0]_set_$j") ne "''" ) { push (@set, $in->param("*insert*_$ary[0]_set_$j") ); }
else { push (@set, ''); }
$k++;
}
$j++;
}
}
$value = $dbh->quote( join(",", @set) );
# If none of the checkboxes is checked, check for null option.
if (!$k) {
if ($in->param("*insert*_$ary[0]_null")) { $value = 'NULL'; }
else { $value = '""'; }
}
}
# Handle all other types.
else {
# if nothing in input field.
if (!$in->param("*insert*_$ary[0]") && ($in->param("*insert*_$ary[0]") ne '0')) {
# check for null
if ($in->param("*insert*_$ary[0]_null")) { $value = 'NULL'; }
# check for function.
else {
if ( $in->param("*insert*_$ary[0]_function") ) {$value = $in->param("*insert*_$ary[0]_function") . '()'; }
else { $value = '""'; }
}
}
# check if any function is needed to apply on the input.
elsif ($in->param("*insert*_$ary[0]_function")){
$value = $in->param("*insert*_$ary[0]_function") . '(' . $dbh->quote($in->param("*insert*_$ary[0]")) .')';
}
# otherwise make the field equal to the value entered.
else{ $value = $dbh->quote($in->param("*insert*_$ary[0]")); }
}
push (@insert_fields, "$ary[0] = $value");
}
$prep->finish();
return (@insert_fields);
}
sub function_select{
# ---------------------------------------------------
# Creates enumeration of functions available in select input.
my $field = shift;
return GT_Template->parse ($config{'template_dir'} . '/functions.txt', { field => $field })
}
sub get_key_table{
# ---------------------------------------------------
# Creates a key/index table. A "drop" link is created
# together with each each read in.
my $in = shift;
my $data_source = $in->param('data_source') || '';
my $table = $in->param('table') || '';
my ($sth, $query, @ary, $unique, $non_unique, $key_name, $column_name, $keys, $key_table);
$query = "SHOW INDEX from $table";
$sth = &exec_query($query) or return undef;
while (@ary = $sth->fetchrow_array) {
my $non_unique = $ary[1];
my $key_name = $ary[2];
my $column_name = $ary[4];
if ($non_unique) {$unique = 'NO';}
else {$unique = 'YES';}
$keys .= qq~
"; }
else { $key_table = ''; }
return $key_table;
}
sub get_db{
# ---------------------------------------------------
# Gets the database name from the data source which is
# in the format "DBI:mysql:database_name:host"
my $db = shift;
my @dsn = split /([:])/, $db;
$db = $dsn[4];
return $db;
}
sub valid_name_check{
# ---------------------------------------------------
# Checks to see if the input database/table name is a
# valid one. The function checks the following:
# 1. if a name is entered at all;
# 2. if there are spaces in the name;
# 3. if the name is consisted of valid characters; and
# 4. if the name is consisted of only numbers.
my $name = shift;
$name =~ s/^\s+//;
$name =~ s/\s+$//;
my @name = split / /, $name;
if (!$name) { &sqlerr("Please provide a valid name."); }
elsif ($#name > 0) { &sqlerr("Spaces are not allowed in name."); }
elsif ($name =~ m/[^\w_\$]/){ &sqlerr("Invalid name. A name may consist of characters, numbers, and also '_' and '\$'."); }
elsif (!($name =~ m/\D/)) { &sqlerr("Invalid name. A name may not consist only of numbers."); }
else {return 1;}
}
sub concate_col_spec{
# ---------------------------------------------------
# Reconstruct the input variables into a string in the form
# "field_name(type(length_set) attribute DEFAULT default_value extra)"
my ($in, $i) = @_;
my $col_spec;
$col_spec = '';
$col_spec .= $in->param("field_$i") . ' ';
$col_spec .= $in->param("type_$i");
if ( $in->param("length_set_$i") ) { $col_spec .= '(' . $in->param("length_set_$i") . ')'; }
$col_spec .= ' ' . $in->param("attributes_$i") . ' ';
$col_spec .= $in->param("null_$i") . ' ';
if ( $in->param("default_$i") ) { $col_spec .= 'DEFAULT ' . $dbh->quote($in->param("default_$i")) . ' '};
$col_spec .= $in->param("extra_$i");
return $col_spec;
}
sub link_page {
# ---------------------------------------------------
# Provides hyperlinks to next, previous, or top pages when needed
my ($in, $rows, $table, $fields, $example, $index, $total_rec_num) = @_;
my ($data_source, $cur_page, $page, $output, $sort_index, $action, $where, $query, $cur_rec_num, $more_page);
$data_source = $in->param("data_source") || '';
$cur_page = $in->param("page") || 1;
$sort_index = $index;
$action = $in->param("browse_action") || $in->param("action") || '';
$where = $in->escape($in->param("where")) || '';
$query = $in->escape($in->param("query")) || '';
$example = $in->escape($example);
$cur_rec_num = ($cur_page - 1) * $config{'page_length'} + $rows;
if ($cur_rec_num < $total_rec_num) { $more_page = 1; }
else { $more_page = 0; }
$output = '';
# the very first page.
if ( ($cur_page == 1) and ($rows == $config{'page_length'}) and ($more_page)) {
$page = $cur_page + 1;
$output .= qq~< Next page >~;
}
# the very last page.
elsif ((!$more_page) and ($cur_page != 1)){
$page = $cur_page - 1;
$output .= qq~< Privious page > ~;
}
# any page between the first and the last page.
elsif ( ($cur_page != 1) and ($rows == $config{'page_length'}) and ($more_page)){
$page = $cur_page + 1;
$output .= qq~< Next page > ~;
$page = $cur_page - 1;
$output .= qq~< Privious page > ~;
}
# else there is only one page to display. As a result, no links are available.
# link to jump back to the first page.
if (($cur_page != 1)) {
$output .= qq~< Top page >~;
}
return $output;
}
sub link_page_jump{
# ---------------------------------------------------
# Produces a text field to let the user enter a number
# and the user will be brought to the page specified.
my($sth, $table, $where, $action, $query, $data_source, $pages, $output);
my ($in, $fields, $example, $index, $rows) = @_;
$data_source = $in->param("data_source") || '';
$table = $in->param("table") || '';
$where = $in->param("where") || '';
$action = $in->param("browse_action") || $in->param("action") || '';
$pages = $rows / $config{'page_length'};
if (($rows % $config{'page_length'}) != 0) { $pages = int($pages) + 1 }
if ($rows > $config{'page_length'}) {
return &html_page_jump($in, $pages, $fields, $example, $index);
}
}
sub record_count{
# ---------------------------------------------------
# Counts to total number of records/rows in the table
# specified.
my ($sth, $rows, $query);
my $tablename = shift;
$query = "SELECT COUNT(*) FROM $tablename";
$sth = &exec_query($query) or return undef;
$rows = $sth->fetchrow();
$sth->finish();
return $rows;
}
sub get_col_type{
# ---------------------------------------------------
# Gets the type each field/column of the table specified.
my $table = shift;
my ($sth, $query, @ary, @type_ary);
$query = "DESCRIBE $table";
$sth = &exec_query($query) or return undef;
while (@ary = $sth->fetchrow_array()) {
push (@type_ary, $ary[1]);
}
$sth->finish();
return @type_ary;
}
sub do_login{
# ---------------------------------------------------
# Assign login info to cookies.
my $in = shift;
my ($db_host, $db_user, $db_pass);
($db_host, $db_user, $db_pass) = &assign_auth_cookie($in);
# redirects the user to the database list if init_login flag is on.
if ($in->param('init_login')) {
my $redirect_url = $config{'script_url'}.'?do='.$in->param('do').'&data_source='.$in->param('data_source').'&init_login='.$in->param('init_login');
print $in->redirect(-URL => $redirect_url,
-COOKIE => [$db_host, $db_user, $db_pass]);
return 1;
}
else{ print $in->header( -COOKIE => [$db_host, $db_user, $db_pass]); }
&html_back($in);
if ( $config{'debug'} ) {&cgierr("debug");}
}
sub assign_auth_cookie{
# ---------------------------------------------------
# assign values to cookies used in the scirpt.
my $in = shift;
my $host = $in->cookie( -NAME => $config{'db_host_cookie_name'},
-VALUE => $in->param('db_host'),
-PATH => "/",
);
my $user = $in->cookie( -NAME => $config{'db_user_cookie_name'},
-VALUE => $in->param('db_user'),
-PATH => "/",
);
my $pass = $in->cookie( -NAME => $config{'db_pass_cookie_name'},
-VALUE => $in->param('db_pass'),
-PATH => "/",
);
return ($host, $user, $pass);
}
sub assign_url_cookie{
# ---------------------------------------------------
# assign the current url to cookie.
my $in = shift;
my $url = $in->cookie( -NAME => $config{'url_cookie_name'},
-VALUE => $in->self_url,
);
print $in->header(-COOKIE => $url);
}
sub do_logout{
# ---------------------------------------------------
# Logs the users out by making all the cookies used in
# the script expire.
my $in = shift;
my ($host, $user, $pass, $url);
($host, $user, $pass, $url) = &cookie_cleanup($in);
print $in->header(-COOKIE => [$host, $user, $pass, $url]);
&html_logout;
if ( $config{'debug'} ) {&cgierr("debug");}
}
sub cookie_cleanup{
# ---------------------------------------------------
# Makes all cookies expire.
my $in = shift;
my $host = $in->cookie( -NAME => $config{'db_host_cookie_name'},
-VALUE => '',
-EXPIRES => "-1h");
my $user = $in->cookie( -NAME => $config{'db_user_cookie_name'},
-VALUE => '',
-EXPIRES => "-1h");
my $pass = $in->cookie( -NAME => $config{'db_pass_cookie_name'},
-VALUE => '',
-EXPIRES => "-1h");
my $url = $in->cookie( -NAME => $config{'url_cookie_name'},
-VALUE => '',
-EXPIRES => "-1h");
return ($host, $user, $pass, $url);
}
sub alias_name_check{
# ---------------------------------------------------
# Checks to see if the input table name is of the format
# 1. database.table.column OR
# 2. table.column
my ($table, $in) = @_;
my @alias_table = split /[.]/, $table;
if ($#alias_table > 0) { return &html_demo_prompt($in, 'Action not allowed in demo mode'); }
}
sub connect_db{
# ---------------------------------------------------
# Tries to connect the database with user name and password
# provided first. If access denied then tries connecting
# again with user name and password undefined. If both
# fail then an login page will be prompted.
my $in = shift;
my ($db_host, $username, $password, $message);
my $data_source = $in->param("data_source") || 'DBI:mysql:';
# gets user data from cookies.
$username = $in->cookie($config{'db_user_cookie_name'}) || '';
$password = $in->cookie($config{'db_pass_cookie_name'}) || '';
$db_host = $in->cookie($config{'db_host_cookie_name'}) || '';
if ($db_host && ($data_source eq 'DBI:mysql:')) { $data_source = "dbi:mysql:host=$db_host"}
elsif ($db_host) { $data_source = $data_source . ":$db_host" }
warn "($$): Connecting $data_source ..\n";
###############################
if($config{'demo_mode'}){
my $dsn = lc($data_source);
if (($dsn ne "dbi:mysql:$config{'demo_db'}:$config{'demo_host'}") and ($dsn ne 'dbi:mysql:') and ($dsn ne "dbi:mysql:host=$config{'demo_host'}")) {
if ($db_host ne 'localhost') {
return &html_demo_prompt($in, "Please use $config{'demo_host'} as host.");
}
else {
return &html_demo_prompt($in, "Please use database $config{'demo_db'} for the demo.");
}
}
else{
$dbh = DBI->connect("$data_source", "$username", "$password", { RaiseError => 0, PrintError => 0, AutoCommit => 1 });
if (not $dbh){
# If the connection fails then the user name and/or the password may be wrong or that they are correct but the
# the connection fail for some other reason
if ($DBI::errstr =~ m/(.ccess denied)/) { # If the user name and/or the password is incorrect
$dbh = DBI->connect("$data_source", undef, undef, { RaiseError => 0, PrintError => 0, AutoCommit => 1 })
or return &sqlerr("$DBI::errstr.");
}
elsif ($DBI::errstr =~ m/an't connect to/) {
$message = qq~Connection to MySQL failed.
The hostname may be different or the server may be down.
Please enter a new hostname and try again.~;
&html_login($in, $message);
if ( $config{'debug'} ) {&cgierr("debug");}
return undef;
}
else { &cgierr("connection failed: $DBI::errstr"); }
}
}
}
###############################
else {
$dbh = DBI->connect("$data_source", "$username", "$password", { RaiseError => 0, PrintError => 0, AutoCommit => 1 });
if (not $dbh){
# If the connection fails then the user name and/or the password may be wrong or that they are correct but the
# the connection fail for some other reason
if ($DBI::errstr =~ m/(.ccess denied)/) { # If the user name and/or the password is incorrect
$dbh = DBI->connect("$data_source", undef, undef, { RaiseError => 0, PrintError => 0, AutoCommit => 1 })
or return &sqlerr("$DBI::errstr.");
}
elsif ($DBI::errstr =~ m/an't connect to/) {
$message = qq~Connection to MySQL failed.
The hostname may be different or the server may be down.
Please enter a new hostname and try again.~;
&html_login($in, $message);
if ( $config{'debug'} ) {&cgierr("debug");}
return undef;
}
else { &cgierr("connection failed: $DBI::errstr"); }
}
}
return 1;
}
sub exec_query{
# ---------------------------------------------------
# Send the input qeury MySQL thru database handler.
my $query = shift;
my ($sth);
$sth = $dbh->prepare($query) or return &sqlerr("$DBI::errstr.
Query: $query");
$sth->execute() or return &sqlerr("$DBI::errstr.
Query: $query");
return $sth;
}
sub sqlerr{
# ---------------------------------------------------
# Error prompt.
my $in = new CGI;
my $error = shift;
my ($message, $init_login);
$init_login = 0;
# If access denied, then a login page will be displayed.
if ($error =~ m/(.ccess denied)/){
$message = "Permission to perform action denied. Please enter your user name and password";
if (!$in->param || ($in->param('do') eq 'login')) {
$message = 'Welcome! Please enter your log-in info.';
if ($config{'demo_mode'}) { $message .= "( For the demo, you can use Host: $config{'demo_host'} ; User: $config{'demo_user'} ; Pass: $config{'demo_pass'} )"; }
$init_login = 1;
}
elsif ($in->param('init_login')){
if ($config{'demo_mode'}) { $message = "Login failed. ( Host: $config{'demo_host'} ; User: $config{'demo_user'} ; Pass: $config{'demo_pass'} )"; }
else { $message = 'Login failed. Please enter another hostname/username/password.'; }
$init_login = 1;
}
&html_login($in, $message, $init_login);
if ( $config{'debug'} ) {&cgierr("debug");}
return undef;
}
# If connect error, login page is prompted to let the user to enter another
# host name.
elsif ($error =~ m/(.an't connect to)/) {
$message = qq~Connection to MySQL failed.
The hostname may be different or the server may be down.
Please enter a new hostname and try again.~;
&html_login($in, $message, $init_login);
if ( $config{'debug'} ) {&cgierr("debug");}
return undef;
}
# display the error message.
else{
if ($config{'debug'}) {
&cgierr($error);
}
else {
html_sqlerr($in, $error);
if ( $config{'debug'} ) {&cgierr("debug");}
return undef;
}
}
}
sub cgierr{
# --------------------------------------------------------
# Displays any errors and prints out FORM and ENVIRONMENT
# information. Useful for debugging.
#
my $in = new CGI;
print $in->header();
my ($key, $env);
my ($error, $nolog) = @_;
print "";
print "";
print "
\n\nCGI ERROR\n==========================================\n";
$error and print "Error Message : $error\n";
$0 and print "Script Location : $0\n";
$] and print "Perl Version : $]\n";
print "\nConfiguration\n-------------------------------------------\n";
foreach $key (sort keys %config) {
my $space = " " x (20 - length($key));
print "$key$space: $config{$key}\n";
}
print "\nCookies\n-------------------------------------------\n";
print "$config{'db_user_cookie_name'} : " . $in->cookie($config{'db_user_cookie_name'});
print "\n$config{'db_pass_cookie_name'} : " . $in->cookie($config{'db_pass_cookie_name'});
print "\n$config{'db_host_cookie_name'} : " . $in->cookie($config{'db_host_cookie_name'});
print "\n$config{'url_cookie_name'} : " . $in->cookie($config{'url_cookie_name'});
print "\n\nForm Variables\n-------------------------------------------\n";
foreach $key (sort $in->param) {
my $space = " " x (20 - length($key));
print "$key$space: " . $in->param($key) . "\n";
}
print "\nEnvironment Variables\n-------------------------------------------\n";
foreach $env (sort keys %ENV) {
my $space = " " x (20 - length($env));
print "$env$space: $ENV{$env}\n";
}
print "\nStack Trace \n-------------------------------------------\n";
my $i = 0;
while (my ($file, $line, $sub) = (caller($i++))[1,2,3]) {
print qq!($sub) called from ($file) line ($line) \n!;
}
print "\n
";
&log_action ("CGI ERROR: $error") if (!$nolog and $config{'logfile'});
exit;
}