Perl & mod_fcgid- how can I be sure it's working? - perl

I have a couple Perl scripts I'm taking public soon, and I want to make sure they'll run under mod_fcgid in order to keep the server load as low as possible. Previously, I've only ever run scripts that test FastCGI (ie, while ( my $q = new CGI::Fast ) { $count++; echo $count;}) or taken advantage of larger Perl packages (like MovableType) that claim to run as FCGI as long as you set up Apache & FastCGI/mod_fcgid properly and change the file suffix to ".fcgi".
So, here's my question: do I need to do anything besides change the file suffix of my scripts, and if so, what?

You'll need to install FastCGI and configure your Apache to use it, but I assume you knew that. To test if your code is in fact running under FCGI instead of regular CGI, you can use the IsFastCGI method from the FCGI request object, which CGI::Fast uses under the hood.
use FCGI;
my $request = FCGI::Request();
if ( $request->IsFastCGI ) {
print "we're running under FastCGI!";
} else {
print "plain old boring CGI";
}

Related

Perl Dancer how to manage form actions

I'm learning perl Dancer and working on a to-do list depending on a form selection of two dates(today and tomorrow). If you select today a todo list for today will be generated, if you select tomorrow a different list will be created.
I've created a Dancer app called: Organizador and have the following in my Organizador.pm:
package Organizador;
use Dancer ':syntax';
use DBI;
our $VERSION = '0.1';
set session => "Simple";
get '/' => sub{
template 'index';
};
get '/create_to_do_list'=>sub{
template 'create_to_do_list';
};
I've created a file called create_to_do_list.pl which contains the script that I would like to execute when the form is created.
<form action="create_to_do_list.pl">
<legend>Create todo list</legend>
<label for="todoList">Create a todo list</label>
<select name='todoList' id='todoList'>
<option value="today">today</option>
<option value="tomorrow">tomorrow</option>
</select>
<button>Cancel</button>
<button>Create</button>
</form>
How can I call create_to_do_list.pl as an action on template 'create_to_do_list'; after hitting the create button?
Thanks!
I wanted to move to Dancer so I thought there was a faster way of calling my script instead of having to copy it...I'm working with thousands of thousand of [CGI] to-do lists...
Ideally, you should convert all of your CGI scripts to modules so that you can use them in non-CGI contexts (e.g. unit tests, web frameworks like Dancer and Mojolicious); however, if you really have thousands of them, that will take a long time.
As a stop-gap measure while you work on the conversion, you can use CGI::Compile and CGI::Emulate::PSGI to create a PSGI wrapper around each of your unconverted CGI scripts. You can easily integrate these with a Dancer2* app using Plack::Builder.
For example, to integrate the following CGI script with a Dancer2 app:
use strict;
use warnings 'all';
use CGI;
my $q = CGI->new;
print $q->header,
$q->start_html,
$q->h1('Hello, CGI!'),
$q->end_html;
Modify bin/app.psgi to look like this:
use strict;
use warnings 'all';
use FindBin;
use lib "$FindBin::Bin/../lib";
use CGI::Compile;
use CGI::Emulate::PSGI;
use Plack::Builder;
use MyApp;
my $foo_cgi = CGI::Compile->compile('/path/to/foo.cgi');
builder {
mount '/' => MyApp->to_app;
mount '/foo' => CGI::Emulate::PSGI->handler($foo_cgi);
};
Now, requests to / will call the / route in MyApp, while requests to /foo will call your CGI script.
In your form, change:
<form action="create_to_do_list.pl">
to:
<form action="/foo">
Make sure the names of your form fields all match what the CGI script is expecting, and voila! You can keep using your CGI script without modification.
(Note that you could skip all the PSGI wrapper business and just continue serving your CGI scripts with Apache or whatever you were using before, but this approach allows you to centralize your routes and simplifies deployment.)
Add a separate mount statement for each CGI script you want to integrate with your app. Note that this approach will probably have performance problems, so you should only use it as a temporary measure while you work on converting your CGI scripts to proper modules.
* For new development, you should really be using Dancer2. Dancer1 is in maintenance mode and although it's still officially supported, it won't be getting any new features. I know you've had trouble getting started with Dancer2, but you should resolve those issues instead of using an old version of the framework. (And it's still unclear what exactly you were having trouble with; you should edit that question if you still need help.)
Firstly, before you go too far down this path, switch from Dancer to Dancer2.
From your comments, it seems that create_to_do_list.pl is a CGI program. Is it running on the same web server? You could probably call it remotely using something from LWP or HTTP::Tiny, but I don't think that's a very good idea - you'll get HTML back which you'll need to parse in some way to extract the useful information.
It's a far better idea to move the code from create_to_do_list.pl into a module. If the CGI program needs to exist as well (for historical reasons, perhaps) then move the core code into a module which can be used from both the CGI program and the new Dancer app. But if you won't need the CGI program once the Dancer app is ready, I'd just copy the code into the correct place in Organizador.pm.
Instead of using DBI directly, you might find it easier to switch to Dancer::Plugin::Database (or its Dancer2 equivalent), bit for anything other than the simplest of database programs, I'd recommend DBIx::Class (and Dancer2::Plugin::DBIC).

How to use perl "require" function to call a perl script having a form and returning to original script when credentials are checked

I'm working on a perl program where I have a script that displays some information. Before that page is displayed, I need to do some logins to the page. I have tried using "require" function in my main script that calls another script that asks for username and password. I need to return back to my original program automatically when login conditions are satisfied.
Please help me with it.
File 1:
require 'index.pl';
File 2:
sub print_form {
my $query = new CGI; use vars qw($userid $pword);
my $password_dir = '/opt/app/d1pre2w1/sites/apache/cgi-bin-new/';
my $pword_file = "commit_access_control.cfg";
my $passwrd_location = $pword_file;
print("<td><form> \n", "USERNAME :", "<input type=text name=USERNAME >", "<br>", "PASSWORD :", "<input type=password name=PASSWORD>", "<br>", "<input type=submit name=login value=Login>", "</form>");
From your question it looks like you have two problems:
You are using an ancient and ill-advised Perl tutorial. Nobody in 2015 (much less 2001) would recommend using require for code reuse.
You do not understand how web applications work. You can't write a single application script that will flow smoothly from state to state. Instead, you must create a system that has a conversation with the client. While CGI based techniques are hardly modern, they do work and form the basis for many current technologies. Check out Ovid's CGI Course. Once you are comfortable with that, check out Mojolicious, Catalyst or Dancer for more modern approaches to web development in Perl.

How can I dynamically process all .html files through the Catalyst Framework?

I want to use Catalyst to process all requests: Both html (mixed with Template Toolkit), and those normally intended to be processed by Catalyst. I am aware of Catalyst::Plugin::Static::Simple, but that doesn't seem like it does what I am describing since it simply prints files statically.
As an example, I want to show whether the user is logged in on index.html without using ajax or SSI. There are many other cases beside that one.
There is probably a simple answer to this...
Thanks for the pointer, RET. My solution turned out to be pretty simple.
I made the nginx config point to my Catalyst App before serving files directly and added the path to my html files to the TT config in myapp.pm.
Here are the basics of the snippet I added to my Root.pm controller in the default subroutine:
if($c->req->path =~ m{\.html$} || $c->req->path =~ m{\.htm$}) {
$c->stash->{template} = $c->req->path;
$c->detach;
}
elsif($c->req->path !~ m{[.]+}) {
$c->stash->{template} = $c->req->path . '/index.html';
$c->detach;
}

How can I run a CGI::Application run mode from the command line?

I have a run mode in my CGI::Application web-app that I would like to be able to trigger from the command line so i can automate it. From the web-app's perspective it does some processing then sends the results in an email.
When called from the web interface it passes in a set of parameters (email address, which query to run, date, etc) so these need to be passed in.
How can I construct a call to the CGI::Application app that will be the same as if I ran it from the web?
The original CGI specification makes it easy to run things from the command line and was fully intended not as a specific HTTP-only interface but something that could handle FTP and gopher as well as new top-level URL schemes. I know what I wanted when I helped specify it.
The spec I referenced should give you all you need, but for the most part it is just a collection of environment variables. If you see a request for:
http://some.server.com/some/path?a=b&c=d
The environment variables come out looking like this:
SERVER_PROTOCOL=http
REQUEST_METHOD=GET
HTTP_HOST=some.server.com
SERVER_PORT=80
PATH_INFO=/some/path
QUERY_INFO=a=b&c=d
To reverse the polarity of that in Perl would go something like this:
$ENV{'SERVER_PROTOCOL'} = 'http';
$ENV{'REQUEST_METHOD'} = 'GET';
$ENV{'SERVER_PORT'} = 80;
$ENV{'PATH_INFO'} = '/some/path';
$ENV{'QUERY_INFO'} = 'a=b&c=d';
system("perl your-CGI-script.pl");
Things get a bit more complicated in handling POST queries and there are more possible environment variables that may be required. Worst case you can enumerate them all with a quick CGI script something like:
print "Content-Type: text/plain\r\n\r\n";
foreach (keys(%ENV))
{
print "$_=$ENV{$_}\r\n";
}
Now put that on the web server in place of your CGI script and you'll see all the environment that gets passed in (and the original environment so you'll need to make a few judgement calls).
Upon further digging through the CGI::App and the CGI documentation, it appeared to be more straightforward than I thought. The simplest case (no real argument handling or dealing with the output from the webapp run call) is:
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use WebApp;
my $cgi = new CGI( \%{#ARGV} );
my $webapp = WebApp->new( QUERY => $cgi );
$webapp->run();
It just takes a series of space separated name value pairs to create the CGI. You need to pass in the run mode and all the arguments.
I'm the maintainer of CGI::Application, and I do this all the time-- I have dozen of cron scripts built with CGI::Application because it's convenient to share the infrastructure with the application.
The simplest approach is this:
# There is no browser to return results to.
$ENV{CGI_APP_RETURN_ONLY} = 1;
my $app = WebApp->new;
$app->direct_run_mode_method;
In that example, you bypass the normal flow and call a method directly. Be sure you don't need any of the "setup" or "teardown" actions to happen in that case.
If you just have one run mode you are calling, you can also just set the "start_mode", and call run(), so then the default run mode is called by default.
Another idea: you can use a module like Getopt::Long and pass in values through the PARAM hash to new(), or completely replace the run-mode selection process. Here's an example where command line flags are used to determine the run mode:
sub setup {
my $self = shift;
$self->start_mode('send_error_digests');
$self->run_modes([qw/
send_error_digests
help
/]);
my ($dry_run, $help);
GetOptions(
'dry-run' => \$dry_run,
'help' => \$help
);
$self->param('dry_run' => $dry_run);
$self->mode_param(sub {
return 'help' if $help;
return $self->start_mode();
});
}
Thusly:
$ perl yourscript.pl field1=value1 field2=value2
Perl's CGI library takes care of the magic for you, and it appears that CGI::Application relies on CGI (judging from their example code).
Instead of having to go through CGI::Application every time you want to get something done, enforce a proper separation of concerns, perhaps using an MVC setup. All of the functionality should exist outside of the CGI::Application stuff since that should only work as a controller. Once you separate out those bits, you can easily write other controllers for other input methods.
Don't write a web application; write an an application that happens to have a web interface. When you have that, you can easily give your application other sorts of interfaces.
You could automate by calling the web app using curl, wget, or an LWP GET-script with the appropriate parameters. I've used a similar system for cron-driven tasks with a Catalyst application.
That deals with all the environment variables for you..

How can I read the URL-Data send with POST in Perl?

I'm trying to read out the POST-Data that was sent from a form in a page to my Perl Script. I googled and found out that:
read(STDIN, $param_string, $ENV{'CONTENT_LENGTH'})
reads out the whole Data-String with and writes the whole string to $param_string in the form of
Param1=Value1&Param2=Value2&Param3=Value3
by spliting it at the right places I get the necessary Data.
But I wonder why my $param_string is empty.
When I try the whole thing with GET:
$param_string = $ENV{'QUERY_STRING'};
everything works fine. Does anybody have an idea?
There absolutely no real reason for someone at your level to want to hand parse CGI requests.
Please use CGI::Simple or CGI.pm.
CGI.pm has a lot of baggage (HTML generation, function oriented interface) which makes CGI::Simple preferable.
Using any CGI processing module on CPAN is better than trying to write CGI processing code from scratch.
See parse_query_string in CGI::Simple for a way of accessing parameters passed using the query string when processing a form that is POSTed to your script.
If you want to learn how to do it right, you can read the source code of either module. Reading through the CGI.pm CHANGES file is also instructive.
If you are able to retrieve GET-data but not able to retrieve POST-data, most likely you forgot to change form method from to be post. You can check your submit method by using this condition in if statement:
if ($ENV{'REQUEST_METHOD'} eq "POST"){
read(STDIN, $param_string, $ENV{'CONTENT_LENGTH'});
}else {
$param_string = $ENV{'QUERY_STRING'};
}
Under mod_perl 2, Apache2::Request works for me.