Apache2-SSI
view release on metacpan or search on metacpan
NAME
Apache2::SSI - Apache2 Server Side Include
SYNOPSIS
Outside of Apache:
use Apache2::SSI;
my $ssi = Apache2::SSI->new(
## If running outside of Apache
document_root => '/path/to/base/directory'
## Default error message to display when ssi failed to parse
## Default to [an error occurred while processing this directive]
errmsg => '[Oops]'
);
my $fh = IO::File->new( "</some/file.html" ) || die( "$!\n" );
$fh->binmode( ':utf8' );
my $size = -s( $fh );
my $html;
$fh->read( $html, $size );
$fh->close;
if( !defined( my $result = $ssi->parse( $html ) ) )
{
$ssi->throw;
};
print( $result );
Inside Apache, in the VirtualHost configuration, for example:
PerlModule Apache2::SSI
PerlOptions +GlobalRequest
PerlSetupEnv On
<Directory "/home/joe/www">
Options All +Includes +ExecCGI -Indexes -MultiViews
AllowOverride All
SetHandler modperl
# You can choose to set this as a response handler or a output filter, whichever works.
# PerlResponseHandler Apache2::SSI
PerlOutputFilterHandler Apache2::SSI
# If you do not set this to On, path info will not work, example:
# /path/to/file.html/path/info
# See: <https://httpd.apache.org/docs/current/en/mod/core.html#acceptpathinfo>
AcceptPathInfo On
# To enable no-caching (see no_cache() in Apache2::RequestUtil:
PerlSetVar Apache2_SSI_NO_CACHE On
# This is required for exec cgi to work:
# <https://httpd.apache.org/docs/current/en/mod/mod_include.html#element.exec>
<Files ~ "\.pl$">
SetHandler perl-script
AcceptPathInfo On
PerlResponseHandler ModPerl::PerlRun
## Even better for stable cgi scripts:
## PerlResponseHandler ModPerl::Registry
## Change this in mod_perl1 PerlSendHeader On to the following:
## <https://perl.apache.org/docs/2.0/user/porting/compat.html#C_PerlSendHeader_>
PerlOptions +ParseHeaders
</Files>
<Files ~ "\.cgi$">
SetHandler cgi-script
AcceptPathInfo On
</Files>
# To enable debugging output in the Apache error log
# PerlSetVar Apache2_SSI_DEBUG 3
# To set the default echo message
# PerlSetVar Apache2_SSI_Echomsg
# To Set the default error message
# PerlSetVar Apache2_SSI_Errmsg "Oops, something went wrong"
# To Set the default size format: bytes or abbrev
# PerlSetVar Apache2_SSI_Sizefmt "bytes"
# To Set the default date time format
# PerlSetVar Apache2_SSI_Timefmt ""
# To enable legacy mode:
# PerlSetVar Apache2_SSI_Expression "legacy"
# To enable trunk mode:
# PerlSetVar Apache2_SSI_Expression "trunk"
</Directory>
expressions.
handler
This is a key method expected by mod_perl. Depending on how this module
is used, it will redirect either to "apache_filter_handler" or to
"apache_response_handler"
ap2perl_expr
This method is used to convert Apache2 expressions into perl equivalents
to be then eval'ed.
It takes an hash reference provided by "parse" in Apache2::Expression,
an array reference to store the output recursively and an optional hash
reference of parameters.
It parse recursively the structure provided in the hash reference to
provide the perl equivalent for each Apache2 expression component.
It returns the array reference provided used as the content buffer. This
array is used by "parse_expr" and then joined using a single space to
form a string of perl expression to be eval'ed.
apache_filter
Set or get the Apache2::Filter object.
When running under Apache mod_perl this is set automatically from the
special "handler" method.
apache_filter_handler
This method is called from "handler" to handle the Apache response when
this module Apache2::SSI is used as a filter handler.
See also "apache_response_handler"
apache_request
Sets or gets the Apache2::RequestRec object. As explained in the "new"
method, you can get this Apache object by requiring the package
Apache2::RequestUtil and calling "request" in Apache2::RequestUtil such
as "Apache2::RequestUtil-"request> assuming you have set "PerlOptions
+GlobalRequest" in your Apache Virtual Host configuration.
When running under Apache mod_perl this is set automatically from the
special "handler" method, such as:
my $r = $f->r; # $f is the Apache2::Filter object provided by Apache
apache_response_handler
This method is called from "handler" to handle the Apache response when
this module Apache2::SSI is used as a response handler.
See also "apache_filter_handler"
clone
Create a clone of the object and return it.
decode_base64
Decode base64 data provided. When running under Apache mod_perl, this
uses "decode" in APR::Base64 module, otherwise it uses "decode" in
MIME::Base64
If the decoded data contain utf8 data, this will decoded the utf8 data
using "decode" in Encode
If an error occurred during decoding, it will return undef and set an
"error" object accordingly.
decode_entities
Decode html data containing entities. This uses "decode_entities" in
HTML::Entities
If an error occurred during decoding, it will return undef and set an
"error" object accordingly.
Example:
$ssi->decode_entities( 'Tous les êtres humains naissent libres et égaux en dignité et en droits.' );
# Tous les êtres humains naissent libres et égaux en dignité et en droits.
decode_uri
Decode uri encoded data. This uses "uri_unescape" in URI::Escape.
Not to be confused with x-www-form-urlencoded data. For that see
"decode_url"
If an error occurred during decoding, it will return undef and set an
"error" object accordingly.
Example:
$ssi->decode_uri( 'https%3A%2F%2Fwww.example.com%2F' );
# https://www.example.com/
decode_url
Decode x-www-form-urlencoded encoded data. When using Apache mod_perl,
this uses "decode" in APR::Request and "decode" in Encode, otherwise it
uses "url_decode_utf8" in URL::Encode (its XS version) to achieve the
same result.
If an error occurred during decoding, it will return undef and set an
"error" object accordingly.
Example:
$ssi->decode_url( 'Tous+les+%C3%83%C2%AAtres+humains+naissent+libres+et+%C3%83%C2%A9gaux+en+dignit%C3%83%C2%A9+et+en+droits.' );
# Tous les êtres humains naissent libres et égaux en dignité et en droits.
document_filename
This is an alias for "filename" in Apache2::SSI::URI
document_directory
Returns an Apache2::SSI::URI object of the current directory of the
"document_uri" provided.
document_path
Sets or gets the uri path to the document. This is the same as
"document_uri", except it is striped from "query_string" and
"path_info".
document_root
Sets or gets the document root.
Wen running under Apache mod_perl, this value will be available
automatically, using "document_root" in Apache2::RequestRec method.
If it runs outside of Apache, this will use the value provided upon
instantiating the object and passing the *document_root* parameter. If
this is not set, it will return the value of the environment variable
"DOCUMENT_ROOT".
document_uri
Sets or gets the document uri, which is the uri of the document being
processed.
For example:
/index.html
Under Apache, this will get the environment variable "DOCUMENT_URI" or
calls the "uri" in Apache2::RequestRec method.
Outside of Apache, this will rely on a value being provided upon
instantiating an object, or the environment variable "DOCUMENT_URI" be
present.
The value should be an absolute uri.
echomsg
The default message to be returned for the "echo" command when the
variable called is not defined.
Example:
$ssi->echomsg( '[Value Undefined]' );
## or in the document itself
<!--#config echomsg="[Value Undefined]" -->
<!--#echo var="NON_EXISTING" encoding="none" -->
would produce:
[Value Undefined]
encode_base64
Encode data provided into base64. When running under Apache mod_perl,
this uses "encode" in APR::Base64 module, otherwise it uses "encode" in
MIME::Base64
If the data have the perl internal utf8 flag on as checked with
"is_utf8" in Encode, this will encode the data into utf8 using "encode"
in Encode before encoding it into base64.
Please note that the base64 encoded resulting data is all on one line,
similar to what Apache would do. The data is NOT broken into lines of 76
characters.
If an error occurred during encoding, it will return undef and set an
"error" object accordingly.
encode_entities
Encode data into html entities. This uses "encode_entities" in
HTML::Entities
If an error occurred during encoding, it will return undef and set an
"error" object accordingly.
Example:
$ssi->encode_entities( 'Tous les êtres humains naissent libres et égaux en dignité et en droits.' );
# Tous les êtres humains naissent libres et égaux en dignité et en droits.
encode_uri
Encode uri data. This uses "uri_escape_utf8" in URI::Escape.
Not to be confused with x-www-form-urlencoded data. For that see
"encode_url"
If an error occurred during encoding, it will return undef and set an
"error" object accordingly.
Example:
$ssi->encode_uri( 'https://www.example.com/' );
# https%3A%2F%2Fwww.example.com%2F
encode_url
Encode data provided into an x-www-form-urlencoded string. When using
Apache mod_perl, this uses "encode" in APR::Request, otherwise it uses
"url_encode_utf8" in URL::Encode (its XS version)
If an error occurred during decoding, it will return undef and set an
"error" object accordingly.
Example:
$ssi->encode_url( 'Tous les êtres humains naissent libres et égaux en dignité et en droits.' );
# Tous+les+%C3%83%C2%AAtres+humains+naissent+libres+et+%C3%83%C2%A9gaux+en+dignit%C3%83%C2%A9+et+en+droits.
env
Sets or gets the value for an environment variable. Or, if no
environment variable name is provided, it returns the entire hash
reference. This method is intended to be used by users of this module,
not by developers wanting to inherit from it.
Note that the environment variable hash is unique for each new object,
so it works like "subprocess_env" in Apache2::RequestRec, meaning each
process has its set of environment variable.
When a value is set for an environment variable that has an equivalent
name, it will call the method as well with the new value provided. This
is done to ensure data consistency and also additional processing if
necessary.
For example, let assume you set the environment variable "REQUEST_URI"
or "DOCUMENT_URI" like this:
$ssi->env( REQUEST_URI => '/some/path/to/file.html?q=something&l=ja_JP' );
This will, in turn, call "request_uri", which is an alias for
document_uri and this method will get the uri, path info and query
string from the value provided and set those values accordingly, so they
can be available when parsing.
errmsg
Sets or gets the error message to be displayed in lieu of a faulty ssi
directive. This is the same behaviour as in Apache.
error
Retrieve the error object set. This is a Module::Generic::Error object.
This module does not die nor "croak", but instead returns undef when an
error occurs and set the error object.
It is up to you to check the return value of the method calls. If you do
not, you will miss important information. If you really want your script
to die, it is up to you to interrupt it:
if( !defined( $ssi->parse( $some_html_data ) ) )
{
die( $ssi->error );
}
or maybe more simply, when you are sure you will not get a false, but
defined value:
$ssi->parse( $some_html_data ) || die( $ssi->error );
This example is dangerous, because "parse" might return an empty string
which will be construed as a false value and will trigger the die
Example:
<!--#if expr=1 -->
Hi, should print
<!--#elif expr=1 -->
Shouldn't print
<!--#else -->
Shouldn't print
<!--#endif -->
parse_else
Parse the "else" condition.
See "parse_elif" above for example.
parse_endif
Parse the "endif" condition.
See "parse_elif" above for example.
parse_flastmod
Process the ssi directive "flastmod"
Provided with an hash reference of parameters and this will return the
formatted date time of the file last modification time.
parse_fsize
Provided with an hash reference of parameters and this will return the
formatted file size.
The output is affected by the value of "sizefmt". If its value is
"bytes", it will return the raw size in bytes, and if its value is
"abbrev", it will return its value formated in kilo, mega or giga units.
Example
<!--#config sizefmt="abbrev" -->
This file size is <!--#fsize file="/some/filesystem/path/to/archive.tar.gz" -->
would return:
This file size is 12.7M
Or:
<!--#config sizefmt="bytes" -->
This file size is <!--#fsize virtual="/some/filesystem/path/to/archive.tar.gz" -->
would return:
This file size is 13,316,917 bytes
The size value before formatting is a Module::Generic::Number and the
output is formatted using Number::Format by calling "format" in
Module::Generic::Number
parse_func_base64
Returns the arguments provided into a base64 string.
If the arguments are utf8 data with perl internal flag on, as checked
with "is_utf8" in Encode, this will encode the data into utf8 with
"encode" in Encode before encoding it into base64.
Example:
<!--#set var="payload" value='{"sub":"1234567890","name":"John Doe","iat":1609047546}' encoding="base64" -->
<!--#if expr="$payload == 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjA5MDQ3NTQ2fQo='" -->
Payload matches
<!--#else -->
Sorry, this failed
<!--#endif -->
parse_func_env
Return first match of note, reqenv, and osenv
Example:
<!--#if expr="env( $QUERY_STRING ) == /\bl=ja_JP/" -->
Showing Japanese data
<!--#else -->
Defaulting to English
<!--#endif -->
parse_func_escape
Escape special characters in %hex encoding.
Example:
<!--#set var="website" value="https://www.example.com/" -->
Please go to <a href="<!--#echo var='website' encoding='escape' -->"><!--#echo var="website" --></a>
parse_func_http
Get HTTP request header; header names may be added to the Vary header.
Example:
<!--#if expr="http('X-API-ID') == 1234567" -->
You're good to go.
<!--#endif -->
However, outside of an Apache environment this will return the value of
the environment variable in the following order:
X-API-ID (i.e. the name as-is)
HTTP_X_API_ID (i.e. adding "HTTP_" and replace "-" for "_")
X_API_ID (i.e. same as above, but without the "HTTP_" prefix)
If none is found, it returns an empty string.
For an equivalent function for response headers, see "parse_func_resp"
parse_func_ldap
Escape characters as required by LDAP distinguished name escaping
(RFC4514) and LDAP filter escaping (RFC4515).
See Apache documentation
<https://httpd.apache.org/docs/trunk/en/expr.html#page-header> for more
information
Example:
<!--#set var="phrase" value="%{ldap:'Tous les êtres humains naissent libres (et égaux) en dignité et\ en\ droits.\n'}" -->
# Tous les êtres humains naissent libres \28et égaux\29 en dignité et\5c en\5c droits.\5cn
parse_func_md5
Hash the string using MD5, then encode the hash with hexadecimal
encoding.
If the arguments are utf8 data with perl internal flag on, as checked
with "is_utf8" in Encode, this will encode the data into utf8 with
"encode" in Encode before encoding it with md5.
Example:
<!--#if expr="md5( $hash_data ) == '2f50e645b6ef04b5cfb76aed6de343eb'" -->
You're good to go.
<!--#endif -->
parse_func_note
Lookup request note
<!--#set var="CUSTOMER_ID" value="1234567" -->
<!--#if expr="note('CUSTOMER_ID') == 1234567" -->
Showing special message
<!--#endif -->
This uses Apache2::SSI::Notes to enable notes to be shared on and off
Apache2/mod_perl2 environment. Thus, you could set a note from a
command-line perl script, and then access it under Apache2/mod_perl2 or
just your regular script running under a web server.
For example:
In your perl script outside of Apache:
# Basic parameters to make Apache2::SSI happy
my $ssi = Apache2::SSI->new( document_root => '/home/john/www', document_uri => '/' ) ||
die( Apache2::SSI->error );
$ssi->notes( API_VERSION => 2 );
Then, in your perl script running under the web server, be it
Apache2/mod_perl2 or not:
my $ssi = Apache2::SSI->new || die( Apache2::SSI->error );
my $api_version = $ssi->notes( 'API_VERSION' );
To enable shareability of notes on and off Apache, this makes uses of
shared memory segments. See Apache2::SSI::Notes for more information on
the notes api and perlipc for more information on shared memory
segments.
Just keep in mind that the notes are never removed even when Apache
shuts down, so it is your responsibility to remove them if you do not
want them anymore. For example:
use Apache2::SSI::Notes;
my $notes = Apache2::SSI::Notes->new;
$notes->remove;
be aware that shared notes might note be available for your platform.
Check Apache2::SSI::Notes for more information and also perlport on
shared memory segments.
parse_func_osenv
Lookup operating system environment variable
<!--#if expr="env('LANG') =~ /en(_(GB|US))/" -->
Showing English language
<!--#endif -->
parse_func_tolower
Convert string to lower case.
Example:
<!--#if expr="tolower('Tous les êtres humains naissent libres et égaux en dignité et en droits.') == 'tous les êtres humains naissent libres et égaux en dignité et en droits.'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
parse_func_toupper
Convert string to upper case.
Example:
<!--#if expr="toupper('Tous les êtres humains naissent libres et égaux en dignité et en droits.') == 'TOUS LES ÃTRES HUMAINS NAISSENT LIBRES ET ÃGAUX EN DIGNITà ET EN DROITS.'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
parse_func_unbase64
Decode base64 encoded string, return truncated string if 0x00 is found.
Example:
<!--#if expr="unbase64('VG91cyBsZXMgw6p0cmVzIGh1bWFpbnMgbmFpc3NlbnQgbGlicmVzIGV0IMOpZ2F1eCBlbiBkaWduaXTDqSBldCBlbiBkcm9pdHMu') == 'Tous les êtres humains naissent libres et égaux en dignité et en droits.'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
parse_func_unescape
Unescape %hex encoded string, leaving encoded slashes alone; return
empty string if %00 is found.
Example:
<!--#if expr="unescape('https%3A%2F%2Fwww.example.com%2F') == 'https://www.example.com/'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
parse_if
Parse the "if" condition.
See "parse_elif" above for example.
parse_include
Provided with an hash reference of parameters and this process the ssi
directive "include", which is arguably the most used.
It will try to resolve the file to include by calling "find_file" with
the same arguments this is called with.
Under Apache, if the previous look up succeeded, it calls "run" in
Apache2::SubRequest
Outside of Apache, it reads the entire file, utf8 decode it and return
it.
parse_perl
Provided with an hash reference of parameters and this parse some perl
command and returns the output as a string.
Example:
<!--#perl sub="sub{ print 'Hello!' }" -->
or
<!--#perl sub="package::subroutine" -->
parse_printenv
This returns a list of environment variables sorted and their values.
parse_set
Provided with an hash reference of parameters and this process the ssi
directive "set".
Possible parameters are:
*decoding*
The decoding of the variable before it is set. This can be "none",
"url", "urlencoded", "base64" or "entity"
*encoding*
This instruct to encode the variable value before display. It can
the same possible value as for decoding.
*value*
The string value for the variable to be set.
*var*
The variable name
Example:
<!--#set var="debug" value="2" -->
<!--#set decoding="entity" var="HUMAN_RIGHT" value="Tous les êtres humains naissent libres et égaux en dignité et en droits." encoding="urlencoded" -->
See the Apache SSI documentation
<https://httpd.apache.org/docs/current/en/mod/mod_include.html> for more
information.
parse_ssi
Provided with the html data as a string and this will parse its embedded
ssi directives and return its output as a string.
If it fails, it sets an "error" and returns an empty string.
path_info
Sets or gets the path info for the current uri.
Example:
my $string = $ssi->path_info;
$ssi->path_info( '/my/path/info' );
Sets or gets the remote ip address of the visitor.
Under Apache mod_perl, this will call "remote_ip" in Apache2::Connection
for version 2.2 or lower and will call "useragent_ip" in
Apache2::Connection for version above 2.2, and otherwise this will get
the value from the environment variable "REMOTE_ADDR"
This value can also be overriden by being provided during object
instantiation.
# Pretend the ssi directives are accessed from this ip
$ssi->remote_ip( '192.168.2.20' );
This is useful when one wants to check how the rendering will be when
accessed from certain ip addresses.
This is used primarily when there is an expression such as
<!--#if expr="-R '192.168.1.0/24' -->
Visitor is part of my private network
<!--#endif -->
or
<!--#if expr="v('REMOTE_ADDR') -R '192.168.1.0/24' -->
<!--#include file="/home/john/special_hidden_login_feature.html" -->
<!--#endif -->
Apache2::Connection also has a "remote_addr" in Apache2::Connection
method, but this returns a APR::SockAddr object that is used to get the
binary version of the ip. However you can also get the string version
like this:
use APR::SockAddr ();
my $ip = $r->connection->remote_addr->ip_get();
Versions above 2.2 make a distinction between ip from direct connection,
or the real ip behind a proxy, i.e. "useragent_ip" in
Apache2::Connection
request_uri
This is an alias for "document_uri"
server_version
Returns the server version as a version object can caches that value.
Under mod_perl2, it uses "get_server_description" in Apache2::ServerUtil
and outside of mod_perl, it tries to find "apxs" using File::Which and
in last resort, tries to find the "apache2" or "httpd" binary to get its
version information.
sizefmt
Sets or gets the formatting for file sizes. Value can be either "bytes"
or "abbrev"
timefmt
Sets or gets the formatting for date and time values. The format takes
the same values as "strftime" in POSIX
Encoding
At present time, the html data are treated as utf8 data and decoded and
encoded back as such.
If there is a need to broaden support for other charsets, let me know.
SSI Directives
This is taken from Apache documentation and summarised here for
convenience and clarity to the perl community.
config
<!--#config errmsg="Error occurred" sizefmt="abbrev" timefmt="%B %Y" -->
<!--#config errmsg="Oopsie" -->
<!--#config sizefmt="bytes" -->
# Thursday 24 December 2020
<!--#config timefmt="%A $d %B %Y" -->
echo
<!--#set var="HTMl_TITLE" value="Un sujet intéressant" -->
<!--#echo var="HTMl_TITLE" encoding="entity" -->
Encoding can be either "entity", "url" or "none"
exec
# pwd is "print working directory" in shell
<!--#exec cmd="pwd" -->
<!--#exec cgi="/uri/path/to/prog.cgi" -->
include
# Filesystem file path
<!--#include file="/home/john/var/quote_of_the_day.txt" -->
# Relative to the document root
<!--#include virtual="/footer.html" -->
flastmod
<!--#flastmod file="/home/john/var/quote_of_the_day.txt" -->
<!--#flastmod virtual="/copyright.html" -->
fsize
<!--#fsize file="/download/software-v1.2.tgz" -->
<!--#fsize virtual="/images/logo.jpg" -->
printenv
<!--#printenv -->
set
<!--#set var="debug" value="2" -->
if, elif, endif and else
<!--#if expr="$debug > 1" -->
I will print a lot of debugging
<!--#else -->
Debugging output will be reasonable
<!--#endif -->
or with new version of Apache SSI:
No such file or directory.
<!--#if expr="v('HTTP_REFERER') != ''" -->
Please let the admin of the <a href="<!--#echo encoding="url" var="HTTP_REFERER" -->"referring site</a> know about their dead link.
<!--#endif -->
( run in 1.750 second using v1.01-cache-2.11-cpan-39bf76dae61 )