0

what i am trying to do is get the contents of a file from another server. Since im not in tune with perl, nor know its mods and functions iv'e gone about it this way:

 my $fileContents;
 if( $md5Con =~ m/\.php$/g ) {
     my $ftp = Net::FTP->new($DB_ftpserver, Debug => 0) or die "Cannot connect to some.host.name: $@";
     $ftp->login($DB_ftpuser, $DB_ftppass) or die "Cannot login ", $ftp->message;
     $ftp->get("/" . $root . $webpage, "c:/perlscripts/" . md5_hex($md5Con) . "-code.php") or die $ftp->message;
     open FILE, ">>c:/perlscripts/" . md5_hex($md5Con) . "-code.php" or die $!;
     $fileContents = <FILE>;
     close(FILE);
     unlink("c:/perlscripts/" . md5_hex($md5Con) . "-code.php");
     $ftp->quit;
 }

What i thought id do is get the file from the server, put on my local machine, edit the content, upload to where ever an then delete the temp file.

But I cannot seem to figure out how to get the contents of the file;

open FILE, ">>c:/perlscripts/" . md5_hex($md5Con) . "-code.php" or die $!;
$fileContents = <FILE>;
close(FILE);

keep getting error;

Use of uninitialized value $fileContents

Which im guessing means it isn't returning a value.

Any help much appreciated.

>>>>>>>>>> EDIT <<<<<<<<<<

my $fileContents;
if( $md5Con =~ m/\.php$/g ) {
    my $ftp = Net::FTP->new($DB_ftpserver, Debug => 0) or die "Cannot connect to some.host.name: $@";
    $ftp->login($DB_ftpuser, $DB_ftppass) or die "Cannot login ", $ftp->message;
    $ftp->get("/" . $root . $webpage, "c:/perlscripts/" . md5_hex($md5Con) . "-code.php") or die $ftp->message;
    my $file = "c:/perlscripts/" . md5_hex($md5Con) . "-code.php";
    {
        local( $/ ); # undefine the record seperator
        open FILE, "<", $file or die "Cannot open:$!\n";
        my $fileContents = <FILE>;
        #print $fileContents;
        my $bodyContents;
        my $headContents;

        if( $fileContents =~ m/<\s*body[^>]*>.*$/gi ) {
            print $0 . $1 . "\n";
            $bodyContents = $dbh->quote($1);    
        }
        if( $fileContents =~ m/^.*<\/head>/gi ) {
            print $0 . $1 . "\n";
            $headContents = $dbh->quote($1);    
        }

        $bodyTable = $dbh->quote($bodyTable);
        $headerTable = $dbh->quote($headerTable);
        $dbh->do($createBodyTable) or die " error: Couldn't create body table: " . DBI->errstr;
        $dbh->do($createHeadTable) or die " error: Couldn't create header table: " . DBI->errstr;
        $dbh->do("INSERT INTO $headerTable ( headData, headDataOutput ) VALUES ( $headContents, $headContents )") or die " error: Couldn't connect to database: " . DBI->errstr;
        $dbh->do("INSERT INTO $bodyTable ( bodyData, bodyDataOutput ) VALUES ( $bodyContents, $bodyContents )") or die " error: Couldn't connect to database: " . DBI->errstr;
        $dbh->do("INSERT INTO page_names (linkFromRoot, linkTrue, page_name, table_name, navigation, location) VALUES ( $linkFromRoot, $linkTrue, $page_name, $table_name, $navigation, $location )") or die " error: Couldn't connect to database: " . DBI->errstr;

        unlink("c:/perlscripts/" . md5_hex($md5Con) . "-code.php");
    }
    $ftp->quit;
}

the above using print WILL print the whole file. BUT, for some reason the two regular expresions are returning false. Any idea why?

if( $fileContents =~ m/<\s*body[^>]*>.*$/gi ) {
            print $0 . $1 . "\n";
            $bodyContents = $dbh->quote($1);    
        }
        if( $fileContents =~ m/^.*<\/head>/gi ) {
            print $0 . $1 . "\n";
            $headContents = $dbh->quote($1);    
        }
Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
Phil Jackson
  • 10,238
  • 23
  • 96
  • 130

7 Answers7

10

This is covered in section 5 of the Perl FAQ included with the standard distribution.

How can I read in an entire file all at once?

You can use the Path::Class::File::slurp module to do it in one step.

use Path::Class;
$all_of_it = file($filename)->slurp; # entire file in scalar
@all_lines = file($filename)->slurp; # one line per element

The customary Perl approach for processing all the lines in a file is to do so one line at a time:

open (INPUT, $file) || die "can't open $file: $!";
while (<INPUT>) {
    chomp;
    # do something with $_
}
close(INPUT)        || die "can't close $file: $!";

This is tremendously more efficient than reading the entire file into memory as an array of lines and then processing it one element at a time, which is often—if not almost always—the wrong approach. Whenever you see someone do this:

@lines = <INPUT>;

you should think long and hard about why you need everything loaded at once. It's just not a scalable solution. You might also find it more fun to use the standard Tie::File module, or the DB_File module's $DB_RECNO bindings, which allow you to tie an array to a file so that accessing an element the array actually accesses the corresponding line in the file.

You can read the entire filehandle contents into a scalar.

{
local(*INPUT, $/);
open (INPUT, $file) || die "can't open $file: $!";
$var = <INPUT>;
}

That temporarily undefs your record separator, and will automatically close the file at block exit. If the file is already open, just use this:

$var = do { local $/; <INPUT> };

For ordinary files you can also use the read function.

read( INPUT, $var, -s INPUT );

The third argument tests the byte size of the data on the INPUT filehandle and reads that many bytes into the buffer $var.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
8

Use Path::Class::File::slurp if you want to read all file contents in one go.

However, more importantly, use an HTML parser to parse HTML.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
3
open FILE, "c:/perlscripts" . md5_hex($md5Con) . "-code.php" or die $!;
while (<FILE>) {
    # each line is in $_
}
close(FILE);

will open the file and allow you to process it line-by-line (if that's what you want - otherwise investigate binmode). I think the problem is in your prepending the filename to open with >>. See this tutorial for more info.

I note you're also using regular expressions to parse HTML. Generally I would recommend using a parser to do this (e.g. see HTML::Parser). Regular expressions aren't suited to HTML due to HTML's lack of regularity, and won't work reliably in general cases.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • im not wanting line by line just whole content.. will have a play – Phil Jackson Feb 06 '10 at 14:58
  • Your record separator may not match the file contents – Brian Agnew Feb 06 '10 at 16:02
  • have to use regular expression as im not just after HTML. PHP, HTML, JAVASCRIPT, JQUERY AND ASP. I try to split into head and body to analyse and then try to extract the serverside code, add placeholder and then see what content is able to be edited. – Phil Jackson Feb 06 '10 at 17:53
2

Also, if you are in need of editing the contents of the files take a look at the CPAN module Tie::File
This module relieves you from the need to creation of a temp file for editing the content and writing it back to the same file.

EDIT:
What you are looking at is a way to slurp the file. May be you have to undefine the record separator variable $/

The below code works fine for me:

use strict;
my $file = "test.txt";
{
    local( $/ ); # undefine the record seperator
    open FILE, "<", $file or die "Cannot open:$!\n";
    my $lines =<FILE>;
    print $lines;
}

Also see the section "Traditional Slurping" in this article.

sateesh
  • 27,947
  • 7
  • 36
  • 45
1

BUT, for some reason the two regular expresions are returning false. Any idea why?

. in a regular expression by default matches any character except newline. Presumably you have newlines before the </head> tag and after the <body> tag. To make . match any character including newlines, use the //s flag.

I'm not sure what your print $0 . $1 ... code is about; you aren't capturing anything in your matches to be stored in $1, and $0 isn't a variable used for regular expression captures, it's something very different.

ysth
  • 96,171
  • 6
  • 121
  • 214
0

if you want to get the content of the file,

 @lines = <FILE>;
Dyno Fu
  • 8,753
  • 4
  • 39
  • 64
  • Usually given as TMTOWTDI ("There's", not "There is"). But TMTOWTDI. – ysth Feb 07 '10 at 09:43
  • 2
    I would suspect people are voting down because the goal in this particular case is to have the whole file in one scalar, not separate lines in an array. – ysth Feb 07 '10 at 09:44
  • i just want to provide an alternative to solve the problem. (personally, if the answer is not totally irrelevant, or emotional, should not vote down. anyway people are free to vote what they think is wrong). – Dyno Fu Feb 07 '10 at 14:00
0

Use File::Slurp::Tiny. As convenient as File::Slurp, but without the bugs.

jjmerelo
  • 22,578
  • 8
  • 40
  • 86