Using Sftp to Transfer Images from HTML Form to Remote Linux Server Using Perl/Cgi.Pm

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 and use warnings.
  • -w on the shebang was obsoleted by use 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:

  1. Edit (Preferences) > Settings > Connection > SFTP, Click "Add key file”
  2. Browse to the location of your .pem file and select it.
  3. 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.
  4. 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.
  5. 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 and use warnings.
  • -w on the shebang was obsoleted by use 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



Leave a reply



Submit