#!/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~$database_list$drop_cmd~; } } else{ $database_list = qq~$db\n~; $drop_cmd = qq~Drop\n~; $db_table_rows .= qq~$database_list$drop_cmd~; } } $sth->finish; $db_table = qq~$db_table_rows
DATABASEACTION
~; 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~$table Browse Select Properties Insert Drop Empty ~ . &record_count($table) . qq~ \n~; } $sth->finish(); &html_table($in, $table_tables, $feedback); } # ======================= # # Table Browse/Select # # ======================= # sub table_browse{ # --------------------------------------------------- # Browse, Select/Search # The function do a "select * from table" to do a browse # and will display the results according to the select # criteria specified by user in "select". If a primary # key exists in the table, then "edit" and "drop" links # are also created with each record. # # SQL-Monitor # Queries entered in SQL monitor that produces results is # displays it's result using this sub-routine as well. # These queries include explain, select, describe, and desc. my $in = shift; my ($where_clause, $start_row, $empty_set, @pri_key, $prep, $prep2, $sth, $rows, @ary, $index, $col_name, $table_records, $record, $query, $cells, $page_jump, $page_link, $rows_in_page, @fields, @example, @record_modify, $record_modify, $edit_link, @table_list, $table_num, $pri_key_count, $pri_key, $query_printed, $query_count); my $data_source = $in->param("data_source") || ''; my $table = $in->param("table") || ''; my $page = $in->param("page") || 1; my $action = $in->param("browse_action") || $in->param("action") || ''; my $fields = $in->param("fields") || ''; my $where = $in->param("where") || ''; my $example = $in->param("example") || ''; if ($config{'demo_mode'}) { &alias_name_check($table, $in); } # The first row of the page arrived. $start_row = (($page - 1) * $config{'page_length'}); if (!$dbh) {&connect_db($in) or return undef; } if ($action eq 'browse' || $action eq 'select') { # do a quick select statement so that we can get the name of the columns. $query = qq~SELECT * FROM $table LIMIT 1~; $prep = &exec_query($query) or return undef; } if ($action eq 'browse') { $fields = '*'; $index = $in->param("sort_index") || $prep->{'NAME'}->[$config{'sort_default'}]; $prep->finish(); } elsif ($action eq 'select') { # SELECT clause. if (!$fields) { @fields = (); for (my $i = 0; $i < $prep->{NUM_OF_FIELDS}; $i++) { if ($in->param("*select_field*_$prep->{NAME}->[$i]") ne '') { push( @fields, $in->param("*select_field*_$prep->{NAME}->[$i]") ); } } $fields = join ",", @fields; } # WHERE clause. if ($where) { $where_clause = "WHERE $where"; } # Query by example. if (!$example) { @example = (); for (my $i = 0; $i < $prep->{NUM_OF_FIELDS}; $i++) { if ($in->param("*example*_$prep->{NAME}->[$i]") ne '') { my $temp = $prep->{NAME}->[$i] . ' like ' . $dbh->quote( $in->param("*example*_$prep->{NAME}->[$i]") ); push( @example, $temp ); } } $example = join " and ", @example; } if ($example) { if ($where_clause) { $where_clause .= " and $example"; } else { $where_clause = "WHERE $example"; } } $query = qq~SELECT $fields FROM $table $where_clause LIMIT 1~; $prep2 = &exec_query($query) or return undef; $index = $in->param("sort_index") || $prep2->{NAME}->[$config{'sort_default'}]; $prep->finish(); $prep2->finish(); } @pri_key = (); $pri_key = ''; if ($action eq 'browse' || $action eq 'select') { # Prepare the contents in the table selected. @pri_key = &get_pri_key($table); $pri_key = join ",", @pri_key; if ($pri_key ne '') { $pri_key = ',' . $pri_key; } # the actual query sent to statement handler. The # primary key is selected for delete and edit. $query = qq~SELECT $fields $pri_key FROM $table $where_clause ORDER BY $index LIMIT $start_row, $config{'page_length'}~; # The query that gets printed in SQL-Message. $query_printed = qq~SELECT $fields FROM $table $where_clause ORDER BY $index LIMIT $start_row, $config{'page_length'}~; # counts the total number of resulting records from browse/select $query_count =qq~SELECT COUNT(*) FROM $table $where_clause~; $sth = &exec_query($query_count) or return undef; ($total_rec_num) = $sth->fetchrow(); $sth->finish(); } else{ # from SQL Monitor. if ($config{'demo_mode'}) { return &html_demo_prompt($in, 'Browse actions are disabled except for select and browse.'); } else{ $query = $in->param("query") || ''; @table_list = &get_table_list($query); if ($#table_list == 0) { ($table) = @table_list; } } } # Execute query. $sth = &exec_query($query) or return undef; $rows = $sth->rows; if ($action eq 'monitor') { $total_rec_num = $rows; $rows_in_page = $rows - $start_row; if ($rows_in_page > $config{'page_length'}) { $rows_in_page = $config{'page_length'} } } else { $rows_in_page = $rows; } $page_jump = &link_page_jump($in, $fields, $example, $index, $total_rec_num); # Links to next/previous/top page if there is any. $page_link = &link_page($in, $rows_in_page, $table, $fields, $example, $index, $total_rec_num); my $example_esc = $in->escape($example); my $where_esc = $in->escape($where); my $query_esc = $in->escape($query); if (@pri_key != ()) { $pri_key_count = $#pri_key + 1; } else {$pri_key_count = 0; } # Display column names $col_name = ''; if ($action eq 'browse' || $action eq 'select') { for (my $i = 0; $i < $sth->{NUM_OF_FIELDS}- $pri_key_count; $i++) { $col_name .= qq~\n$sth->{NAME}->[$i]~; } } else { for (my $i = 0; $i < $sth->{NUM_OF_FIELDS}- $pri_key_count; $i++) { $col_name .= qq~\n$sth->{NAME}->[$i]~; } } $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 .= " "; } } else { if ($config{'show_null'}) { $record .= "NULL"; } else { $record .= "$ary[$i]"; } } } # if there are any primary keys, then push "pri = value" # into @record_modify. else{ my $cell = $ary[$i]; $cell = $dbh->quote($cell); my $col_name = $sth->{NAME}->[$i]; push (@record_modify, $col_name . ' = ' . $cell); } } if ((@pri_key != ()) && ($action ne 'monitor')) { $record_modify = join ' and ', @record_modify; $record_modify = $in->escape($record_modify); $table_records .= qq~ $record
Edit Delete \n~; } else { $table_records .= qq~$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 .= ""; } # compose "query by example" input fields. $example_fields .= qq~\n$prep->{NAME}->[$i]$type_ary[$i]~; } $select_table = "
" . $select_fields . "
"; $example_table = "" . $example_fields . "
FieldsTypeValue
"; $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" . join ( "" , @ary) . ""; $table_property_row .= qq~\n\t
Change~; $table_property_row .= qq~\n\tDrop~; $table_property_row .= qq~\n\tPrimary~; $table_property_row .= qq~\n\tIndex~; $table_property_row .= qq~\n\tUnique~; } $sth->finish(); # for display purpose, each empty cell is replace with a space. $table_property_row =~ s/<\/TD>/\ \;<\/TD>/g; $query = "describe $table"; $sth = &exec_query($query) or return undef; # Construct the table. $table_property = ""; $table_property .= "\n"; $table_property .= $table_property_row; $table_property .= "
". join ("", @{$sth->{NAME}}) . "ACTION
"; $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 = ""; if ($config{'insert_null'}) { $form_table .= ""; } 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~; } 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~; } else{$form_table .= qq~\n~;} } else { $form_table .= qq~~; } } } # Handle all other types else { $form_table .= qq~\n~; } else { $form_table .= qq~~; } } else { $form_table .= qq~~; } } } $k++; } $form_table .= "
FieldsTypeFunctionValueNull
$ary[0]enum~ . &function_select($ary[0]) . qq~
$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~
$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~
"; $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~$key_name$unique$column_name Drop~; } $sth->finish(); if ($keys) { $key_table = "$keys
KeynameUniqueFieldAction
"; } 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; }