home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / FAQ / discus_admin_1357211388 / source / adm-db.pl < prev    next >
Text File  |  2009-11-06  |  13KB  |  420 lines

  1. # FILE: adm-db.pl
  2. # DESCRIPTION: Administrator's Interface to Manage Database
  3. #-------------------------------------------------------------------------------
  4. # DISCUS COPYRIGHT NOTICE
  5. #
  6. # Discus is copyright (c) 2002 by DiscusWare, LLC, all rights reserved.
  7. # The use of Discus is governed by the Discus License Agreement which is
  8. # available from the Discus WWW site at:
  9. #    http://www.discusware.com/discus/license
  10. #
  11. # Pursuant to the Discus License Agreement, this copyright notice may not be
  12. # removed or altered in any way.
  13. #-------------------------------------------------------------------------------
  14.  
  15. use strict;
  16. use vars qw($GLOBAL_OPTIONS $DCONF $PARAMS);
  17.  
  18. ###
  19. ### DATABASE_admin
  20. ###
  21. ### Runs the Database Manager
  22. ###
  23.  
  24. sub DATABASE_admin {
  25.     my ($FORMref) = @_;
  26.     my $result = check_password($FORMref->{username}, undef, { type_required => 'moderator' }, $FORMref->{'COOKIE'});
  27.     bad_login( { bad_database => 1 } ) if scalar(@{ $result }) == 0;
  28.     bad_login( { superuser_required => 1 } ) if $result->[0]->{user} ne $DCONF->{superuser};
  29.     $PARAMS->{no_db_connect} = 1;
  30.     dreq("dbint");
  31.     $PARAMS->{no_db_connect} = 0;
  32.     touch_createfile("$DCONF->{admin_dir}/data/db.txt");
  33.     if ($FORMref->{'action'} eq "database-import") {
  34.         database_import($FORMref->{imports}, $FORMref, $result);
  35.         database_manager($FORMref, $result->[0]->{user}, { what => 2, menu => 2 });
  36.     }
  37.     if ($FORMref->{action} eq "database-imp") {
  38.         dreq("sql-imex-PRO");
  39.         sql_import_handler($FORMref, $result, undef);
  40.     }
  41.     if ($FORMref->{'action'} eq "database-export") {
  42.         database_export($FORMref->{exports}, $FORMref, $result);
  43.         database_manager($FORMref, $result->[0]->{user}, { what => 4, menu => 3 });
  44.     }
  45.     if ($FORMref->{action} eq "database-exp") {
  46.         dreq("sql-imex-PRO");
  47.         sql_export_handler($FORMref, $result, undef);
  48.     }
  49.     if ($FORMref->{'action'} eq "database-setup") {
  50.         database_save_settings($FORMref->{database}, $FORMref->{dbusername}, $FORMref->{dbpassword}, $FORMref->{dbprefix}, $FORMref->{dbsocket});
  51.         database_manager($FORMref, $result->[0]->{user}, { what => 1 });
  52.     }
  53.     if ($FORMref->{'action'} eq "database-init") {
  54.         my $success = database_initialize($FORMref->{init});
  55.         database_manager($FORMref, $result->[0]->{user}, { what => $success, menu => 1 });
  56.     }
  57.     if ($FORMref->{'action'} eq "database") {
  58.         database_manager($FORMref, $result->[0]->{user});
  59.     }
  60.     if ($FORMref->{'action'} eq "database-toggle") {
  61.         dreq("adm-opts");
  62.         if ($FORMref->{source} == 1) {
  63.             $PARAMS->{dbh} = db_connect();
  64.         }
  65.         options_save({ database => 0+$FORMref->{source} });
  66.         database_manager($FORMref, $result->[0]->{user}, { toggle => 1 });
  67.     }
  68. }
  69.  
  70. ###
  71. ### database_get_tables
  72. ###
  73. ### Methods to work around broken $dbh->tables() on some platforms.  Sigh.
  74. ###
  75.  
  76. sub database_get_tables {
  77.     my ($dbh, $prefix) = @_;
  78.     my %found = map { $_, 1 } $dbh->tables;
  79.     my @out = ();
  80.     my @possible = map { join("", $prefix, $_) } database_possible_tables();
  81.     foreach my $poss (@possible) {
  82.         if (defined $found{$poss}) {
  83.             push @out, $poss;
  84.             next;
  85.         }
  86.         my $str = "SELECT COUNT(*) FROM $poss;";
  87.         my $sth = $dbh->prepare($str) or do { next; };
  88.         $sth->execute() or do { next; };
  89.         push @out, $poss;
  90.     }
  91.     return @out;
  92. }
  93.  
  94. ###
  95. ### database_stats
  96. ###
  97. ### Gets stats from the MySQL database
  98. ###
  99.  
  100. sub database_stats {
  101.     my ($subst, $dbh) = @_;
  102.     return undef if ! defined $dbh;
  103.     my $query02 = "SHOW TABLE STATUS";
  104.     my @k = ();
  105.     if (my $sth2 = $dbh->prepare($query02)) {
  106.         $sth2->execute();
  107.         while (my $k = $sth2->fetchrow_hashref()) {
  108.             my $pct = $k->{Max_data_length} == 0 ? 1 : $k->{Data_length} / $k->{Max_data_length};
  109.             $pct = sprintf("%2.4f", $pct*100);
  110.             $k->{percent} = $pct;
  111.             push @k, \%{ $k };
  112.         }
  113.         $sth2->finish();
  114.     }
  115.     @k = sort { case_lower($a->{Name}) cmp case_lower($b->{Name}) } @k;
  116.     $subst->{stables} = \@k;
  117.     my $query03 = "SHOW VARIABLES;";
  118.     if (my $sth3 = $dbh->prepare($query03)) {
  119.         $sth3->execute();
  120.         while (my $k = $sth3->fetchrow_arrayref()) {
  121.             next if $k->[0] ne "version";
  122.             $subst->{general}->{mysql_version} = $k->[1];
  123.             last;
  124.         }
  125.         $sth3->finish();
  126.     }
  127.     return $subst;
  128. }
  129.  
  130. ###
  131. ### database_initialize
  132. ###
  133. ### Initializes a database following request from Database Manager.
  134. ###
  135.  
  136. sub database_initialize {
  137.     my ($init) = @_;
  138.     undef my $hashref;
  139.     foreach my $xz (split(/,/, $init)) {
  140.         $hashref->{$xz} = 1;
  141.     }
  142.     if ($GLOBAL_OPTIONS->{'database'} == 1) {
  143.         error_message("Initialization Error", "Cannot initialize table "passwd" when database is being used for authentication!  Deselect this initialization or toggle off the database!", 0, 1) if $hashref->{passwd};
  144.     }
  145.     my ($dbh2, $error) = db_connect(2);
  146.     database_create_tables($dbh2, $hashref);
  147.     $dbh2->disconnect();
  148.     return 3;
  149. }
  150.  
  151. ###
  152. ### database_import
  153. ###
  154. ### Imports values from flat text files into database.
  155. ###
  156.  
  157. sub database_import {
  158.     my ($import_list, $FORMref, $result) = @_;
  159.     my %imp = map { $_, 1 } split(/,/, $import_list);
  160.     my $dbh = db_connect();
  161.     if ($imp{counters}) {
  162.         dreq("posting");
  163.         db_sql_query({ ID => 1, value => 100+get_number() }, "counters", "replace", undef, $dbh);
  164.         db_sql_query({ ID => 2, value => 100+get_postindex() }, "counters", "replace", undef, $dbh);
  165.         delete $imp{counters};
  166.     }
  167.     if (scalar(keys(%imp)) == 0) {
  168.         $dbh->disconnect();
  169.         return 1;
  170.     }
  171.     dreq("sql-imex-PRO");
  172.     return sql_import_handler($FORMref, $result, $dbh, \%imp);
  173. }
  174.  
  175. ###
  176. ### database_export
  177. ###
  178. ### Exports values to flat text files from the database.
  179. ###
  180.  
  181. sub database_export {
  182.     my ($import_list, $FORMref, $result) = @_;
  183.     my %imp = map { $_, 1 } split(/,/, $import_list);
  184.     if ($imp{counters}) {
  185.         my $r1 = db_sql_query({}, "counters", "select", { ID => 1 });
  186.         my @z1 = (); $z1[0] = join("", 100 + $r1->[0]->{value}, "\n");
  187.         writefile("$DCONF->{admin_dir}/data.txt", \@z1, "database_export", { no_lock => 1, no_unlock => 1 });
  188.         my $r2 = db_sql_query({}, "counters", "select", { ID => 2 });
  189.         my @z2 = (); $z2[0] = join("", 100 + $r2->[0]->{value}, "\n");
  190.         writefile("$DCONF->{admin_dir}/postindex.txt", \@z2, "database_export", { no_lock => 1, no_unlock => 1 });
  191.         delete $imp{counters};
  192.     }
  193.     return 1 if scalar(keys(%imp)) == 0;
  194.     dreq("sql-imex-PRO");
  195.     return sql_export_handler($FORMref, $result, \%imp);
  196. }
  197. ###
  198. ### database_db_param
  199. ###
  200. ### Reads database parameters
  201. ###
  202.  
  203. sub database_db_param {
  204.     undef my $db_param;
  205.     my $db = readfile("$DCONF->{admin_dir}/data/db.txt", "DATABASE_admin", { no_lock => 1, no_unlock => 1, zero_ok => 1} );
  206.     foreach my $x (@{ $db }) {
  207.         if ($x =~ m|^(\w+)=(.*)|) {
  208.             $db_param->{$1} = $2;
  209.         }
  210.     }
  211.     return $db_param;
  212. }
  213.  
  214. ###
  215. ### database_possible_tables
  216. ###
  217. ### Tables that Discus uses
  218. ###
  219.  
  220. sub database_possible_tables {
  221.     my @possible = ('counters', 'locks');
  222.     push @possible, ('users', 'log', 'passwd', 'search') if $DCONF->{pro};
  223.     push @possible, ('tree') if $DCONF->{pro} && $DCONF->{tree_as_sql};
  224.     return @possible;
  225. }
  226.  
  227. ###
  228. ### database_manager
  229. ###
  230. ### Database Manager interface
  231.  
  232. sub database_manager {
  233.     my ($FORMref, $username, $stuff) = @_;
  234.     undef my $subst;
  235.     $subst->{stuff} = $stuff;
  236.     $subst->{db_param} = database_db_param();
  237.     $subst->{general}->{username} = $username;
  238.     my ($dbh, $error) = db_connect(2);
  239.     my @tables = map { join("", $PARAMS->{db_prefix}, $_) } database_possible_tables();
  240.     my %h = map { $_, 1 } @tables;
  241.     if (defined($dbh) && $subst->{db_param}->{database} =~ /\S/) {
  242.         $subst->{'connect'}->{'status'} = 1;
  243.         my $table_ctr = 0;
  244.         my $q =quotemeta(trim($subst->{db_param}->{prefix}));
  245.         foreach my $xy (database_get_tables($dbh, $PARAMS->{db_prefix})) {
  246.             next if ! $h{$xy};
  247.             my $xy2 = $xy =~ m|^$q\_?(.+)| ? $1 : $xy;
  248.             $table_ctr ++;
  249.             $subst->{'exists'}->{$xy2} = 1;
  250.             my $str = "SELECT COUNT(*) FROM $xy;";
  251.             my $sth = $dbh->prepare($str) || error_message("SQL error", "Could not prepare [$str]:" . $dbh->errstr);
  252.             $sth->execute() || error_message("SQL error", "Could not execute [$str]: " . $dbh->errstr);
  253.             my $rf = $sth->fetchrow_hashref();
  254.             $subst->{'count'}->{$xy2} = $rf->{'COUNT(*)'};
  255.         }
  256.         $subst = database_stats($subst, $dbh) if $FORMref->{menu} == 5;
  257.         $subst->{'general'}->{'ok_to_toggle_on'} = 0;
  258.         if ($table_ctr == scalar @tables) {
  259.             $subst->{'general'}->{'ok_to_toggle_on'} = 1;
  260.             if ($DCONF->{pro}) {
  261.                 my $stha = $dbh->prepare("SELECT pass FROM $PARAMS->{db_prefix}passwd WHERE user = ?");
  262.                 if ($stha->execute($DCONF->{superuser})) {
  263.                     my $j = $stha->fetchrow_hashref();
  264.                     $subst->{'general'}->{'ok_to_toggle_on'} = 2 if $j->{pass} eq "";
  265.                     $stha->finish();
  266.                 } else {
  267.                     $subst->{'general'}->{'ok_to_toggle_on'} = 2;
  268.                 }
  269.             }
  270.         }
  271.         $dbh->disconnect();
  272.     } elsif (defined $dbh) {
  273.         $subst->{'general'}->{'ok_to_toggle_on'} = 0;
  274.         $subst->{'connect'}->{'status'} = 2;
  275.     } else {
  276.         $subst->{'general'}->{'ok_to_toggle_on'} = 0;
  277.         $subst->{'connect'}->{'status'} = 0;
  278.         $subst->{'connect'}->{'message'} = $error;
  279.     }
  280.     $subst->{'general'}->{'url'} = "$PARAMS->{cgiurl}?action=database&username=$username";
  281.     $subst->{'general'}->{'menu'} = (defined $stuff->{menu} ? $stuff->{menu} : $FORMref->{'menu'});
  282.     screen_out("database", $subst);
  283. }
  284.  
  285.  
  286. ###
  287. ### database_create_tables
  288. ###
  289. ### Creates tables in a database, initializing it for first use.
  290. ###
  291.  
  292. sub database_create_tables {
  293.     my ($dbh, $tables_do) = @_;
  294.     my @tables = database_get_tables($dbh, $PARAMS->{db_prefix});
  295.     my $existing_table = {};
  296.     my $m = quotemeta($PARAMS->{db_prefix});
  297.     foreach my $x (@tables) {
  298.         my $k = $x;
  299.         $k =~ s/^$m//;
  300.         $existing_table->{$k} = 1;
  301.     }
  302.     if ($tables_do->{users} || $tables_do->{passwd}) {
  303.         my $statement = "CREATE TABLE $PARAMS->{db_prefix}users (
  304.             user VARCHAR(100) PRIMARY KEY,
  305.             pass TEXT,
  306.             email TEXT,
  307.             fullname TEXT,
  308.             edit INT,
  309.             notify TEXT,
  310.             ctime INT,
  311.             stime VARCHAR(40),
  312.             atime VARCHAR(40),
  313.             groups TEXT,
  314.             picture TEXT,
  315.             prefs TEXT,
  316.             favorites TEXT,
  317.             signature TEXT,
  318.             status INT,
  319.             posts INT,
  320.             idnum INT,";
  321.         for (my $i = 1; $i <= 20; $i++) {
  322.             $statement .= "personal$i TEXT,\n";
  323.         }
  324.         for (my $i = 1; $i <= 10; $i++) {
  325.             $statement .= "custom$i TEXT,\n";
  326.             $statement .= "customdesc$i TEXT,\n";
  327.         }
  328.         $statement =~ s/,\n$//;
  329.         $statement .= ");";
  330.         if ($tables_do->{users}) {
  331.             db_query("DROP TABLE $PARAMS->{db_prefix}users;", $dbh, 1) if ($existing_table->{users});
  332.             db_query($statement, $dbh, 0);
  333.         }
  334.         $statement =~ s/CREATE TABLE $PARAMS->{db_prefix}users/CREATE TABLE $PARAMS->{db_prefix}passwd/;
  335.         if ($tables_do->{passwd}) {
  336.             db_query("DROP TABLE $PARAMS->{db_prefix}passwd;", $dbh, 1) if ($existing_table->{passwd});
  337.             db_query($statement, $dbh, 0);
  338.         }
  339.     }
  340.     if ($tables_do->{tree}) {
  341.         my $lstatement = "CREATE TABLE $PARAMS->{db_prefix}tree (
  342.             page INT PRIMARY KEY NOT NULL,
  343.             level INT,
  344.             topic INT,
  345.             parent INT,
  346.             name TEXT,
  347.             param TEXT,
  348.             islink INT,
  349.             url TEXT,
  350.             posts INT,
  351.             subs INT,
  352.             properties TEXT,
  353.             originator TEXT,
  354.             last_poster TEXT,
  355.             lastmod INT,
  356.             post_list TEXT,
  357.             onpage_order INT,
  358.             overall_order INT
  359.         );";
  360.         db_query("DROP TABLE $PARAMS->{db_prefix}tree;", $dbh, 1) if ($existing_table->{tree});
  361.         db_query($lstatement, $dbh, 0);
  362.     }
  363.     if ($tables_do->{log}) {
  364.         my $lstatement = "CREATE TABLE $PARAMS->{db_prefix}log (
  365.             postnum INT PRIMARY KEY NOT NULL,
  366.             postby TEXT,
  367.             posttime INT,
  368.             posttopic INT,
  369.             postpage INT,
  370.             postip VARCHAR(20),
  371.             posthost VARCHAR(100),
  372.             firstfew TEXT,
  373.             author TEXT);";
  374.         db_query("DROP TABLE $PARAMS->{db_prefix}log;", $dbh, 1) if ($existing_table->{log});
  375.         db_query($lstatement, $dbh, 0);
  376.     }
  377.     if ($tables_do->{search}) {
  378.         my $sstatement = "CREATE TABLE $PARAMS->{db_prefix}search (
  379.             postnum INT PRIMARY KEY NOT NULL,
  380.             posttopic INT,
  381.             postpage INT,
  382.             posttime INT,
  383.             text TEXT);";
  384.         db_query("DROP TABLE $PARAMS->{db_prefix}search;", $dbh, 1) if ($existing_table->{search});
  385.         db_query($sstatement, $dbh, 0);
  386.     }
  387.     if ($tables_do->{counters}) {
  388.         my $sstatement = "CREATE TABLE $PARAMS->{db_prefix}counters (
  389.             ID INT PRIMARY KEY NOT NULL,
  390.             value INT);";
  391.         db_query("DROP TABLE $PARAMS->{db_prefix}counters;", $dbh, 1) if ($existing_table->{counters});
  392.         db_query($sstatement, $dbh, 0);
  393.         db_sql_query([{ ID => 1, value => 1 }, { ID => 2, value => 1 }], "counters", "insert", undef, $dbh);
  394.     }
  395.     if ($tables_do->{locks}) {
  396.         my $sstatement = "CREATE TABLE $PARAMS->{db_prefix}locks (
  397.             filename VARCHAR(100) PRIMARY KEY NOT NULL,
  398.             processid VARCHAR(20),
  399.             timecreate INT);";
  400.         db_query("DROP TABLE $PARAMS->{db_prefix}locks;", $dbh, 1) if ($existing_table->{locks});
  401.         db_query($sstatement, $dbh, 0);
  402.     }
  403. }
  404.  
  405. ###
  406. ### database_save_settings
  407. ###
  408. ### Saves your database name, username, and password into a file.
  409. ###
  410.  
  411. sub database_save_settings {
  412.     my ($database, $username, $password, $prefix, $sockets) = trim( @_ );
  413.     $prefix =~ s/\s+/_/g;
  414.     $PARAMS->{db_prefix} = join("", $prefix, "_");
  415.     my @db = ("database=$database\n", "username=$username\n", "password=$password\n", "prefix=$prefix\n", "force_socket=$sockets\n");
  416.     writefile("$DCONF->{admin_dir}/data/db.txt", \@db, "save_db_settings");
  417. }
  418.  
  419. 1;
  420.