jptxs has asked for the wisdom of the Perl Monks concerning the following question:

A friend has asked me to put together a simple message board for them. np, right? I figure what I'll do is have an index page, which is made of nested links to root messages and their replies (and replies to replies etc.), and I'll keep all the actual messages in their own HTML files. No DB, it will run on almost any version of perl - simple. Then, for giggles, I looked at the source for MSA's message board. It does the exact same thing basically. Now, of course, it is lacking any signs of warnings, strict or taint checking - but the concept is the same. So many times now in the CB and throughout many nodes the work of MSA has been dismissed as absolute evil. Now, seeing it does almost exactly waht I was planning on, I find myself doubting my ideas on how to do this.

Am I nuts? Is there a much better way I'm missing? Am I way too paranoid? How would any of you do it?

"A man's maturity -- consists in having found again the seriousness on +e had as a child, at play." --Nietzsch +e

Replies are listed 'Best First'.
Re: simple message board gone very wrong?
by chromatic (Archbishop) on Dec 11, 2000 at 23:52 UTC
    I haven't looked at the source of Matt's message board myself, but I recall that on comp.lang.perl.misc about a year ago, there was an extended thread familiy dealing with security holes in it.

    Besides that, the phrases "no DB" and "their own HTML files" make me wonder about unnecessary complexity and scalability. Just about any recent version of Perl has dbfile support in various flavors, and it's easy to use. See tie, dbmopen and dbmclose.

    You might take a look at Matt's message board for a general idea of structure, but I suspect that you'll have a better time writing your own from scratch than trying to fix design flaws and security holes and manage threading with his version.

    Or you could search on Freshmeat for any of a dozen variants on the theme.

      $out_of_context_rambling = qq|

      Without wishing to unneccecarily trash anyone, Matt's stuff is rediculously popular, considering the quality of his products. I run servers containing many thousands of websites, and over the years I have been constantly amazed at the problems caused by his code. Thinking about it now, I wonder why I didn't submit a whole bunch of patches to him in the first place - maybe that would have helped things.

      This seems to echo somthing that's true accross all western society -- the masses just accept whatever is rammed down their throat. Matt put a lot of effort into FAQs, nice packaging, a pretty website, and decent search engine submission. And he did all this at a time when there was little else available. I hope he's now worth a lot of money and drives a nice car.

      Websites were still very much the domain of HTML monkeys who needed that extra little active add-on. They can't read the code, so they have no way to judge the quality of it. Why do people eat McDonalds or buy lousy stereos?

      So, the question for me is this: How do we encourage the popularity of high quality software in a market where the buyer is simply not empowered to make the "right" descision? They are certainly not reading perlmonks...

      |;

        If you can't make a street musician move from in front of your shop it sometimes makes sense to tune his guitar. ;-)

        Claude

      Well, I wanted to avoid any sort of DB b/c this needs to run on a hosted box for somone and they requested it be as self contained as possible. Also, they requested the ability to be able to zip up the whole thing and move it whenever they wanted. I figure if it's just one .cgi and a bunch of .html files it couldn't be all that hard, right?

      Doing the Freshmeat thing as we speak. I was planning on just writing it all from scratch for the fun of it, but after sketching out the idea I thought it was so easy that I decided to see what MSA did so horribly wrong - that had come up in here before. I just got spooked when I saw how similar what he was doing was to what I had thought up myself...

      "A man's maturity -- consists in having found again the seriousness on +e had as a child, at play." --Nietzsch +e
        I think he suggested using DBM files, which are supported (to my knowledge) across most any Unix system. It does not utilize a true database, merely a set of lower-level calls that interact with standard file formats. This would let you use database type functionality in a portable way that won't involve you installing a bunch of extra cruft.
Re: simple message board gone very wrong?
by cei (Monk) on Dec 12, 2000 at 03:05 UTC
    I looked at MSA's board and there were a handful of things I didn't like about it. I'm no perl saint, but here's what I came up with as a quick & dirty:
    #!/usr/bin/perl -w use CGI; use strict; my ($CGID, $i, $date); my $P = CGI::new(); $P->import_names('NM'); if ($0=~m#^(.*)\\#){ $CGID = "$1"; } elsif ($0=~m#^(.*)/# ){ $CGID = "$1"; } else {`pwd` =~ /(.*)/; $CGID = "$1"; } my $gb = "$CGID/../www/html/fan/fan_main.html"; open (FH, "$gb") || die "Can't Open $gb: $!\n"; my @LINES=<FH>; close(FH); my $SIZE=@LINES; my $minutes = (localtime)[1]; ($minutes = "0".$minutes) if ($minutes < 10); $date = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday')[(localtime)[6]] . ', ' . ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')[(localtime)[4]] . " " . (localtime)[3] . ", " . ((localtime)[5] + 1900) . " at " . (localtime)[2] . ":" . (localtime)[1]; open (FH,">$gb") || die "Can't Open $gb: $!\n"; for ($i=0;$i<=$SIZE;$i++) { $_=$LINES[$i]; if (/<!--begin-->/) { print FH "<!--begin-->\n"; $NM::message =~ s/(\S{20})/$1 /g; $NM::message =~ s/</&lt;/g; $NM::message =~ s/>/&gt;/g; $NM::message =~ s/\cM\n/<br>\n/g; print FH "<b>$NM::message</b><!-- $ENV{'REMOTE_HOST'} --><br>\n"; if ( $NM::email ){ print FH " \&lt;<a href = 'mailto:$NM::email'>$NM::name</a>\&gt;"; } else { print FH " \&lt;$NM::name\&gt;"; } print FH "<br>\n - $date<p><hr>\n\n"; } else { print FH $_; }} close (FH); open(FH, $gb) or die "Can't open $gb: $!"; local($/) = undef; my $template = <FH>; close(FH); print "Content-type: text/html\n\n$template"; exit (0);
    I'd like to add flock to that, but I haven't quite gotten it working for some reason... Any suggestions welcome.
      Nice ++, but you should know that even WITH flock(), you're not absolutely safe. In any interpreted language, ALL function calls not matter how harmless-looking, are interruptable. And "interruptable" means potential race condition when your functions access the same variable (in this case, a file). While with the simple flock() call, your chances are better that you will not end in a race condition (and basically, for messages less than _POSIX_PIPE_BUF in <limits.h> there is almost zero chance of it). But the possibility still exists, so in the interests of full security and functionality, the filesystem should not be depended on as a backbone to a multiuser interfaces. Sadly, that's not an option here and it looks like the %dbhash via Perl's DBM APIs are the best bet (hint, hint, jptxs).
      AgentM Systems nor Nasca Enterprises nor Bone::Easy nor Macperl is responsible for the comments made by AgentM. Remember, you can build any logical system with NOR.

      At the top:

      use Fcntl qw(:flock);

      Immediately after the 'read open':

      flock(FH, LOCK_SH);

      Change the 'write open' to:

      open(FH, "<+ $gb") or die "Could not open $gb: $!\n"; flock(FH, LOCK_EX); seek(FH,0,0); truncate(FH,0) or die "Could not truncate $gb: $!\n";

      Once you use flock, make sure that every process that accesess the files also uses flock.

      Also, the "local $/" should be in it's own block, otherwise anything else you add to the bottom of this script will be in "ultraslurp mode"