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>

VERSION

v0.2.0

DESCRIPTION

Apache2::SSI implements Apache Server Side Include, a.k.a. SSI, within and outside of Apache2/mod_perl2 framework.

Apache2::SSI is inspired from the original work of Apache::SSI with the main difference that Apache2::SSI works well when called from within Apache mod_perl2 as well as when called outside of Apache if you want to simulate SSI.

Apache2::SSI also implements all of Apache SSI features, including functions, encoding and decoding and old style variables such as ${QUERY_STRING} as well as modern style such as v('QUERY_STRING') and variants such as %{REQUEST_URI}.

See below details in this documentation and in the section on "SSI Directives"

Under Apache mod_perl, you would implement it like this in your apache2.conf or httpd.conf

<Files *.phtml>
    SetHandler modperl
    PerlOutputFilterHandler Apache2::SSI
</Files>

This would enable Apache2::SSI for files whose extension is .phtml. You can also limit this by location, such as:

<Location /some/web/path>
    <Files *.html>
        SetHandler modperl
        PerlOutputFilterHandler Apache2::SSI
    </Files>
</Location>

In the example above, we enable it in files with extensions .phtml, but you can, of course, enable it for all html by setting extension .html or whatever extension you use for your html files.

As pointed out by Ken Williams, the original author of Apache::SSI, the benefit for using Apache2::SSI is:

1. You want to subclass Apache2::SSI and have granular control on how to render ssi
2. You want to "parse the output of other mod_perl handlers, or send the SSI output through another handler"
3. You want to imitate SSI without activating them or without using Apache (such as in command line) or within your perl/cgi script

INSTALLATION

perl Makefile.PL
make
make test
sudo make install

This will detect if you have Apache installed and run the Apache mod_perl2 tests by starting a separate instance of Apache on a non-standard port like 8123 under your username just for the purpose of testing. This is all handled automatically by Apache::Test

If you do not have Apache or mod_perl installed, it will still install, but obviously not start an instance of Apache/mod_perl, nor perform any of the Apache mod_perl tests.

It tries hard to find the Apache configuration file. You can help it by providing command line modifiers, such as:

perl Makefile.PL -apxs /usr/bin/apxs

or, even specify the Apache configuration file:

perl Makefile.PL -apxs /usr/bin/apxs -httpd_conf /home/john/etc/apache2/apache2.conf

To run only some tests, for example:

make test TEST_FILES="./t/31.file.t"

If you are on a Linux type system, you can install apxs by issuing on the command line:

apt install apache2-dev

You can check if you have it installed with the following command:

dpkg -l | grep apache

See ExtUtils::MakeMaker for more information.

METHODS

new

This instantiate an object that is used to access other key methods. It takes the following parameters:

apache_filter

This is the Apache2::Filter object object that is provided if running under mod_perl.

apache_request

This is the Apache2::RequestRec object that is provided if running under mod_perl.

it can be retrieved from "request" in Apache2::RequestUtil or via "r" in Apache2::Filter

You can get this Apache2::RequestRec object by requiring Apache2::RequestUtil and calling its class method "request" in Apache2::RequestUtil such as Apache2::RequestUtil->request and assuming you have set PerlOptions +GlobalRequest in your Apache Virtual Host configuration.

Note that there is a main request object and subprocess request object, so to find out which one you are dealing with, use "is_initial_req" in Apache2::RequestUtil, such as:

use Apache2::RequestUtil (); # extends Apache2::RequestRec objects
my $r = $r->is_initial_req ? $r : $r->main;
debug

Sets the debug level. Starting from 3, this will output on the STDERR or in Apache error log a lot of debugging output.

document_root

This is only necessary to be provided if this is not running under Apache mod_perl. Without this value, Apache2::SSI has no way to guess the document root and will not be able to function properly and will return an "error".

document_uri

This is only necessary to be provided if this is not running under Apache mod_perl. This must be the uri of the document being served, such as /my/path/index.html. So, if you are using this outside of the rim of Apache mod_perl and your file resides, for example, at /home/john/www/my/path/index.html and your document root is /home/john/www, then the document uri would be /my/path/index.html

errmsg

The error message to be returned when a ssi directive fails. By default, it is [an error occurred while processing this directive]

html

The html data to be parsed. You do not have to provide that value now. You can provide it to "parse" as its first argument when you call it.

legacy

Takes a boolean value suchas 1 or 0 to indicate whether the Apache2 expression supported accepts legacy style.

Legacy Apache expression typically allows for perl style variable ${REQUEST_URI} versus the modern style of %{REQUEST_URI} and just an equal sign to imply a regular expression such as:

$HTTP_COOKIES = /lang\%22\%3A\%22([a-zA-Z]+\-[a-zA-Z]+)\%22\%7D;?/

Modern expression equivalent would be:

%{HTTP_COOKIES} =~ /lang\%22\%3A\%22([a-zA-Z]+\-[a-zA-Z]+)\%22\%7D;?/

See Regexp::Common::Apache2 for more information.

See also the property trunk to enable experimental expressions.

remote_ip

This is used when you want to artificially set the remote ip address, i.e. the address of the visitor accessing the page. This is used essentially by the SSI directive:

my $ssi = Apache2::SSI->new( remote_ip => '192.168.2.10' ) ||
    die( Apache2::SSI->error );

<!--#if expr="-R '192.168.2.0/24' || -R '127.0.0.1/24'" -->
Remote ip is part of my private network
<!--#else -->
Go away!
<!--#endif -->
sizefmt

The default way to format a file size. By default, this is abbrev, which means a human readable format such as 2.5M for 2.5 megabytes. Other possible value is bytes which would have the fsize ssi directive return the size in bytes.

See Apache2 documentation for more information on this.

timefmt

The default way to format a date time. By default, this uses the display according to your locale, such as ja_JP (for Japan) or en_GB for the United Kingdoms. The time zone can be specified in the format, or it will be set to the local time zone, whatever it is.

See Apache2 documentation for more information on this.

trunk

This takes a boolean value such as 0 or 1 and when enabled this allows the support for Apache2 experimental expressions.

See Regexp::Common::Apache2 for more information.

Also, see the property legacy to enable legacy Apache2 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 &Atilde;&ordf;tres humains naissent libres et &Atilde;&copy;gaux en dignit&Atilde;&copy; 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 &Atilde;&ordf;tres humains naissent libres et &Atilde;&copy;gaux en dignit&Atilde;&copy; et en droits.

encode_uri

Encode uri data. This uses "uri_escape" in URI::Escape::XS.

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 statement, even though no error had occurred.

filename

This is an alias for "filename" in Apache2::SSI::URI

find_file

Provided with a file path, and this will resolve any variable used and attempt to look it up as a file if the argument file is provided with a file path as a value, or as a URI if the argument virtual is provided as an argument.

This will call "lookup_file" or "lookup_uri" depending on whether it is dealing with a file or an uri.

It returns a Apache2::SSI::URI object which is stringifyable and contain the file path.

finfo

Returns a Apache2::SSI::Finfo object. This provides access to "stat" in perlfunc information as method, taking advantage of APR::Finfo when running under Apache, and File::stat-like interface otherwise. See Apache2::SSI::Finfo for more information.

html

Sets or gets the html data to be processed.

lookup_file

Provided with a file path and this will look up the file.

When using Apache, this will call "lookup_file" in Apache2::SubRequest. Outside of Apache, this will mimick Apache's lookup_file method by searching the file relative to the directory of the current document being served, i.e. the "document_uri".

As per Apache SSI documentation, you cannot specify a path starting with / or ../

It returns a Apache2::SSI::File object.

lookup_uri

Provided with an uri, and this will loo it up and return a Apache2::SSI::URI object.

Under Apache mod_perl, this uses "lookup_uri" in Apache2::SubRequest to achieve that. Outside of Apache it will attempt to lookup the uri relative to the document root if it is an absolute uri or to the current document uri.

It returns a Apache2::SSI::URI object.

mod_perl

Returns true when running under mod_perl, false otherwise.

parse

Provided with html data and if none is provided will use the data specified with the method "html", this method will parse the html and process the ssi directives.

It returns the html string with the ssi result.

parse_config

Provided with an hash reference of parameters and this sets three of the object parameters that can also be set during object instantiation:

echomsg

The value is a message that is sent back to the client if the echo element attempts to echo an undefined variable.

This overrides any default value set for the parameter echomsg upon object instantiation.

errmsg

This is the default error message to be used as the result for a faulty ssi directive.

See the "echomsg" method.

sizefmt

This is the format to be used to format the files size. Value can be either bytes or abbrev

See also the "sizefmt" method.

timefmt

This is the format to be used to format the dates and times. The value is a date formatting based on "strftime" in POSIX

See also the "timefmt" method.

parse_echo

Provided with an hash reference of parameter and this process the echo ssi directive and returns its output as a string.

For example:

Query string passed: <!--#echo var="QUERY_STRING" -->

There are a number of standard environment variable accessible under SSI on top of other environment variables set. See "SSI Directives" section below.

parse_echo_date_gmt

Returns the current date with time zone set to gmt and based on the provided format or the format available for the current locale such as ja_JP or en_GB.

parse_echo_date_local

Returns the current date with time zone set to the local time zone whatever that may be and on the provided format or the format available for the current locale such as ja_JP or en_GB.

Example:

<!--#echo var="DATE_LOCAL" -->

parse_echo_document_name

Returns the document name. Under Apache, this returns the environment variable DOCUMENT_NAME, if set, or the base name of the value returned by "filename" in Apache2::RequestRec

Outside of Apache, this returns the environment variable DOCUMENT_NAME, if set, or the base name of the value for "document_uri"

Example:

<!--#echo var="DOCUMENT_NAME" -->

If the uri were /some/where/file.html, this would return only file.html

parse_echo_document_uri

Returns the value of "document_uri"

Example:

<!--#echo var="DOCUMENT_URI" -->

The document uri would include, if any, any path info and query string.

parse_echo_last_modified

This returns document last modified date. Under Apache, there is a standard environment variable called LAST_MODIFIED (see the section on "SSI Directives"), and if somehow absent, it will return instead the formatted last modification datetime for the file returned with "filename" in Apache2::RequestRec. The formatting of that date follows whatever format provided with "timefmt" or by default the datetime format for the current locale (e.g. ja_JP).

Outside of Apache, the similar result is achieved by returning the value of the environment variable LAST_MODIFIED if available, or the formatted datetime of the document uri as set with "document_uri"

Example:

<!--#echo var="LAST_MODIFIED" -->

parse_eval_expr

Provided with a string representing an Apache2 expression and this will parse it, transform it into a perl equivalent and return its value.

It does the parsing using "parse" in Apache2::Expression called from "parse_expr"

If the expression contains regular expression with capture groups, the value of capture groups will be stored and will be usable in later expressions, such as:

<!--#config errmsg="[Include error]" -->
<!--#if expr="%{HTTP_COOKIE} =~ /lang\%22\%3A\%22([a-zA-Z]+\-[a-zA-Z]+)\%22\%7D;?/"-->
    <!--#set var="CONTENT_LANGUAGE" value="%{tolower:$1}"-->
<!--#elif expr="-z %{CONTENT_LANGUAGE}"-->
    <!--#set var="CONTENT_LANGUAGE" value="en"-->
<!--#endif-->
<!DOCTYPE html>
<html lang="<!--#echo encoding="none" var="CONTENT_LANGUAGE" -->">

parse_exec

Provided with an hash reference of parameters and this process the exec ssi directives.

Example:

<!--#exec cgi="/uri/path/to/progr.cgi" -->

or

<!--#exec cmd="/some/system/file/path.sh" -->

parse_expr

It takes a string representing an Apache2 expression and calls "parse" in Apache2::Expression to break it down, and then calls "ap2perl_expr" to transform it into a perl expression that is then eval'ed by "parse_eval_expr".

It returns the perl representation of the Apache2 expression.

To make this work, certain Apache2 standard functions used such as base64 or md5 are converted to use this package function equivalents. See the parse_func_* methods for more information.

parse_elif

Parse the elif condition.

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 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_replace

replace(string, "from", "to") replaces all occurrences of "from" in the string with "to".

Example:

<!--#if expr="replace( 'John is in Tokyo', 'John', 'Jack' ) == 'Jack is in Tokyo'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->

parse_func_req

See "parse_func_http"

parse_func_reqenv

Lookup request environment variable (as a shortcut, v can also be used to access variables).

This is only different from "parse_func_env" under Apache.

See "parse_func_env"

Example:

<!--#if expr="reqenv('ProcessId') == '$$'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->

Or using the Apache SSI v shortcut:

<!--#if expr="v('ProcessId') == '$$'" -->

parse_func_req_novary

Same as "parse_func_req", but header names will not be added to the Vary header.

parse_func_resp

Get HTTP response header.

Example:

<!--#if expr="resp('X-ProcessId') == '$$'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->

An important note here:

First, there is obviously no response header available for perl scripts running outside of Apache2/mod_perl2 framework.

If the script runs under mod_perl, not all response header will be available depending on whether you are using Apache2::SSI in your Apache configuration as an output filter handler (PerlOutputFilterHandler) or a response handler (PerlResponseHandler).

If it is running as an output filter handler, then some headers, such as Content-Type will not be available, unless they have been set by a script in a previous phase. Only basic headers will be available. For more information, check the Apache/mod_perl2 documentation on each phase.

parse_func_sha1

Hash the string using SHA1, then encode the hash with hexadecimal encoding.

Example:

<!--#if expr="sha1('Tous les êtres humains naissent libres et égaux en dignité et en droits.') == '8c244078c64a51e8924ecf646df968094a818d59'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#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 &Atilde;&ordf;tres humains naissent libres et &Atilde;&copy;gaux en dignit&Atilde;&copy; et en droits." encoding="urlencoded" -->

See the Apache SSI documentation 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' );

The path info value is also set automatically when "document_uri" is called, such as:

$ssi->document_uri( '/some/path/to/file.html/my/path/info?q=something&l=ja_JP' );

This will also set automatically the PATH_INFO environment variable.

query_string

Set or gets the query string for the current uri.

Example:

my $string = $ssi->query_string;
$ssi->query_string( 'q=something&l=ja_JP' );

or, using the URI module:

$ssi->query_string( $uri->query );

The query string value is set automatically when you provide an document_uri upon instantiation or after:

$ssi->document_uri( '/some/path/to/file.html?q=something&l=ja_JP' );

This will also set automatically the QUERY_STRING environment variable.

remote_ip

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 -->

functions

Apache SSI supports the following functions, as of Apache version 2.4.

See Apache documentation for detailed description of what they do.

You can also refer to the methods parse_func_* documented above, which implement those Apache functions.

base64
env
escape
http
ldap
md5
note
osenv
replace
req
reqenv
req_novary
resp
sha1
tolower
toupper
unbase64
unescape

variables

On top of all environment variables available, Apache makes the following ones also accessible:

DATE_GMT
DATE_LOCAL
DOCUMENT_ARGS
DOCUMENT_NAME
DOCUMENT_PATH_INFO
DOCUMENT_URI
LAST_MODIFIED
QUERY_STRING_UNESCAPED
USER_NAME

See Apache documentation and this page too for more information.

expressions

There is reasonable, but limited support for Apache expressions. For example, the followings are supported

In the examples below, we use the variable QUERY_STRING, but you can use any other variable of course.

The regular expression are the ones PCRE compliant, so your perl regular expressions should work.

<!--#if expr="$QUERY_STRING = 'something'" -->
<!--#if expr="v('QUERY_STRING') = 'something'" -->
<!--#if expr="%{QUERY_STRING} = 'something'" -->
<!--#if expr="$QUERY_STRING = /^something/" -->
<!--#if expr="$QUERY_STRING == /^something/" -->
# works also with eq, ne, lt, le, gt and ge
<!--#if expr="9 gt 3" -->
<!--#if expr="9 -gt 3" -->
# Other operators work too, namely == != < <= > >= =~ !~
<!--#if expr="9 > 3" -->
<!--#if expr="9 !> 3" -->
<!--#if expr="9 !gt 3" -->
# Checks the remote ip is part of this subnet
<!--#if expr="-R 192.168.2.0/24" -->
<!--#if expr="192.168.2.10 -R 192.168.2.0/24" -->
<!--#if expr="192.168.2.10 -ipmatch 192.168.2.0/24" -->
# Checks if variable is non-empty
<!--#if expr="-n $some_variable" -->
# Checks if variable is empty
<!--#if expr="-z $some_variable" -->
# Checks if the visitor can access the uri /restricted/uri
<!--#if expr="-A /restricted/uri" -->

For subnet checks, this uses Net::Subnet

Expressions that would not work outside of Apache, i.e. it will return an empty string:

<!--#expr="%{HTTP:X-example-header} in { 'foo', 'bar', 'baz' }" -->

See Apache documentation for more information.

CREDITS

Credits to Ken Williams for his implementation of Apache::SSI from which I borrowed some code.

AUTHOR

Jacques Deguest <jack@deguest.jp>

CPAN ID: jdeguest

Lhttps://gitlab.com/jackdeguest/Apache2-SSI>

SEE ALSO

Apache2::SSI::File, Apache2::SSI::Finfo, Apache2::SSI::Notes, Apache2::SSI::URI, Apache2::SSI::SharedMem and Apache2::SSI::SemStat

mod_include, mod_perl(3), Apache::SSI, https://httpd.apache.org/docs/current/en/mod/mod_include.html, https://httpd.apache.org/docs/current/en/howto/ssi.html, https://httpd.apache.org/docs/current/en/expr.html https://perl.apache.org/docs/2.0/user/handlers/filters.html#C_PerlOutputFilterHandler_

COPYRIGHT & LICENSE

Copyright (c) 2020-2021 DEGUEST Pte. Ltd.

You can use, copy, modify and redistribute this package and associated files under the same terms as Perl itself.