Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
I'm preparing to move my CGI scripts over to CGI::Application.

The constraints are that any modules I need that don't come with Perl need to be installed locally and therefore need to be pure Perl. Also, the webhoster doesn't provide a cgi-bin dir so the cgi scripts are under docroot.

Please bear with me while I explain how the dir tree is arranged as it will have some bearing on how it all holds together.

I've created a 'project' dir (sw) outside of docroot.

This has 'app' dirs (e.g. test) and the local 'lib' dir.

Each app dir has a 'cnf' dir (config files), tmpl dir (template files), upld (uploaded files) etc..

The lib dir has the extra CPAN modules required plus a project dir (SW) for project specific modules and 'app' dirs (like Test).

my_root # top dir of web space docroot # html files and the cgi instance scripts sw lib CGI HTML # etc. SW ProjectClass.pm Test TestApp.pm OtherApps test cnf tmpl upld otherapps cnf tmpl upld

The first thing the instance script needs to do is set use lib;.

Rather that hard code the path to the local lib it knocks the last dir off the docroot env var and constructs the path given the scheme above. Due to the way CGI::App works the instance script is very short which makes keeping them in docroot less of a worry.

#!/usr/bin/perl -T # instance script # somewhere under docroot use strict; use warnings; #use CGI::Carp qw(fatalsToBrowser); use File::Spec; my ($my_root, $project, $lib); BEGIN { $ENV{DOCUMENT_ROOT} =~ m|([\w/-]+)/|; $my_root = $1; $project = 'sw'; $lib = File::Spec->catdir($my_root, $project, 'lib'); } use lib $lib; use SW::Test::TestApp; $ENV{PATH} = ''; my $c = SW::Test::TestApp->new( PARAMS => { 'root' => $my_root, 'project' => $project, 'app' => 'test', }, ); $c->run;

SW::Test::TestApp; is a sandbox that exercises all the plugins. A CGI::App 'hello world' script! Like nurse, something to hang on to when the going gets rough!

package SW::Test::TestApp; use strict; use warnings; use base 'SW::ProjectClass'; sub setup { my ($self) = @_; $self->error_mode( 'error_runmode' ); $self->start_mode( 'm1' ); $self->mode_param( path_info=> 1, param =>'rm' ); $self->run_modes( 'm1' => 'start', 'm2' => 'show_log_records', 'm5' => 'show_session', 'm7' => 'get_cnf_value', 'm8' => 'force_error', 'm9' => 'send_email_test', 'm10' => 'path_info', 'm11' => 'upload_get', 'm12' => 'upload_process', ); } # and then all the run modes # to exercise each plugin sub start { # }

CGI::Apps cgiapp_init method is in SW::ProjectClass.pm and will be the base class for all the apps.

The project super class loads all the required CGI::App::Plugins, configures them, sets a common error_runmode and sets cgiapp_get_query to CGI::Simple. As the instance script sets the root, project and app params the correct path for template files, config files, upload dirs, mysql cnfig file etc. are easily obtained.

package SW::ProjectClass; use strict; use warnings; use base 'CGI::Application'; use CGI::Simple; use CGI::Application::Plugin::Config::MyNewt; use CGI::Application::Plugin::DBH (qw/dbh_config dbh/); use CGI::Application::Plugin::LogDispatch; use CGI::Application::Plugin::Session; use CGI::Application::Plugin::SQL::Library; use MIME::Lite; sub cgiapp_init { my $self = shift; my $app_path = File::Spec->catdir( $self->param('root'), $self->param('project'), $self->param('app') ); $self->tmpl_path( File::Spec->catdir($app_path, 'tmpl'), ); my $cnf_path = File::Spec->catdir($app_path, 'cnf'); my $cnf_file = join('.', $self->param('app'), 'cnf'); $self->config_init( File::Spec->catfile($cnf_path, $cnf_file), ); my $dsn = join ('', "DBI:mysql:;mysql_read_default_file=", File::Spec->catfile($cnf_path, 'db.cnf'), ); $self->dbh_config( $dsn, undef, undef, {RaiseError => 1} ); $self->sql_lib_config( File::Spec->catfile($cnf_path, 'sql.lib'), ); $self->session_config( CGI_SESSION_OPTIONS => [ "driver:MySQL;serializer:Storable", $self->query, {Handle=>$self->dbh} ], DEFAULT_EXPIRY => '+1w', COOKIE_PARAMS => { -expires => '+24h', -path => '/' }, SEND_COOKIE => 1, ); $self->log_config( LOG_DISPATCH_MODULES => [ { module => 'Log::Dispatch::DBI', name => 'dbi', dbh => $self->dbh, table => 'log', min_level => 'debug', }, { module => 'Log::Dispatch::Email::MailSend', name => 'email', to => [qw(my@email.com)], subject => 'Log message from www.mywebsite.org.uk', min_level => 'emerg' } ] ); } sub cgiapp_get_query { my $self = shift; $CGI::Simple::DISABLE_UPLOADS = 0; # enable uploads $CGI::Simple::POST_MAX = 1_048_576; # allow 1MB uploads return CGI::Simple->new(); } sub mime_email { my ($self, $over_ride) = @_; my %default = ( From => 'somewhere@mail.com', To => 'webadmin@website.com', Subject => 'website enquiry', Type => 'text/html', Data => undef, ); @default{keys %{$over_ride}} = values %{$over_ride}; my $msg = MIME::Lite->new(%default,) or die "Error creating MIME body: $!\n"; $msg->send or die "Error sending MIME body: $!\n"; return \%default; } sub error_runmode{ my ($self, $msg) = @_; $self->log->emerg("Error: $msg"); my $tmpl_obj = $self->load_tmpl('error.html'); $tmpl_obj->param(msg => $msg,); return $tmpl_obj->output; } 1;

The apps I'll be converting use mysql as a backend which is why I've used it for session tracking and logging.

I still have a few wrinkles to sort out.

I've tried, as yet unsuccessfully, to install Template::Toolkit to the local lib. As explained before it would need to be the pure Perl version. I have to confess that tracking down the dependancy trail and installing those on the webhost has defeated me but it's still on the list. As it happens I'm a great fan of HTML::Template so this isn't a major draw back.

I had a similar snag with CGI::Application::Plugin::ValidateRM. The dependancies seemed to go on for ever! Also on the list.

I've yet to investigate CGI::Application::MailPage (I've rolled my own sub) and, for my sins, I've also rolled my own config module. At the moment I'm leaning toward CGI::Application::Plugin::Config::Simple.

I'm quite pleased with my very own CGI::Application::Plugin::SQL::Library, a simple wrapper around SQL::Library. ("Mum! Look! I've written a plugin!" :-))

For any monks in a similar situation to myself I would strongly recommend having a serious look at CGI::Application.

There is some work up front straightening out your structure and your base class. But after that things like query handling, sessions, db connection, logging, error handling, templating, configuration etc. all just work.

update:
Removed email/url details


In reply to "Hello world" for CGI::Application by wfsp

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2024-04-19 17:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found