Using SFTP to transfer images from HTML form to remote linux server using PERL/CGI.pm
use CGI qw(:standard);
use File::Basename;
my ( $name, $path, $extension) = fileparse ( $productimage, '..*' );
$productimage = $name . $extension;
$productimage =~ tr/ /_/; $productimage =~ s/[^$safechars]//g;
if ( $productimage =~/^([$safechars]+)$/ ) {
$productimage = $1;
} else {
die "Filename contains invalid characters";
}
$fh = upload('image');
$uploaddir = "../../.hidden/images";
open ( UPLOADFILE, ">$uploaddir/$productimage" )
or die "$!"; binmode UPLOADFILE;
while (<$fh>) {
print UPLOADFILE;
}
close UPLOADFILE;
This is the code I used to upload the file into the server.
How do I use embedded HTML form data when method is POST?
Someone is teaching you very bad practices. I don't know whether your sample code is following examples supplied by your school or whether you have cobbled it together from bad examples on the internet - but either way, this code uses techniques that have been out of date for twenty years.
There's a whole debate to be had about the wisdom of teaching CGI programming in 2017 (see CGI::Alternatives for a brief discussion of some better approaches) but let's ignore that and assume that CGI is a good idea here.
If you're writing a CGI program, then you should use the CGI.pm library which has been part of the standard Perl distribution for over twenty years (it was removed recently, but the chances of your school using a version this up to date is tiny).
A standard CGI program, using CGI.pm looks like this:
#!/user/bin/env perl
use strict;
use warnings;
use CGI qw[header param]; # Load the two functions we're going to use
# Display the content-type header
print header;
# See if we have been passed parameters.
if (param) {
# Display the parameters
# Note: I've ignored HTML here. You shouldn't
print 'Name: ', param('person');
print 'Sport: ', param('sport');
# etc...
} else {
# Display the form
...
}
I ignored HTML in my example because embedding HTML in your Perl code is a terrible idea. It's a much better idea to use a templating system (I recommend the Template Toolkit).
A few other points:
- Always
use strict
anduse warnings
. -w
on the shebang was obsoleted byuse warnings
in 2000.- Using
&
on subroutine calls has been unnecessary since Perl 5 was released in 1994.
I know that you don't know any better and that you're just following what your teacher is telling you to do. But it's really depressing to see such outdated practices been taught in school.
Update: And just to add the answer to your original question. You're right that in a POST request, the parameter data is no longer available in the QUERY_STRING
environment variable - you need to read it from STDIN
instead. That's one of the many advantages of CGI.pm - you use the same method (the param()
subroutine) to access both GET and POST parameters.
Pseudo-terminal will not be allocated because stdin is not a terminal
Try ssh -t -t
(or ssh -tt
for short) to force pseudo-tty allocation even if stdin isn't a terminal.
See also: Terminating SSH session executed by bash script
From ssh manpage:
-T Disable pseudo-tty allocation.
-t Force pseudo-tty allocation. This can be used to execute arbitrary
screen-based programs on a remote machine, which can be very useful,
e.g. when implementing menu services. Multiple -t options force tty
allocation, even if ssh has no local tty.
How to retrieve a file from a server via SFTP?
Another option is to consider looking at the JSch library. JSch seems to be the preferred library for a few large open source projects, including Eclipse, Ant and Apache Commons HttpClient, amongst others.
It supports both user/pass and certificate-based logins nicely, as well as all a whole host of other yummy SSH2 features.
Here's a simple remote file retrieve over SFTP. Error handling is left as an exercise for the reader :-)
JSch jsch = new JSch();
String knownHostsFilename = "/home/username/.ssh/known_hosts";
jsch.setKnownHosts( knownHostsFilename );
Session session = jsch.getSession( "remote-username", "remote-host" );
{
// "interactive" version
// can selectively update specified known_hosts file
// need to implement UserInfo interface
// MyUserInfo is a swing implementation provided in
// examples/Sftp.java in the JSch dist
UserInfo ui = new MyUserInfo();
session.setUserInfo(ui);
// OR non-interactive version. Relies in host key being in known-hosts file
session.setPassword( "remote-password" );
}
session.connect();
Channel channel = session.openChannel( "sftp" );
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp) channel;
sftpChannel.get("remote-file", "local-file" );
// OR
InputStream in = sftpChannel.get( "remote-file" );
// process inputstream as needed
sftpChannel.exit();
session.disconnect();
Connect to Amazon EC2 file directory using Filezilla and SFTP
I've created a video tutorial for this. Just check:
Connect to Amazon EC2 file directory using FileZilla and SFTP, Video Tutorial
Summary of above video tutorial:
- Edit (Preferences) > Settings > Connection > SFTP, Click "Add key file”
- Browse to the location of your .pem file and select it.
- A message box will appear asking your permission to convert the file into ppk format. Click Yes, then give the file a name and store it somewhere.
- If the new file is shown in the list of Keyfiles, then continue to the next step. If not, then click "Add keyfile..." and select the converted file.
File > Site Manager Add a new site with the following parameters:
Host: Your public DNS name of your EC2 instance, or the public IP address of the server.
Protocol: SFTP
Logon Type: Normal
User: From the docs: "For Amazon Linux, the default user name is ec2-user. For RHEL5, the user name is often root but might be ec2-user. For Ubuntu, the user name is ubuntu. For SUSE Linux, the user name is root. For Debian, the user name is admin. Otherwise, check with your AMI provider."
Press Connect Button - If saving of passwords has been disabled, you will be prompted that the logon type will be changed to 'Ask for password'. Say 'OK' and when connecting, at the password prompt push 'OK' without entering a password to proceed past the dialog.
Note: FileZilla automatically figures out which key to use. You do not need to specify the key after importing it as described above.
If you use Cyberduck follow this.
Check this post if you have any permission issues.
How can I upload (FTP) files to server in a Bash script?
Below are two answers. First is a suggestion to use a more secure/flexible solution like ssh/scp/sftp. Second is an explanation of how to run ftp in batch mode.
A secure solution:
You really should use SSH/SCP/SFTP for this rather than FTP. SSH/SCP have the benefits of being more secure and working with public/private keys which allows it to run without a username or password.
You can send a single file:
scp <file to upload> <username>@<hostname>:<destination path>
Or a whole directory:
scp -r <directory to upload> <username>@<hostname>:<destination path>
For more details on setting up keys and moving files to the server with RSYNC, which is useful if you have a lot of files to move, or if you sometimes get just one new file among a set of random files, take a look at:
http://troy.jdmz.net/rsync/index.html
You can also execute a single command after sshing into a server:
From man ssh
ssh [...snipped...] hostname [command] If command is specified, it is
executed on the remote host instead of a login shell.
So, an example command is:
ssh username@hostname.example bunzip file_just_sent.bz2
If you can use SFTP with keys to gain the benefit of a secured connection, there are two tricks I've used to execute commands.
First, you can pass commands using echo and pipe
echo "put files*.xml" | sftp -p -i ~/.ssh/key_name username@hostname.example
You can also use a batchfile with the -b
parameter:
sftp -b batchfile.txt ~/.ssh/key_name username@hostname.example
An FTP solution, if you really need it:
If you understand that FTP is insecure and more limited and you really really want to script it...
There's a great article on this at http://www.stratigery.com/scripting.ftp.html
#!/bin/sh
HOST='ftp.example.com'
USER='yourid'
PASSWD='yourpw'
FILE='file.txt'
ftp -n $HOST <<END_SCRIPT
quote USER $USER
quote PASS $PASSWD
binary
put $FILE
quit
END_SCRIPT
exit 0
The -n
to ftp ensures that the command won't try to get the password from the current terminal. The other fancy part is the use of a heredoc: the <<END_SCRIPT
starts the heredoc and then that exact same END_SCRIPT
on the beginning of the line by itself ends the heredoc. The binary
command will set it to binary mode which helps if you are transferring something other than a text file.
How do I use embedded HTML form data when method is POST?
Someone is teaching you very bad practices. I don't know whether your sample code is following examples supplied by your school or whether you have cobbled it together from bad examples on the internet - but either way, this code uses techniques that have been out of date for twenty years.
There's a whole debate to be had about the wisdom of teaching CGI programming in 2017 (see CGI::Alternatives for a brief discussion of some better approaches) but let's ignore that and assume that CGI is a good idea here.
If you're writing a CGI program, then you should use the CGI.pm library which has been part of the standard Perl distribution for over twenty years (it was removed recently, but the chances of your school using a version this up to date is tiny).
A standard CGI program, using CGI.pm looks like this:
#!/user/bin/env perl
use strict;
use warnings;
use CGI qw[header param]; # Load the two functions we're going to use
# Display the content-type header
print header;
# See if we have been passed parameters.
if (param) {
# Display the parameters
# Note: I've ignored HTML here. You shouldn't
print 'Name: ', param('person');
print 'Sport: ', param('sport');
# etc...
} else {
# Display the form
...
}
I ignored HTML in my example because embedding HTML in your Perl code is a terrible idea. It's a much better idea to use a templating system (I recommend the Template Toolkit).
A few other points:
- Always
use strict
anduse warnings
. -w
on the shebang was obsoleted byuse warnings
in 2000.- Using
&
on subroutine calls has been unnecessary since Perl 5 was released in 1994.
I know that you don't know any better and that you're just following what your teacher is telling you to do. But it's really depressing to see such outdated practices been taught in school.
Update: And just to add the answer to your original question. You're right that in a POST request, the parameter data is no longer available in the QUERY_STRING
environment variable - you need to read it from STDIN
instead. That's one of the many advantages of CGI.pm - you use the same method (the param()
subroutine) to access both GET and POST parameters.
Related Topics
Awk: Sum Up Column Values Across Multiple Files with Identical Column Layout
How to Search The Content of a PDF File in Linux Shell Script
Generic Printing Using a Usb Port
Sort a Find Command to Respect a Custom Order in Unix
Why a Static Library Can Depend on a Shared a Library
How to Write Content to File on Linux Sftp Server Using Sshclient
Session Permission Denied on Aws After Setting Up Cake PHP.
Command and Script to Re-Read a File in Gnuplot
Use Awk to Print $0 Using The Same Format for All Columns
Git Status Between Windows and Linux Does Not Agree
How to Use Schell Script to Read Element from a File, Do Some Calculation and Write Back
Does Zgrep Unzip a File Before Searching
Change The Rlimit_Nproc in Linux
Cvs Error: Failed to Create Lock Directory... Permission Denied
How to Cross-Compile a Autotools Project for Arm
Difference Between The Commands "Gcloud Compute Ssh" and "Ssh"