#!/usr/bin/perl
use CGI::Carp qw(fatalsToBrowser);
use strict;
use lib '.';
use lib 'module';
require DBI;
require fobj;
my $f=new fobj;
$f->start;
(print "Sorry, your user name and or password is non existant or not valid") unless $f->valid;
$f->template
('forum.tmpl',
threads => construct_rows(),
section_nav => construct_section_nav(),
);
$f->finish;
sub construct_rows
{
my $alt=0;
my $sql="SELECT `cid`,`name`,`descr` FROM ".$f->conf('pre')."categories";
my $pn=$f->dbh->prepare($sql);
$pn->execute;
my ($name,$desc,$cid);
$pn->bind_columns(\$cid,\$name,\$desc);
$sql="SELECT `author`,`time` FROM ".$f->conf('pre')."posts WHERE `cid`=? ORDER BY `time` DESC LIMIT 0,1";
my $qn=$f->dbh->prepare($sql);
my ($auth,$time);
$qn->execute(0);
$qn->bind_columns(\$auth,\$time);
$sql="SELECT COUNT(pid) FROM ".$f->conf('pre')."posts WHERE `cid`=?";
my $rn=$f->dbh->prepare($sql);
my ($posts);
$rn->execute(0);
$rn->bind_columns(\$posts);
my @cats;
while($pn->fetch)
{
$alt=$alt?0:1;
$qn->execute($cid);
$qn->fetch;
$rn->execute($cid);
$rn->fetch;
my $last=$auth.' - '.$f->date_diff($time);
push @cats,
(
{
name => $name,
cid => $cid,
posts => $posts,
last => $last,
alt => $alt,
desc => $desc,
}
);
}
$pn->finish;
$qn->finish;
$rn->finish;
return \@cats;
}
sub construct_section_nav
{
return "/index";
}
#------------------------------
# fobj.pm
#------------------------------
use strict; #d'uh
use CGI::Carp qw(fatalsToBrowser); #To see errors while developing,
#should probably be taken out of
#production code;
use CGI::Carp;
package fobj;
sub new
{
return bless my $x={};
}
#########################################################
# "Start": Generally called at the beginning, just after
# "new", it calls template('header.html'); and then
# calls _start_benchmark;
#########################################################
sub start
{
my $self=shift;
my %opts=@_;
my $i=0;
my $stylesheet=$self->stylesheet;
my $date=$self->date;
print "Content-type:text/html\n\n";
my $sql="UPDATE `".$self->conf('pre')."members` SET `lastvisit`=now() WHERE `name`=?";
my $pn=$self->dbh->prepare($sql);
$pn->execute($self->env('name'));
$pn->finish;
my $page=$self->cgi('get','tid') ne ''?'thread.pl':'cat.pl';
$self->template
('header.tmpl',
date => $date,
pm => $self->_check_pm,
stylesheet => $stylesheet,
);
$self->start_benchmark;
}
sub _check_pm
{
my $self=shift;
my $sql="SELECT COUNT(mid) FROM ".$self->conf('pre')."pm WHERE `target`=? AND `pmread`=0";
my $pn=$self->dbh->prepare($sql);
$pn->execute($self->env('name'));
my $x;
$pn->bind_columns(\$x);
$pn->fetch;
$pn->finish;
if($x){return "";}
else{return "";}
}
sub date
{
my $self=shift;
my $sql="SELECT `lastvisit` FROM `".$self->conf('pre')."members` WHERE `name`=?";
my $pn=$self->dbh->prepare($sql);
my ($date);
$pn->execute($self->env('name'));
$pn->bind_columns(\$date);
$pn->fetch;
$pn->finish;
return $self->date_diff($date);
}
sub stylesheet
{
my $self=shift;
my $stylesheet;
my $sql="SELECT `stylesheet`,`personalsheet` FROM `".$self->conf('pre')."members` WHERE `name`=?";
my $pn=$self->dbh->prepare($sql);
my ($style,$perstyle);
$pn->execute($self->env('name'));
$pn->bind_columns(\$style,\$perstyle);
$pn->fetch;
$pn->finish;
if($style ne '')
{
my $sql="SELECT `data` FROM `".$self->conf('pre')."styles` WHERE `id`=? limit 0,1";
my $pn=$self->dbh->prepare($sql);
$pn->execute($style);
$pn->bind_columns(\$stylesheet);
$pn->fetch;
}
elsif($perstyle ne '')
{
$stylesheet=$perstyle;
}
else
{
$stylesheet='@import url("styles/forum.css"); ';
}
return $stylesheet;
}
#########################################################
# Typically the last subroutine to be called, it calls
# _end_benchmark and passes that value to the
# template call, in the form of
# template('footer.html',time=>$time);
#########################################################
sub finish
{
my $self=shift;
my $time=$self->end_benchmark($self->{t}) if defined $self->{t};
$self->template('footer.tmpl',time=>$time);
}
#########################################################
# "start_benchmark": Creates a new Benchmark in $obj->{t}
#########################################################
sub start_benchmark
{
require Benchmark;
my $self=shift;
$self->{t}=new Benchmark;
}
#########################################################
# Basically a wrapper around Template.pm, 2 args, first
# arg is the name of the template two open, second arg is
# a hash of values to replace in the template, replaces
# with $value, also sets up
# a few other default substitutions.
#########################################################
sub template
{
my $self=shift;
require Template;
my $what=shift;
if($what!~m!/|\\!){$what=$self->conf('tmpl_dir').$what;}
my %rep=@_;
$self->_set_rep(\%rep);
my $template = HTML::Template->new
(
filename => $what,
die_on_bad_params => 0
);
$template->param(\%rep);
print $template->output;
}
sub _set_rep
{
my $self=shift;
my $rep=shift;
my $sql="SELECT `style` FROM `".$self->conf('pre')."members` WHERE ".
"`name`=?";
my $pn=$self->dbh->prepare($sql);
my $temp;
$pn->execute($self->env('name'));
$pn->bind_columns(\$temp);
$pn->fetch;
$pn->finish;
$rep->{style}='styles/'. ($temp || 'forum.css');
$rep->{name}=$self->env('name');
}
sub cgi
{
require Lite;
my $self=shift;
my $c=CGI::Lite->new;
$self->{get_cgi}=$c->parse_form_data('GET') unless (defined $self->{get_cgi});
$self->{post_cgi}=$c->parse_form_data('POST') unless (defined $self->{post_cgi});
my ($which,$what) =@_;
unless(defined $what){return $self->{$which.'_cgi'};}
elsif($which && $what){return $self->{$which.'_cgi'}->{lc $what};}
}
sub dbh
{
my $self=shift;
require DBI;
unless(defined $self->{dbh})
{
$self->{dbh}=
DBI->connect
(
"DBI:mysql:".$self->conf('db_name'),
$self->conf('db_user_name'),
$self->conf('db_user_pass'),
{RaiseError => 1}
);
}
return $self->{dbh};
}
#########################################################
# "conf": the configuration function. This function creates
# a hash out of 'db.conf', in the form of $key = $value;
# It takes one or zero parameters, if one parameter, it
# returns whatever the parameter corresponds to in the
# db.conf file, and if zero parameters, it returns the
# hash itself.
#########################################################
sub conf
{
my $self=shift;
my $what=shift;
my %temp;
if(defined $self->{conf})
{
return (defined $what)?$self->{conf}{$what}:$self->{conf};
}
else
{
open C,'){/([\w\d\_]+)\s*=\s*(.*)/;$temp{$1}=$2;}
$self->{conf}={%temp};
return (defined $what)?$self->{conf}{$what}:$self->{conf};
}
}
#########################################################
# Similar to the above function, except this function
# works on cookies instead of db.conf, and a few other
# values. Takes one or zero parameters, if one parameter
# it returns the value of the cookie where
# cookie_name eq $parameter, or if zero, it returns the
# hash of cookies itself.
#########################################################
sub env
{
my $self=shift;
my $targ=shift;
unless(defined $self->{cookie}){$self->{cookie}=$self->_cookie;}
unless(defined $self->{env}){$self->_define_env;}
return (defined $targ)?
(
defined $self->{env}{$targ}?
$self->{env}{$targ}
:
$self->{cookie}{$targ}
)
:
$self->{env};
}
sub _define_env
{
my $self=shift;
my $sql="SELECT `admin`,`avatar`,`sig`,`threadsperpage`,`postsperpage` FROM `".
$self->conf('pre')."members` WHERE `name`=? LIMIT 0,1";
my ($admin,$av);
my $pn=$self->dbh->prepare($sql);
$pn->execute($self->{cookie}{name});
$pn->bind_columns
(
\$self->{env}{admin},
\$self->{env}{avatar},
\$self->{env}{sig},
\$self->{env}{threadsperpage},
\$self->{env}{postsperpage},
);
$pn->fetch;
$pn->finish;
$self->{env}{ignored}=$self->__ignored();
}
sub __ignored
{
my $self=shift;
my $sql="SELECT `name` FROM `".$self->conf('pre')."ignored` WHERE `user`=?";
my $pn=$self->dbh->prepare($sql);
$pn->execute($self->env('name'));
$pn->bind_columns( \( my $name) );
my %i;
while($pn->fetch)
{
$i{$name}=1;
}
$pn->finish;
return \%i;
}
sub _cookie
{
require Lite;
my $lite=CGI::Lite->new;
return $lite->parse_cookies;
}
#########################################################
#"end_benchmark": takes a benchmark object, creates a
# new one, and returns a nicely formatted string
# containing the difference between the two benchmarks
#########################################################
sub end_benchmark
{
require Benchmark;
my $t2=new Benchmark;
my $self=shift;
my $t1=shift;
my $td = Benchmark::timediff($t1, $t2);
return Benchmark::timestr($td);
}
sub date_diff
{
$_=shift;
my ($self,$date);
(ref $_ eq 'fobj')?($self=$_ and $date=shift):($date=$_);
require Pcalc;
return " " unless $date;
my @date;
push @date,substr($date,0,4,'');
for my $i(0..int (length $date)/2){push @date,substr($date,0,2,'');}
pop @date;
my @diff=reverse Date::Pcalc::Delta_DHMS(@date,Date::Pcalc::Today_and_Now());
return "[$diff[0]s:$diff[1]m:$diff[2]h:$diff[3]d]";
}
sub valid
{
my $self=shift;
(print "Error, name/pass not found. Log In" and exit) unless ($self->env('name') ne '' && $self->env('pw') ne '');
my $sql="SELECT `pw` FROM `".$self->conf('pre')."members` WHERE `name`=?";
my $pn=$self->{dbh}->prepare($sql);
$pn->execute($self->env('name'));
my $pw;
$pn->bind_columns(\$pw);
$pn->fetch;
$pn->finish;
(print "Error, invalid name/pass Log In" and exit) unless ($pw eq $self->env('pw'));
return 1;
}
sub DESTROY
{
my $self=shift;
$self->{dbh}->disconnect if (defined $self->{dbh} && ref $self->{dbh} eq 'DBI::db');
}
sub AUTOLOAD
{
shift;
CGI::Carp::croak "Content-type:text/html\n\n
You attempted to call $fobj::AUTOLOAD(".join(',',@_).");
This sub doesnt exist.\n";
}
1; # is the loneliest number..