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

Hi there, I have written this code. It all works and allows me to Add,insert,change,delete and re-edit records in a file. I want to create a small database for my personal site. Mostly to store stories,artwork etc. Does this look ok? Are there any problems here regarding people adding at the same time? or loosing the data whilst manipulating it via an array? Could do with some wise opinions. To run the script, copy it. Give it a name, change the 3 lines of code and create a datafile.
#!/usr/bin/perl #SPLIT INCOMING DATA ################################################################### read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); $buffer=$ENV{QUERY_STRING} if ($ENV{QUERY_STRING}=~/=/); @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; if ($F{$name}) { $F{$name} = $F{$name}.",".$value; } else { $F{$name} = $value; } } #VARIABLES TO CHANGE ############################ $scriptfile = 'test.cgi'; #Name of this script $datafile = 'testdata.dat'; #Name of the file to sto +re data to $workdir = 'http://myworld.server101.com'; #Default Working Dir #OTHER VARIABLES ############################ $action = $F{'action'}; $userid = $F{'userid'}; $name1 = $F{'name1'}; $name2 = $F{'name2'}; $line = $F{'line'}; #DECIDE ACTION TO TAKE ############################ if ($action eq '') { &Show;} if ($action eq 'show') { &Show;} if ($action eq 'add') { &Add;} if ($action eq 'addsave') { &Addsave;} if ($action eq 'change') { &Change;} if ($action eq 'changesave'){ &Changesave;} if ($action eq 'insert') { &Insert;} if ($action eq 'insertsave'){ &Insertsave;} if ($action eq 'delete') { &Delete;} #ADD - Create Form ############################ sub Add { &Header; print qq| <form action=$scriptfile> <input type=hidden name=action value=addsave> ForeName:<input type=text name=name1 size=20><br> Surname :<input type=text name=name2 size=20><br> <input type=submit value="Add Record"> </form> |; exit; } #ADD - Save data to File ############################ sub Addsave { $newname = join('¬', $name1, $name2); $newname .= "\n"; open ("database", ">>$datafile") || &Printerror; print database $newname; close(database); print "Location: $workdir/cgi/$scriptfile?action=show\n\n"; exit; } #CHANGE - Create Form ############################ sub Change { &Header; open ("database", "$datafile") || &Printerror; @database = <database>; close(database); ($name1, $name2) = split ('[¬]',@database[$line]); $name2 =~ s/\n//g; print qq| <form action=$scriptfile> <input type=hidden name=action value=changesave> <input type=hidden name=line value=$line> Forename:<input type=text name=name1 size=20 value=$name1><br> Surname :<input type=text name=name2 size=20 value=$name2><br> <input type=submit value="Change Record"> </form> |; exit; } #CHANGE - Save changed data to File ################################### sub Changesave { $newname = join('¬', $name1, $name2); $newname .= "\n"; open ("oldbase", "$datafile") || &Printerror; @oldbase = <oldbase>; close(oldbase); @oldbase[$line] = $newname; open ("newbase", ">$datafile") || &Printerror; print newbase @oldbase; close(newbase); print "Location: $workdir/cgi/$scriptfile?action=show\n\n"; exit; } #INSERT - Create Form ############################ sub Insert { &Header; print qq| <form action=$scriptfile> <input type=hidden name=action value=insertsave> <input type=hidden name=line value=$line> Forename:<input type=text name=name1 size=20><br> Surname :<input type=text name=name2 size=20><br> <input type=submit value="Insert Record"> </form> |; exit; } #INSERT - Save inserted data to File ##################################### sub Insertsave { $newname = join('¬', $name1, $name2); $newname .= "\n"; open ("oldbase", "$datafile") || &Printerror; @oldbase = <oldbase>; close(oldbase); $oldname = @oldbase[$line]; @oldbase[$line] = "$newname$oldname"; open ("newbase", ">$datafile") || &Printerror; print newbase @oldbase; close(newbase); print "Location: $workdir/cgi/$scriptfile?action=show\n\n"; exit; } #DELETE - delete record ################################### sub Delete { open ("oldbase", "$datafile") || &Printerror; @oldbase = <oldbase>; close(oldbase); @oldbase[$line] = ''; open ("newbase", ">$datafile") || &Printerror; print newbase @oldbase; close(newbase); print "Location: $workdir/cgi/$scriptfile?action=show\n\n"; exit; } #SHOW - Create List of Records ############################## sub Show { $line = "-1"; &Header; open ("database","$datafile")|| &Printerror; @database = <database>; close(database); foreach (@database) { $line += 1; ($name1, $name2) = split ('[¬]',$_); print qq| $line $name1 $name2 \| <a href=$scriptfile?action=change&line=$line>Edit</a> \| <a href=$scriptfile?action=delete&line=$line>Delete</a> \| <a href=$scriptfile?action=insert&line=$line>Insert</a><br>|; } print qq| <br> <a href=$scriptfile?action=add>Add Record</a> |; exit; } #HEADER ##################################### sub Header { print "Content-type: text/html\n\n"; }
ThAtH0M

Replies are listed 'Best First'.
Re: Add,Insert,Change,Delete File / Array
by BigJoe (Curate) on Oct 04, 2001 at 17:39 UTC
    Hey, you are going to want to check out a fun place we like to call CPAN. There you will find cool modules like CGI.pm and DBI which will help you on your website quests.

    With DBI and it's drivers you can connect to almost any Database (Even CSV files!). Go to http://search.cpan.org and search for "DBI" and it will give you all sorts of tidbits of things you can do. While you are there you may wish to look at CGI.pm. This does all you IO better.

    --BigJoe

    Learn patience, you must.
    Young PerlMonk, craves Not these things.
    Use the source Luke.

    UPDATE ALWAYS have: use strict;

      No need to go to CPAN for CGI.pm. It's been a part of the standard Perl distribution for many years.

      --
      <http://www.dave.org.uk>

      "The first rule of Perl club is you don't talk about Perl club."

        Thathom can at least look at the POD and then it makes him aware of where to find information about more modules that are there for using.

        --BigJoe

        Learn patience, you must.
        Young PerlMonk, craves Not these things.
        Use the source Luke.
      This is a quick and untested example of how to use CGI in your script. There is alot more that it can do for you also.
      #!/usr/bin/perl use strict; use CGI; my $q = new CGI; #VARIABLES TO CHANGE ############################ $scriptfile = 'test.cgi'; #Name of this script $datafile = 'testdata.dat'; #Name of the file to sto +re data to $workdir = 'http://myworld.server101.com'; #Default Working Dir #OTHER VARIABLES ############################ $action = $q->param('action'); $userid = $q->param('userid'); $name1 = $q->param('name1'); $name2 = $q->param('name2'); $line = $q->param('line'); #DECIDE ACTION TO TAKE ############################ if ($action eq '') { &Show;} if ($action eq 'show') { &Show;} if ($action eq 'add') { &Add;} if ($action eq 'addsave') { &Addsave;} if ($action eq 'change') { &Change;} if ($action eq 'changesave'){ &Changesave;} if ($action eq 'insert') { &Insert;} if ($action eq 'insertsave'){ &Insertsave;} if ($action eq 'delete') { &Delete;} #ADD - Create Form ############################ sub Add { print $q->header; print qq| <form action=$scriptfile> <input type=hidden name=action value=addsave> ForeName:<input type=text name=name1 size=20><br> Surname :<input type=text name=name2 size=20><br> <input type=submit value="Add Record"> </form> |; exit; } #ADD - Save data to File ############################ sub Addsave { $newname = join('¬', $name1, $name2); $newname .= "\n"; open ("database", ">>$datafile") || &Printerror; print database $newname; close(database); print "Location: $workdir/cgi/$scriptfile?action=show\n\n"; exit; } #CHANGE - Create Form ############################ sub Change { print $q->header; open ("database", "$datafile") || &Printerror; @database = <database>; close(database); ($name1, $name2) = split ('[¬]',@database[$line]); $name2 =~ s/\n//g; print qq| <form action=$scriptfile> <input type=hidden name=action value=changesave> <input type=hidden name=line value=$line> Forename:<input type=text name=name1 size=20 value=$name1><br> Surname :<input type=text name=name2 size=20 value=$name2><br> <input type=submit value="Change Record"> </form> |; exit; } #CHANGE - Save changed data to File ################################### sub Changesave { $newname = join('¬', $name1, $name2); $newname .= "\n"; open ("oldbase", "$datafile") || &Printerror; @oldbase = <oldbase>; close(oldbase); @oldbase[$line] = $newname; open ("newbase", ">$datafile") || &Printerror; print newbase @oldbase; close(newbase); print "Location: $workdir/cgi/$scriptfile?action=show\n\n"; exit; } #INSERT - Create Form ############################ sub Insert { print $q->header; print qq| <form action=$scriptfile> <input type=hidden name=action value=insertsave> <input type=hidden name=line value=$line> Forename:<input type=text name=name1 size=20><br> Surname :<input type=text name=name2 size=20><br> <input type=submit value="Insert Record"> </form> |; exit; } #INSERT - Save inserted data to File ##################################### sub Insertsave { $newname = join('¬', $name1, $name2); $newname .= "\n"; open ("oldbase", "$datafile") || &Printerror; @oldbase = <oldbase>; close(oldbase); $oldname = @oldbase[$line]; @oldbase[$line] = "$newname$oldname"; open ("newbase", ">$datafile") || &Printerror; print newbase @oldbase; close(newbase); print "Location: $workdir/cgi/$scriptfile?action=show\n\n"; exit; } #DELETE - delete record ################################### sub Delete { open ("oldbase", "$datafile") || &Printerror; @oldbase = <oldbase>; close(oldbase); @oldbase[$line] = ''; open ("newbase", ">$datafile") || &Printerror; print newbase @oldbase; close(newbase); print "Location: $workdir/cgi/$scriptfile?action=show\n\n"; exit; } #SHOW - Create List of Records ############################## sub Show { $line = "-1"; print $q->header; open ("database","$datafile")|| &Printerror; @database = <database>; close(database); foreach (@database) { $line += 1; ($name1, $name2) = split ('[¬]',$_); print qq| $line $name1 $name2 \| <a href=$scriptfile?action=change&line=$line>Edit</a> \| <a href=$scriptfile?action=delete&line=$line>Delete</a> \| <a href=$scriptfile?action=insert&line=$line>Insert</a><br>|; } print qq| <br> <a href=$scriptfile?action=add>Add Record</a> |; exit;


      --BigJoe

      Learn patience, you must.
      Young PerlMonk, craves Not these things.
      Use the source Luke.
Re: Add,Insert,Change,Delete File / Array
by davorg (Chancellor) on Oct 04, 2001 at 17:43 UTC

    You need to use -w, strict and CGI.pm. All of these will make your scripts more robust.

    Update: ajt is, of course, right. I don't know why I didn't add -T to my original list. Any CGI script that is not run in taint mode is just asking for trouble.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you don't talk about Perl club."

      I can't agree with my learned colleagues more, you should use strict; use CGI; and set the -w flag.

      Another thing to do however, is to switch taint checks on and scrub your data clean (detaint). Your CGI-BIN is a gaping hole in your server's defences against the world, and if you put something in there, especially something that writes to the disk system, you sould make sure that you know what it's writing and where. You can't trust the users not to add something nasty inside a form.

      Please read perlsec, to see why -T is a good idea. At best a inocent mistake could mess up your array, at worst they could format your hard disk....

Re: Add,Insert,Change,Delete File / Array
by MZSanford (Curate) on Oct 04, 2001 at 17:42 UTC
    One of your questions was about multiple people reading/writing at the same time. Unless you use some sort of file locking mechanisim (like flock), multiple instances can be started by the webserver and corrupt the data file. So, i suggest that before any reading/writing, you use flock to secure the file.
    Other than that, you are going to hear alot of use CGI comments, with which i must say i agree.
    "They shall not overcome. Whoever told them that the truth shall set them free was obviously and grossly unfamiliar with federal law."
        -- John Ashcroft
Re: Add,Insert,Change,Delete File / Array
by stefan k (Curate) on Oct 04, 2001 at 17:43 UTC
    Hi,
    is there any deeper reason why you don't
    use CGI;
    ?? That is something which immediately comes to my mind.

    Well, actually I couldn't think of it before I re-entered my mind after passing out, because you don't

    use strict;
    and have no warnings enabled (perl -w).
    :-)

    Regards... Stefan
    you begin bashing the string with a +42 regexp of confusion

Re: Add,Insert,Change,Delete File / Array
by Fletch (Bishop) on Oct 04, 2001 at 18:42 UTC

    Well, aside from using CGI three things: you should move the call to exit out of all the different subs and place it after your dispatch code (repeated code is bad); you're not locking the database file (perldoc -f flock); and your dispatch code might be a little cleaner this way:

    my %actions = ( Add => \&Add, Delete => \&Delete, Show => \&Show, ... ); if( length( $action ) ) { $actions{ $action }->( ); } else { Show(); } exit 0;

    That way you just have to maintain the dispatch table in the %actions hash rather than having n different if statements (repeated code bad, again :).