Using SFTP to transfer images from HTML form to remote linux server using PERL/CGI.pm - linux

This is a school project, and the instructor has no knowledge of how to write the code.
I am using CGI and I am attempting to transfer a file without using Net::FTP or Net::SFTP since the server I am attempting to transfer it to will not allow connections from these services. I have written the HTML form and I am able to grab the name of the file uploaded through CGI.
Is it possible to use the SFTP command within a Perl script that resides on a Linux server using bash to transfer a file uploaded through an HTML form?
If anyone knows a way to do it please post the code so I can modify it and insert into my script.

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.

Related

Run PHP script in Node.js (or CMD)?

Due to some reasons in need to run a small part of my NodeJS Project in PHP7.
I know I can make an internal API but that would increase network dependency.
To solve this problem I found that this can be done as
php test.php
How do I provide a JSON input to this PHP file where data is stored in a JS variable not in file and receive output in another JS variable.
function runPHP(jsonString){
....what to write here
...
return output_string;
}
Note: Please, do not suggest Query parameters as the data is too large.
I assume you want to call a php scipt from a nodejs process, send some arguments in JSON and get back some JSON and process it further.
The php script:
<?php
// test.php
$stdin = fopen('php://stdin', 'r');
$json = '';
while ($line = fgets($stdin)) {
$json .= $line;
}
$decoded = \json_decode($json);
$decoded->return_message = 'Hello from PHP';
print \json_encode($decoded);
exit(0);
The nodejs script:
// test.js
function runPHP(jsonString) {
const spawn = require('child_process').spawn;
const child = spawn('php', ['test.php']);
child.stdin.setEncoding('utf-8');
child.stdout.pipe(process.stdout);
child.stdin.write(jsonString + '\n');
child.stdin.end();
}
runPHP('{"message": "hello from js"}');
This will need some polishing and error handling...

Module cwd assistance

I created a Perl module that is to be used in many Perl scripts to use Net::SSH::Expect
to do a login.
package myRoutines;
#
use v5.22;
use strict;
use warnings;
use Net::SSH::Expect;
use Exporter qw(import);
our #EXPORT_OK = qw(my_login);
sub my_login {
my $user = 'xxxx';
my $port = '10000';
my $passwd = 'XYZ';
my $adminServer = 'myServer';
my $rootpassword = 'ABCDEF';
my ( $pName, $vName ) = #_;
our $ssh = Net::SSH::Expect->new(
host => "$adminServer",
ssh_option => "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null",
user => "$user",
password => "$passwd",
port => "$port",
raw_pty => 1,
restart_timeout_upon_receive => 1,
log_file => "/var/tmp/clilog_$pName$vName"
);
eval {
my $login_output = $ssh->login();
if ( $login_output !~ />/ ) {
die "Login has failed.
Login output was $login_output";
}
};
return $ssh;
}
1;
The scripts will do:
use myRoutines qw(my_login);
our ( $ssh, $pName, $vName );
$pName = 'abc';
$vName = '123';
$ssh = my_login( $pName, $vName );
$ssh->send( "some command\r" );
This all works if I'm in the directory that the script and module are in. If I'm in any other directory, the new call works but the call to $ssh->send does nothing.
I've tried adding to my script:
use lib '/some/dir';
(where the .pm file resides) to force it find the module, and that seems to work when I'm not in the directory where the pm file resides.
I've tried to:
use File::chdir;
$CWD = '/some/dir';
and again, the login seems to work but the next send does nothing. So I'm at a loss as to what might be happening and would like some advice.
Update 20170908:
Upon further playing and following the suggestions made, I've done the following and it now works:
removed the eval as it was unnecessary.
removed the our's and made it my's.
removed the ""'s
set the following in the script:
use File::Basename;
use Cwd qw( abs_path );
chdir "/some/dir";
use lib dirname(abs_path($0));
my $scriptName = basename($0);
use myRoutines qw(ovm_login);
my $pName = substr($scriptName,0,-3); (cutting off the .pl from the end of the script name to pass the scriptname as the pName)
using chdir to change directory to where my pl script and pm file is and then setting the lib is seemingly working as it should.
Borodin, I'm not sure I understand your meaning when you say to object orient the module and .... but would be interested in hearing more to better understand.
If you don't want to hardcode the directory, you can use
use FindBin qw( $RealBin );
use lib $RealBin;
($RealBin is the path to the script. Adjust as needed if myRoutines.pm is in a subdir.)
The simple and easy way would be placing your .pm file in:
/usr/lib64/perl5/
directory and you shouldn't have any problems.
But still not the perfect solution, you should be able to put the .pm file wherever you want.

display /var/log/messages in html/php output?

I am trying to display the output of /var/log/messages or similar (../secure for instance) in a webpage that I access through a webserver on the same host.
Should I use bash to tail -f >> the messages file to a new output file and display that text file in the html page, or is there a better way to do this?
Thanks!
idiglivemusic
If you're looking for a way to display actual file contents online without the need to reload the page, then you should setup a WebSocket server.
You can build a WebSocket server using a framework such as phpDaemon, ReactPHP, Ratchet, icicle, or implement your own server with the help of PHP extensions wrapping asynchronous libraries: event, ev, or similar.
I've chosen a random framework from the list above: Ratchet. Ratchet is based on ReactPHP. ReactPHP chooses a backend for the event loop from the following list:
- libevent extension,
- libev extension,
- event extension,
- or an internal class based on the built-in stream_select() function.
As a maintainer of the event extension, I've chosen event.
I've written a "quick" example just to give you idea of how it might be implemented. You'll most likely have to work out your own version, maybe using different tools. But the code should give you an impulse.
src/MyApp/Server.php
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Server implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
printf("Connection %d sending '%s' to %d other connection%s\n",
$from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
public function broadcast($msg) {
foreach ($this->clients as $client) {
$client->send($msg);
}
}
}
server.php
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Server;
require __DIR__ . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
$my_app_server = new Server()
)
),
9989
);
$loop = $server->loop;
$filename = '/var/log/messages';
$loop->addPeriodicTimer(5, function ()
use ($filename, $my_app_server)
{
static $stat_info;
if ($stat_info == null) {
clearstatcache(true, $filename);
$stat_info = stat($filename);
}
clearstatcache(true, $filename);
$st = stat($filename);
$size_diff = $st['size'] - $stat_info['size'];
echo "Diff = $size_diff bytes\n";
if ($size_diff > 0) {
$offset = $stat_info['size'];
$bytes = $size_diff;
} elseif ($size_diff < 0) {
// The file is likely truncated by `logrotate` or similar utility
$offset = 0;
$bytes = $st['size'];
} else {
$bytes = 0;
}
$stat_info = $st;
if ($bytes) {
if (! $fp = fopen($filename, 'r')) {
fprintf(STDERR, "Failed to open file $filename\n");
return;
}
if ($offset > 0) {
fseek($fp, $offset);
}
if ($msg = fread($fp, $bytes)) {
$my_app_server->broadcast($msg);
}
fclose($fp);
}
}
);
$server->run();
test.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Test</title>
</head>
<body>
<script>
var conn = new WebSocket('ws://localhost:9989');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log("Msg from server", e.data);
};
</script>
</body>
</html>
I'll skip the steps required to setup a basic test environment using Composer. Assuming you have successfully configured the test environment for the files above, you'll be able to run the server with the following command:
php server.php
Check, if the user has permissions to read /var/log/messages. On my system only root can read the file. So you might need to run the above-mentioned command with sudo(root permissions).
Now you can open test.html in a browser and look at the console output. Then trigger some event which is normally logged to the messages file. For instance, you can invoke sudo with a wrong password. The server should detect the changes within interval of 5 seconds, then send it to the WebSocket clients.
If you're using tail -f, that means that you'll be continuously getting data from the file while it grows as the command runs.
You can use cat or tail -n. Also, of course, you can access files directly by creating a symbolic or hard link to them (ln source-file link-file, ln -s source-file link-file) - but make sure, that your web-server has enough rights to access them.
Make sure that your html-server has rights to access the page and read the page (with something like cat, tail, grep).
In <html> put the output between <pre> and </pre>.
Method 1
In one of your base directories, create a symbolic link
ln -s /var/log/messages messages
If the directory belonged to say, test.web, access the log with
unmesh
http://test.web/messages
Method 2
If you're looking for a php script then, first create the link as mentioned in method 1. Then, create a new file, say, readlog.php in the base directory of test.web with the below content :
<?php
readfile(“$DOCUMENT_ROOT/messages”);
?>
Access the readlog.php like :
http://test.web/readlog.php
Requirement:
Read access should be enabled for all users for /var/log/messages.
Note:
Setting read option for /var/log/messages for the whole world is NOT a good idea.
<!DOCTYPE html>
<html>
<head>
<title>toyLogs</title>
</head>
<body>
<div><p><?php include('/var/www/html/accesslog.txt'); ?></p></div>
</body>
</html>

How to avoid the hard coded username/password in perl script

How to avoid the hard coded username/password in perl script
I am new to perl I have tried lot of things nothing worked out for me, Please help to provide some method to read the username/password from config file. What things I need to change here,
Below is my perl script:
#!/usr/bin/perl -w
use strict;
use warnings;
use Net::SFTP::Foreign;
my $server="sftp.abcpvt.com";
my $remote="outgoing_folder";
my $user="auser";
my $LOCAL_PATH="/home/sara";
my $file_transfer="DATA.ZIP";
my $password="abc123"
my %args = (user => "$user", password => "$password");
chdir $LOCAL_PATH or die "cannot cd to ($!)\n";
my $sftp = Net::SFTP::Foreign->new(host=>$server,user=>$user,password=>$password) or die "unable to connect";
$sftp->error and die "SSH connection failed: " . $sftp->error;
$sftp->get("$remote/$file_transfer","$LOCAL_PATH/$file_transfer") or die "unable to retrieve file".$sftp->error;
undef $sftp;
exit;
MY config file contains below thing.
Username = “auser”;
Password = “abc123”;
Time_out=180;
Port = 22
I tried the below things,
my $user=get_credentials("/home/sar/config");
my $password=get_credentials("/home/sar/config");
sub get_credentials {
my ($file) = #_;
open my $fh, "<", $file or die $!;
my $line = <$fh>;
chomp($line);
my ($user, $pass) = split /:/, $line;
return ($user, password => $pass);
}
Here I am getting only the password, Username is not getting here…
Could you please share the sample coding for using the username/password in perl script.
I think you want something like this.
sub get_config {
my ($file) = #_;
open my $fh, "<", $file or die $!;
my %config;
while (<>) {
chomp;
next unless /\S/;
my ($key, $val) = split /\s*=\s*/;
$val =~ s/^"//;
$val =~ s/"$//;
%config{$key} = $val;
}
return \%config;
}
my $config = get_config('/home/a911091/config');
my $user = $config->{Username};
my $pass = $config->{Password};
But you'd be far better off looking for a config file module from CPAN.

File transfered via SFTP

I have a Linux (openSUSE 10.X) box and have a SFTP service on it.
When someone puts a file I have to write a script to move the files to another dir. I do not want to write a cron job. Is there an event or something I can check to see if they have sent the file?
You can write a c application and hook into inotify events.
Check also Net::SFTP::Server, an SFTP server written in Perl that can be extended to do things like the one you need.
Some code:
#!/usr/bin/perl
use strict;
use warnings;
use File::Basename ();
my $server = Server->new(timeout => 15);
$server->run;
exit(0);
package Server;
use Net::SFTP::Server::Constants qw(SSH_FXF_WRITE);
use parent 'Net::SFTP::Server::FS';
sub handle_command_open_v3 {
my ($self, $id, $path, $flags, $attrs) = #_;
my $writable = $flags & SSH_FXF_WRITE;
my $pflags = $self->sftp_open_flags_to_sysopen($flags);
my $perms = $attrs->{mode};
my $old_umask;
if (defined $perms) {
$old_umask = umask $perms;
}
else {
$perms = 0666;
}
my $fh;
unless (sysopen $fh, $path, $pflags, $perms) {
$self->push_status_errno_response($id);
umask $old_umask if defined $old_umask;
return;
}
umask $old_umask if defined $old_umask;
if ($writable) {
Net::SFTP::Server::FS::_set_attrs($path, $attrs)
or $self->send_status_errno_response($id);
}
my $hid = $self->save_file_handler($fh, $flags, $perms, $path);
$self->push_handle_response($id, $hid);
}
sub handle_command_close_v3 {
my $self = shift;
my ($id, $hid) = #_;
my ($type, $fh, $flags, $perms, $path) = $self->get_handler($hid);
$self->SUPER::handle_command_close_v3(#_);
if ($type eq 'file' and $flags & SSH_FXF_WRITE) {
my $name = File::Basename::basename($path);
rename $path, "/tmp/$name";
}
}
Save the script to somewhere in your server, chmod 755 $it, and configure OpenSSH to use it as the SFTP server instead of the default one.

Resources