I am trying to send an input to ftp opened handle in Perl. My script is
open (CALC, "|ftp abc.cde.com");
print "hello";
close CALC;
The website will only accept anonymous users as input. I have tried using $guess = <STDIN>; but it wont work.
How can i force Perl to ask for user as well as hard coding a user?
You would probably save alot of code and frustration using this module. Net::FTP is a class implementing a simple FTP client in Perl as described in RFC959. It provides wrappers for a subset of the RFC959 commands.
use Net::FTP;
$ftp = Net::FTP->new("some.host.name", Debug => 0)
or die "Cannot connect to some.host.name: $#";
$ftp->login("$user","$Password")
or die "Cannot login ", $ftp->message;
$ftp->cwd("/pub")
or die "Cannot change working directory ", $ftp->message;
$ftp->get("that.file")
or die "get failed ", $ftp->message;
$ftp->quit;
As for the user prompt, if you can use STDIN the following should work.
print "Enter username or press enter for anonymous: ";
my $user = <STDIN>;
chomp $user;
if (length($user //= '')) {$user="anonymous";$password="INSERTPASSWORD"}
else {
print "Enter password for $user: ";
my $password = <STDIN>;
chomp $password;
}
I would request the user and password as early as possible in your script, and then you can pass it to the $ftp object. Using the module is better then using exec or pipes as it will have built in error reporting and is going to be easy to OO.
Hope this helps and comment if you need more help.
Related
I'm writing a script to schedule port checks on some of my servers, and report the state. I am planning to go along with one of two options:
Pipe the output of netcat (nc) into a perl variable, and check the return state
my $rcode=`nc -z 6.6.6.6 80; echo $?`
Use the perl module IO::Socket::PortState to do the same thing.
use IO::Socket::PortState qw(check_ports);
my %porthash = ( ... );
check_ports($host,$timeout,\%porthash);
print "$proto $_ is not open ($porthash{$proto}->{$_}->{name})
if !$porthash{$proto}->{$_}->{open};
I'd like to go along the more efficient (shorter time, more specific) route.
Is there a rule of thumb regarding this? As in piping the output of a system command/unix utility is more/less efficient than using a perl module? Or are different perl modules different, and one can check the same only by setting up multiple iterations of these checks and compare the time taken by this versus a system call to execute a unix utility?
This isn't really an answer to your question so much as a suggested implementation.
Just a quick run at an untested example of using Socket.pm.
This is probably the fastest perl implementation. But at the point you are using socket.pm you may as well just write it in C with socket.h. They are a near 1:1 mapping.
Ref:
#!/usr/bin/perl -w
use Socket;
$remote = $ARGV[0];
$port = $ARGV[1];
print ":: Attempting to connect to - $remote.\n";
$iaddr = inet_aton($remote) or die "Error: $!";
$paddr = sockaddr_in($port, $iaddr) or die "Error: $!";
$proto = getprotobyname('tcp') or die "Error: $!";
socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "Error: $!";
connect(SOCK, $paddr) or die "Error: $!";
print ":: Connected Successfully!\n";
I'm trying to write some unit tests for a perl file uploading script. I'm still pretty new to perl so I'm having some issues achieving the outcome I expect from my code.
Basically my thought process is that I can pass a test_only attribute along with the request that will tell the script to just grab a file already on the system rather than try to use an uploaded file.
I created a test file and put it in my output/tmp directory. I made sure to set its permissions to 775. Its just a simple .txt file that says "I am a test file".
What I expect to happen currently is that when I run my test script I should see the contents of the file printed out to the error log as well as some reference to the buffer(so I can verify the file is being opened properly). However, this is not happening, nothing is being put in the error log. I'm wondering if the file is being opened properly?
I'm sure I'm just missing something fundamental about how perl opens files. Any help will be appreciated. Thanks :)
This is the appropriate snippet of my code:
my $test_only = 1;
my $tmp_uploads_path = "/home/my_instance/output/tmp/";
if($test_only)
{
#put simulated file handle and file name here
$file = "";
$file_name = "test_file.txt";
}
else
{
$file = $q->upload('file')
|| die "No file data sent\n $!";
$file_name = $q->param('file_name')
|| die "No file_name sent\n $!";
}
########
#SAVE THE UPLOAD
########
my $bufsize = 1024;
my $buffer = '';
open(my $TMPFILE, ">".$tmp_uploads_path.$file_name);
binmode $TMPFILE;
print STDERR "=> ".Dumper($TMPFILE)."\n";
while(read ($TMPFILE, $buffer, $bufsize)){
print STDERR "=> ".Dumper($TMPFILE)."\n";
print STDERR "=> ".Dumper($buffer)."\n";
print $TMPFILE $buffer;
}
close($TMPFILE);
You opened the $TMPFILE for writing, due to the > mode. Therefore, you cannot read from it.
You should always put use strict; use warnings; at the top of your scripts, this would have alerted you to this problem!
You should open files like
my $name = ...;
open my $fh, "<", $name or die "Can't open $name: $!";
or
use autodie;
open my $fh, "<", $name;
That is, do proper error handling, and use the three-arg variant of open: handle, mode and name (don't concat mode and name, except on ancient perls).
I am also suprised that you are using read. You can get a similar effect by
local $/ = \$bufsize;
while (defined(my $buffer = <$TMPFILE>)) { ... }
How to pass the variable user_name to the exe file file.exe as a parameter? Also, tell me if I would actually get the username from the accounting start packet with the getusername command.
#!/usr/bin/perl
use warnings;
use strict;
my $user_name;
print "Hello radiator is executing the exe file...\n";
my $user_name = $p->getUserName;
open my $EX1_PIPE, '|-', 'file.exe'
or die $!;
print $EX1_PIPE "$_\n" # i dont know what this line is for
for qw/username password/; # i dont know what this line is for
close $EX1_PIPE or die $!;
open is running the command, so you just need to invoke the command
with the desired argument:
open my $EX1_PIPE, '|-', "file.exe $user_name" or die "file.exe $!\n";
On the other hand, given your comment, it seems you want to pass the username
as input to the script. If that is the case, perhaps you are looking for:
print $EX1_PIPE "$_\n" for ($user_name $password);
(You will need to define a variable named $password)
I cannot get the script below to write to the file, data.txt, using a FILEHANDLE. Both the files are in the same folder, so that's not the issue. Since I started with Perl, I have noticed to run scripts, I have to use a full path: c:\programs\scriptname.pl and also the same method to input files. I thought that could be the issue and tried this syntax below but that didn't work either...
open(WRITE, ">c:\programs\data.txt") || die "Unable to open file data.txt: $!";
Here is my script. I have checked the syntax until it makes me crazy and cannot see an issue. Any help would be greatly appreciated!. I'm also puzzled, why the die function hasn't kicked in.
#!c:\strawberry\perl\bin\perl.exe
#strict
#diagnostics
#warnings
#obtain info in variables to be written to data.txt
print("What is your name?");
$name = <STDIN>;
print("How old are you?");
$age = <STDIN>;
print("What is your email address?");
$email = <STDIN>;
#data.txt is in the same file as this file.
open(WRITE, ">data.txt") || die "Unable to open file data.txt: $!";
#print information to data.txt
print WRITE "Hi, $name, you are \s $age and your email is \s $email";
#close the connection
close(WRITE);
How I solved this problem solved.
I have Strawberry Perl perl.exe installed on the c: drive, installed through and using the installer with a folder also on c with my scripts in, which meant I couldn't red/write to a file (directional or using functions, ie the open one) and I always had to use full paths to launch a script. I solved this problem after a suggestion of leaving the interpreter installed where it was and moving my scripts file to the desktop (leave the OS command in the first line of the script where it is as the interpreter is still in the same place it was initially). Now I can run the scripts with one click and read/write and append to file with CMD prompt and using Perl functions with ease.
Backslashes have a special meaning in double-quoted strings. Try escaping the backslashes.
open(WRITE, ">c:\\programs\\data.txt") || die ...;
Or, as you're not interpolating variables, switch to single quotes.
open(WRITE, '>c:\programs\data.txt') || die ...;
It's also worth using the three-argument version of open and lexical filehandles.
open(my $write_fh, '>', 'c:\programs\data.txt') || die ...;
you must use "/" to ensure portability, so: open(WRITE, ">c:/programs/data.txt")
Note: I assume that c:/programs folder exists
You may want to try FindBin.
use strict;
use warnings;
use autodie; # open will now die on failure
use FindBin;
use File::Spec::Functions 'catfile';
my $filename = catfile $FindBin::Bin, 'data.txt';
#obtain info in variables to be written to data.txt
print("What is your name?"); my $name = <STDIN>;
print("How old are you?"); my $age = <STDIN>;
print("What is your email address?"); my $email = <STDIN>;
{
open( my $fh, '>', $filename );
print {$fh} "Hi, $name, you are $age, and your email is $email\n";
close $fh;
}
If you have an access problem when you try to print to data.txt you can change that line to:
print WRITE "Hi, $name, you are \s $age and your email is \s $email" || die $!;
to get more information. A read only file will cause this error message:
Unable to open file data.txt: Permission denied at perl.pl line 12, <STDIN> line 3.
The code for my sub:
sub put_file
{
my($host, $placement_directory, $tar_directory, $filename, $user, $pass) = #_;
my $ftp = Net::FTP->new($host) or die "cannot connect to localhost";
$ftp->login($user, $pass) or die "cannot log in";
$ftp->cwd($placement_directory);
print $tar_directory."/".$filename;
$ftp->put("$tar_directory/$filename") or die "cannot put file ", $ftp->message;
print "File has been placed \n";
}
So when this sub is called from a test script(that runs from command line) that uses the same config file and does all of the same things as the CGI script, no errors are found and the file is placed correctly. When the sub is called from my CGI script the script will output the $tar_directory."/".$filename but not "File has been placed \n" and the ftp->message outputs "cannot put file Directory successfully changed." Which seems to come from the cwd line before it.
Other info:
I have tried running the test script as multiple users with the same result.
I use strict and warnings.
The tar file that is being moved is created by the script.
I'm new to perl so any advice is helpful because I'm stuck on this and cant find any help using the power of The Google.
Just a guess. Your ftp->put is failing, triggering the die. Unless you have:
use CGI::Carp qw(carpout fatalsToBrowser);
you won't see the die message in your browser. Since you died, you don't see the final print statement either.
Check your webserver log for the die output, or just change "die" to "print".
Net::FTP can put() from a filehandle as well as a file name:
open my $fh, '<', $tar_directory . '/' . $filename or die "Could not open file: $!";
$ftp->put($fh, $filename) or die "cannot put file ", $ftp->message;
If the problem is on your side then the open should fail and you should get an error message of some kind that will, hopefully, tell you what is wrong; if the problem is on the remote side then the put should fail and you'll see the same thing you'r seeing now.
That $ftp->message only has the success message from the cwd indicates that everything is fine on the remote side and the put isn't even reaching the remote server.