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

Hi everyone,

Few days back a message was posted about modifying a line in an ASCII file. Well I’m trying to do the same, but I’m getting my parameters through a get method from a web browser which calls myscript.pl, one of the subroutines in the script deals with changing the held quantity based on what the user typed:

#!/usr/bin/perl -wT use CGI qw(:standard); $ItemForm = param('item'); $AmountForm = param('amount'); $OldLine = `grep $ItemForm stock.dat`; ($item, $OldHeld, $order)=split(/” “/, $OldLine); $NewHeld = $OldHeld-$AmountForm; $NewLine= join (" ",$item, $NewHeld, $order); open(STOCK,"items.dat"); @items=<STOCK>; close STOCK; for ($i=0; $i < $#items; $i++) { $items[ $i ] = $NewLine if ($items[ $i ] eq $OldLine); } open (STOCK,">items.dat"); foreach (@items) { print STOCK; } close(STOCK);


It's working fine but my question: is there any better way doing it? I believe it’s not practical to read the file in an array and then rewrite it back.
The other point is I don’t have the Tie::File module and chances are very low that I would be allowed to install it on the server.

Cheers,
Tom

Replies are listed 'Best First'.
Re: Read/Write ASCII file
by Corion (Patriarch) on Jun 07, 2003 at 12:08 UTC

    There is not much way beyond reading the complete file, making the changes and writing the file again, as the length of your lines will vary depending on the number of items actually ordered (each digit takes up one byte).

    "installing" a Perl module simply means copying it onto the server in the right location or appending the file to your program. If you decide to keep Tie::File in a separate file from your program (much recommended), find a directory on your server under your control that is not readable from the web, note the path (let's assume it's /home/export/tom/)and make a subdirectory lib and then lib/Tie there. Put File.pm in the directory lib/Tie, and add to the top of your program :

    use lib '/home/export/tom/lib'; use Tie::File;
    That's it.
    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
(jeffa) Re: Read/Write ASCII file
by jeffa (Bishop) on Jun 07, 2003 at 18:23 UTC
    "... chances are very low that I would be allowed to install [Tie::File] on the server."

    As Corion mentioned, you don't need permission. Detailed instructions for installing modules without being root are right here. :)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Security problem in your code ...
by skx (Parson) on Jun 07, 2003 at 22:28 UTC

     A better way would be avoid the external grep command - unless you want people to be able to delete all your files!

     Your code looks like this:

    $ItemForm = param('item'); $OldLine = `grep $ItemForm stock.dat`;

     Because you're not validating the input at all, (I'm suprised that the -T flag doesnt catch this), a malicious user could pass something like:

    /cgi-bin/script.cgi?item=t%20/etc/passwd;%20rm%20-rf%20~;echo

     This would make your command:

    `grep t /etc/passwd; rm -rf ~; cat stock.dat`

     You see the problem? ;)

    Steve
    ---
    steve.org.uk
      Steve,

      This Sub is called after an extensive validation(the $item should exist in the stock, the amount should be in certain range...etc,) I just didn't post all the script for the sake of simplicity.

      Cheers,

         That's good to know - I almost assued you'd do it, but I thought it was worth replying anyway for the benefit of people who might not be so careful.

        Steve
        ---
        steve.org.uk