mod_perl handles inclusion paths differently than cgi? - perl

I have a script that's written in perl, and executed as CGI. It works fine. Recently I have installed the mod_perl module into apache, and used the PerlModule ModPerl::Registry directive.
PerlModule ModPerl::Registry
PerlModule CGI
PerlSendHeader On
Alias /perl/ /real/path/to/perl/scripts/
<Location /perl>
SetHandler perl-script
PerlHandler ModPerl::Registry
Options ExecCGI
</Location>
<Files *.perl>
SetHandler perl-script
PerlHandler ModPerl::Registry
Options ExecCGI
</Files>
I've read that using this I do not need to modify my cgi perl code. (I always use strict pragma, so don't worry about uninitialized global variables and stuff like that).
My original script still works as intended, except for one thing, files that I included with the require() function can no longer be resolved.
script.cgi:
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard Vars);
require "includes/functions.cgi";
#blah blah, more stuff
script.perl
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard Vars);
require "includes/functions.perl"; # <---- Returns error: Can't locate includes/functions.perl in #INC
#blah blah, more stuff
The directory structure works like this:
$ ls
script.cgi script.perl includes/
$ ls includes/
functions.cgi functions.perl

From: http://perl.apache.org/docs/2.0/api/ModPerl/Registry.html
META: document that for now we don't chdir() into the script's dir, because it affects the whole process under threads. ModPerl::RegistryPrefork should be used by those who run only under prefork MPM.
so, if you're using Apache2's prefork MPM, you should try using ModPerl::RegistryPrefork. If you're using worker, or event, or windows, you're going to have to change your program to not assume that the cwd is the directory that that the perl is sitting in.

Related

Perlbrew libs management

I have installed perlbrew and installed two Perls with it.
Now I am trying to separate libraries for modules I install with cpanm.
I want (if possible) to switch to one Perl (within Perlbrew) (for example: 5.22.4) and once I call cpanm install Some::Module the module will be installed in the separate library, related only to this Perl.
Then, in the script, I would like to have like the example below:
#!/usr/bin/env perl
use strict;
use Some::Module;
print "Content-type:text/html\n\n";
print "Works!";
and that's it. No any other use lib 'path'; or so.
I tried to use perlbrew lib create perl-5.22.4#somename and then switch to it.
Then call cpanm install Some::Module and I see the result at the location ~/.perlbrew/perl-5.22.4#somename/lib/perl5/Some/Module.pm, but when I call my script from a browser I see Error 500 and the logs say "missing module Some::Module, check #INC etc..."
What I also found that if I move the ~/.perlbrew/perl-5.22.4#somename/lib/perl5/Some/Module.pm to ~/perl5/perlbrew/perls/perl-5.22.4/lib/5.22.4/Some/Module.pm or to /home/arseniigorkin/perl5/perlbrew/perls/perl-5.22.4/lib/site_perl/5.22.4/x86_64-linux/Some/Module.pm then the script works. And Perl 5.22.4 (in our example) has its own library without need to use use lib 'path';
But, how to set up Perlbrew to switch cpanm automatically to this directory?
What I was also trying: cpanm install -l /home/arseniigorkin/perl5/perlbrew/perls/perl-5.22.4/lib/site_perl/5.22.4/x86_64-linux Some::Module to specify the target lib dir, but it creates the next tree under /home/arseniigorkin/perl5/perlbrew/perls/perl-5.22.4/lib/site_perl/5.22.4/x86_64-linux instead:
lib
perl5
Some
Module.pm
x86_64-linux
auto
[.....]
.meta
[.....]
perllocal.pod
install.pm
man
man3
[.....]
and, sadly, the script throws Error 500.
So, is there a possibility to omit use lib 'path'; in the script, switching between multiple Perl versions in Perlbrew?
This all happens on Ubuntu 22.04.
Update:
When switching to perl-5.22.4#somename and installing Some::Module via cpanm the module appears under the ~/.perlbrew/perl-5.22.4#somename/lib/perl5/Some/Module.pm as mentioned above, but the CGI script fails with Error 500.
However, when I execute the next command: perlbrew list-modules it shows Some::Module as installed under the current Perl (which I am switched to). So, this is a dissonance: Perlbrew "sees" the module under the specific Perl, but the CGI script cannot "see" this module under the same Perl.
Update 2:
here is the output of the perlbrew info:
Current perl:
Name: perl-5.22.4#somename
Path: /home/username/perl5/perlbrew/perls/perl-5.22.4/bin/perl
Config: -de -Dprefix=/home/username/perl5/perlbrew/perls/perl-5.22.4 -Dusesitecustomize -Aeval:scriptdir=/home/username/perl5/perlbrew/perls/perl-5.22.4/bin
Compiled at: Nov 10 2022 23:26:53
perlbrew:
version: 0.96
ENV:
PERLBREW_ROOT: /home/username/perl5/perlbrew
PERLBREW_HOME: /home/username/.perlbrew
PERLBREW_PATH: /home/username/.perlbrew/libs/perl-5.22.4#somename/bin:/home/username/perl5/perlbrew/bin:/home/arseniigorkin/perl5/perlbrew/perls/perl-5.22.4/bin
PERLBREW_MANPATH: /home/username/.perlbrew/libs/perl-5.22.4#somename/man:/home/username/perl5/perlbrew/perls/perl-5.22.4/man
Update 3:
The dirs permissions for the libs:
and
#terry0its is the name of the library (in the example I called it #somename.
Update 4:
Printing vars:
PERL_MB_OPT
PERL_MM_OPT
PERL5LIB
PATH
PERL_LOCAL_LIB_ROOT
with the script:
#!/usr/bin/env perl
print "Content-type:text/html\n\n";
print <<HTML;
Vars:<br>
PERL_MB_OPT = #{[$ENV{"PERL_MB_OPT"}]}<br>
PERL_MM_OPT = #{[$ENV{"PERL_MM_OPT"}]}<br>
PERL5LIB = #{[$ENV{"PERL5LIB"}]}<br>
PATH = #{[$ENV{"PATH"}]}<br>
PERL_LOCAL_LIB_ROOT = #{[$ENV{"PERL_LOCAL_LIB_ROOT"}]}<br>
HTML
In the web browser:
Vars:
PERL_MB_OPT =
PERL_MM_OPT =
PERL5LIB =
PATH = /home/username/.perlbrew/libs/perl-5.22.4#terry0its/bin:/home/username/perl5/perlbrew/bin:/home/username/perl5/perlbrew/perls/perl-5.22.4/bin:/root/Komodo IDE/bin:/home/username/anaconda3/condabin:/root/Komodo IDE/bin:/home/username/pycharm/bin:/home/username/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/home/username/.local/share/JetBrains/Toolbox/scripts
PERL_LOCAL_LIB_ROOT =
With the terminal:
Content-type:text/html
Vars:
PERL_MB_OPT = --install_base
/home/username/.perlbrew/libs/perl-5.22.4#terry0its
PERL_MM_OPT =
INSTALL_BASE=/home/username/.perlbrew/libs/perl-5.22.4#terry0its
PERL5LIB =
/home/username/.perlbrew/libs/perl-5.22.4#terry0its/lib/perl5
PATH =
/home/username/.perlbrew/libs/perl-5.22.4#terry0its/bin:/home/username/perl5/perlbrew/bin:/home/username/perl5/perlbrew/perls/perl-5.22.4/bin:/root/Komodo
IDE/bin:/home/username/anaconda3/condabin:/root/Komodo
IDE/bin:/home/username/pycharm/bin:/home/username/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/home/username/.local/share/JetBrains/Toolbox/scripts
PERL_LOCAL_LIB_ROOT =
/home/username/.perlbrew/libs/perl-5.22.4#terry0its
Update 5:
When I switch to a pure perl-5.22.4 (without external lib, like #terry0its) I see the next output for the same scripts (after the restart of the server):
In the web browser:
Vars:
PERL_MB_OPT =
PERL_MM_OPT =
PERL5LIB =
PATH = /home/username/anaconda3/condabin:/home/username/perl5/perlbrew/bin:/home/username/perl5/perlbrew/perls/perl-5.22.4/bin:/root/Komodo IDE/bin:/home/arseniigorkin/perl5/bin:/home/username/pycharm/bin:/home/username/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/home/username/.local/share/JetBrains/Toolbox/scripts
PERL_LOCAL_LIB_ROOT =
With the terminal:
Content-type:text/html
Vars:
PERL_MB_OPT --install_base "/home/username/perl5"
PERL_MM_OPT = INSTALL_BASE=/home/username/perl5
PERL5LIB =
PATH =
/home/username/anaconda3/condabin:/home/username/perl5/perlbrew/bin:/home/username/perl5/perlbrew/perls/perl-5.22.4/bin:/root/Komodo IDE/bin:/home/username/perl5/bin:/home/username/pycharm/bin:/home/username/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/home/username/.local/share/JetBrains/Toolbox/scripts
PERL_LOCAL_LIB_ROOT =
/home/username/perl5
The issue was related to Apache2 server-specific behavior with ENV variables.
It strips off some environment variables so they are undefined in your CGI scripts.
To have them in the CGI script you simply have to add PassEnv PERL5LIB into your host conf file and restart the server. Then, voila - you have PERL5LIB showing correctly in the output of $ENV{PERL5LIB} all across your site.
The example code:
<Directory "/home/user/someproject/server/www/public_html/cgi-bin">
AllowOverride All
Options None
Require all granted
Options +ExecCGI
PassEnv PERL5LIB
AddHandler cgi-script .cgi .pl
</Directory>
So, to use Perlbrew and easily switching between Perls and to have automatically handling all your libs (incl. externally created with perlbrew create lib somename) you have to PASS the PERl5LIB environment to your CGI scripts explicitly in the Apache configuration file for your host.
Do not forget to check if your mod_env is enabled in the httpd.conf (main Apache configuration file) as LoadModule env_module modules/mod_env.so (it must be uncommented).
I hope it will help others to handle easily their Perl libraries of perlbrew with Apache2 server.
Also, the module mod_env allows us to add custom environment variables, that we will be able to use all across the host or a server (it depends on where you put it in - inside the main conf file, your host file, or just into .htaccess for a particular dir(s) or even page(s)).
perlbrew does two things:
Makes installing Perl a little bit easier.
Manipulate the PATH of a shell that loads it.
The CGI script isn't launched by a shell.
First, you shouldn't be using PERL5LIB. Why install a custom perl using perlbrew and then try to cause it to use modules installed by another perl? This is nothing but bad. Unset PERL5LIB.
And with PERL5LIB unset, you shouldn't be using PERL_MB_OPT and PERL_MM_OPT either. You need to let the modules get installed where perl will find them.
So start by cleaning out the mess. Make sure PERL5LIB, PERL_MB_OPT and PERL_MM_OPT aren't set anywhere. You may to need reinstall the modules if they were installed in a weird place.
Now, using the correct perl will load the modules installed by that perl.
So what left is ensuring that we're using the correct perl. You use /usr/bin/env to locate perl. Does it makes sense for Apache's PATH to control which perl your application uses? Probably not.
What I would do is create an alias in perlbrew for your project.
perlbrew alias create perl-5.22.4#somename myproject
Then use the following shebang line:
#!/home/username/perl5/perlbrew/perls/myproject/bin/perl
That will allow you use to control which build of perl your project uses using
perlbrew alias create -f ... myproject
This works using symlinks, not PATH manipulation, so it works from anywhere, not just shells using perlbrew.

My Perl code does not seem to work with .lib?

I'm new to both Perl and its feature of .lib.
I made this simple subroutine and saved it as a file with an extension of .lib
sub shorterline {
print "Content-type: text/html\n\n";
}
1;
As I tried to insert the subroutine into the Perl file with an extension of .cgi below, it doesn't work somehow:
#!/usr/bin/perl
require 'mysubs.lib';
&shorterline;
print "Hello, world!";
I gave the .cgi the chmod permission, but the .cgi still doesn't work, what seem to be the problem ?
Your descriptions of what the problem is are rather unclear.
it doesn't work somehow
the .cgi still doesn't work
Without knowing what problems you're seeing, it's hard to know what the problem is. But I tried copying your code and running the program from the command line and I got this error message:
Can't locate mysubs.lib in #INC (#INC contains: ...)
So I think you are using a recent version of Perl and are running up against this change:
Removal of the current directory (".") from #INC
The perl binary includes a default set of paths in #INC. Historically it has also included the current directory (".") as the final entry, unless run with taint mode enabled (perl -T). While convenient, this has security implications: for example, where a script attempts to load an optional module when its current directory is untrusted (such as /tmp), it could load and execute code from under that directory.
Starting with v5.26, "." is always removed by default, not just under tainting. This has major implications for installing modules and executing scripts.
If this is the problem, then you can fix it by adding the script's directory to #INC as follows:
use FindBin qw( $RealBin );
use lib $RealBin;
before your call to require. If that doesn't solve your problem, perhaps you would consider sharing a little more detail about the problems that you are experiencing.

cgi script is not executing

I have a perl.cgi file which has the content:
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<h1>Hello World</h1>\n";
I made it executable. (chmod a+x perl.cgi)
Then I created a new file perl.htm in the same directory. Which has the following data:
Content-type: text/html
<p>RUN perl.cgi</p>
When I run the perl.htm in my browser then I get the output as:
Content-type: text/html
RUN perl.cgi
When I click on RUN perl.cgi another page opens and there the output is:
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<h1>Hello World</h1>\n";
i.e. the perl.cgi is not executing. Only the file contents are being shown.
EDIT: From the answers and comments I came to know that I will have to configure my web server (apache) to run cgi scripts. How can I do that? Let me know.
Sounds like Apache is not configured to run *.cgi files:
AddHandler cgi-script cgi pl
<Directory /path/to/cgi/files>
Options +ExecCGI
</Directory>
Make sure you are loading the CGI module in the httpd.conf file:
LoadModule cgi_module modules/mod_cgi.so or
LoadModule cgi_module modules/mod_cgid.so depending on which version of Apache you are running.
You can also read about additional solutions for
Dynamic Content with CGI.
Problem has been solved. I was not using httpd service at all, was opening from file:// URL.
Perl script is not executing in HTML form
You need to setup your web server so that it executes *.cgi files (or, more normally, all the files in a particular directory) rather than just delivering them to the browser as it does .html files.
How this is done depends on your server.

perl page not read as perl

I am trying to run this script
mail.pl
#!/usr/bin/perl
print "Content-type: text/html \n\n"; #HTTP HEADER
#CREATE
$email = "pt-desu\#*****-****.com";
#PRINT
print "$email<br />";
The file could be accessed via http://mysite.com/p/cgi-bin/mail.pl but when you go there the browser proms to download the file and does not display anything
Your webserver isn't set up to process *.pl files as Perl; it's instead just serving them up as plain-text. Consult your webserver's documentation for setting this up.
For Apache, try consulting this tutorial. The key bits are:
AddHandler cgi-script .cgi .pl
and
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
and
Options FollowSymLinks +ExecCGI
...in your httpd.conf file.

function not avaliable after restarting Apache

I am fairly new with perl and apache and seem to be having a small problem with my code.
I have 3 files:
hw.pm
package hw;
sub calc {
my $num1 = shift;
my $num2 = shift;
return $num1 + $num2;
}
1;
startup.pl
use lib qw(path to where hw.pm is located);
1;
hel.pl
#!/usr/bin/perl -w
use hw;
use CGI qw(:standard);
print header;
my $ans = calc(5,4);
print $ans;
I have no problem restarting apache but when I access hel.pl from the browser I get an error Can't locate hw.pm in #INC
Should the startup.pl have already included it in #INC? Or am I missing something?
I am using perl v5.10.1 and Apache2 v2.2.16
Perl is not finding hw.pm.
Try copying this line from startup.pl
use lib qw(path to where hw.pm is located);
to hel.pl, replacing the "use hw;" there. But first make sure the path is correct.
#INC - The array #INC contains the list
of places to look for Perl scripts to
be evaluated by the do EXPR , require
, or use constructs. It initially
consists of the arguments to any -I
command line switches, followed by the
default Perl library, probably
"/usr/local/lib/perl", followed by
".", to represent the current
directory.
I managed to solve it. initially i had this in my apache2.conf:
PerlRequire startup.pl
but after adding this code:
<Directory /var/www>
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
Options +ExecCGI
</Directory>
I was able to access my modules from hel.pl
Thanks guys for your help.