MojoX::Plugin::PHP - use PHP as a templating system in Mojolicious
0.05
Keep reading.
# MyApp.pl, using Mojolicious app->plugin('MojoX::Plugin::PHP'); app->plugin('MojoX::Plugin::PHP', { php_var_preprocessor => sub { my $params = shift; ... }, php_stderr_preprocessor => sub { my $msg = shift; ... }, php_header_processor => sub { my ($field,$value,$repl) = @_; ... }, php_output_processor => sub { my ($outref, $headers, $c) = @_; ... } } ); # using Mojolicious::Lite plugin 'MojoX::Plugin::PHP'; plugin 'MojoX::Plugin::PHP', { php_var_preprocessor => sub { my $params = shift; ... }, php_stderr_preprocessor => sub { my $msg = shift; ... }, php_header_processor => sub { my ($field,$value,$repl) = @_; ... }, php_output_processor => sub { my ($outref, $headers, $c) = @_; ... } };
MojoX::Plugin::PHP establishes a PHP engine as the default handler for php files and templates in a Mojolicious application. This allows you to put a PHP template (say, called foo/bar.php under your Mojolicious application's /templates or /public directory, make a request to
php
foo/bar.php
/templates
/public
/foo/bar.php
and have a PHP interpreter process your file, and Mojolicious return a response as if it the request were processed in Apache with mod_php.
Why would anyone want to do this? Here are a couple of reasons I can think of:
to put a Mojolicious wrapper around some decent PHP application (WordPress?). Then you could use Perl and any other state of your Mojolicious application to post process output and response headers.
allow PHP developers on your project to keep prototyping in PHP, postponing the religious war about which appserver your project should use
use_index_php => boolean | undef
Describes how the before_dispatch hook should handle requests for a path that contains a file called index.php.
index.php
If use_index_php is set to a defined value, then a request like /foo/ (with a trailing slash) will be routed to /foo/index.php if /foo/index.php would resolve to a valid PHP template.
use_index_php
/foo/
/foo/index.php
If use_index_php is set to a true value, then a request like /foo (with or without a trailing slash) will be routed to /foo/index.php if /foo/index.php would resolve to a valid PHP template.
/foo
If use_index_php is not defined or set to undef, then this module will not look for an index.php file related to any request.
undef
There are four hooks in the PHP template processing engine (MojoX::Template::PHP) where you can customize or extend the behavior of the PHP engine. In the plugin configuration, you can specify the code that should be run off each of these hooks. All of these configuration are optional.
php_var_preprocessor => sub { my $params = shift; ... }
MojoX::Template::PHP gathers several variables from Perl and sets them as global variables in the PHP environment. These include the standard $_GET, $_POST, $_REQUEST, $_SERVER, $_ENV, $_COOKIE, and $_FILES variables, but also includes most of the stash variables. All of these variable values are gathered into a single hash reference. Right before all of the variables are assigned in PHP, the PHP engine will look for a php_var_preprocessor setting, and will invoke its code, passing that hash reference as an argument. In this callback, you can add, remove, or edit the set of variables that will be initialized in PHP.
$_GET
$_POST
$_REQUEST
$_SERVER
$_ENV
$_COOKIE
$_FILES
php_var_preprocessor
php_stderr_processor => sub { my $msg = shift; ... }
When the PHP interpreter writes a message to its standard error stream, a callback specified by the php_stderr_processor config setting can be called with the text that PHP was trying to write to that stream. You can use this callback to log warnings and errors from PHP.
php_stderr_processor
php_header_processor => sub { my ($field,$value,$replace) = @_; ... return $keep_header; }
When the PHP header() function is invoked in the PHP interpreter, a callback specified by the php_header_processor config setting can be called with the name and value of the header. If this callback returns a true value (or if there is no callback), the header from PHP will be included in the Mojolicious response headers. If this callback returns a false value, the header will not be returned with the Mojolicious response.
header()
php_header_processor
One powerful use of the header callback is as a communication channel between PHP and Perl. For example, the header processor can look for a specific header field. When it sees this header, the value can be a JSON-encoded payload which can be processed in Perl. Perl can return the results of the processing through a global PHP variable (again, possibly JSON encoded). The t/10-headers.t test case in this distribution has a proof-of-concept of this kind of use of the header callback.
t/10-headers.t
php_output_postprocessor => sub { my ($output_ref, $headers, $c) = @_; ... }
When the PHP engine has finished processing a PHP template, and a callback has been specified with the php_output_postprocessor config setting, then that callback will be invoked with a reference to the PHP output, the set of headers returned by PHP (probably in a Mojo::Headers object), and the current controller/context object. You can use this callback for postprocessing the output or the set of headers that will be included in the Mojolicious response.
php_output_postprocessor
One thing that you might want to do in the output post-processing is to look for a Location: ... header, and determine if you want the application to follow it.
Location: ...
$plugin->register(Mojolicious->new);
Register the php renderer in Mojolicious application.
As mentioned in the "php_header_processor" documentation in the CONFIG section above, it is possible to use the header callback mechanism to execute arbitrary Perl code from PHP and to establish a communication channel between your PHP scripts and your Mojolicious application.
Let's demonstrate with a simple example:
The Collatz conjecture states that the following algorithm:
Take any natural number n . If n is even, divide it by 2. If n is odd, multiply it by 3 and add 1 so the result is 3n + 1 . Repeat the process until you reach the number 1.
will always terminate in a finite number of steps.
Suppose we are interested in finding out, for a given numner n, how many steps of this algorithm are required to reach the number 1. We'll make a request to a path like:
collatz.php?n=n
collatz.php?n=
and return the number of steps in the response. Our collatz.php template looks like:
collatz.php
<?php $nsteps = 0; $n = $_GET['n']; while ($n > 1) { if ($n % 2 == 0) { $n = divide_by_two($n); } else { $n = triple_plus_one($n); } $nsteps++; } function divide_by_two($x) { return $x / 2; } function triple_plus_one($x) { ... } ?> number of Collatz steps is <?php echo $nsteps; ?>
and we will implement the triple_plus_one function in Perl.
triple_plus_one
The configuration for MojoX::Plugin::PHP can specify a callback function that will be invoked when PHP sends a response header. To use this channel to perform work in PHP, we need
MojoX::Plugin::PHP
PHP::assign_global
In the Mojolicious application, we intercept a header of the form X-collatz:payload where payload is the JSON-encoding of a hash that defines n, the number to operate on, and result, the name of the PHP variable to publish the results to.
X-collatz:
n
result
JSON-encoding the header value is a convenient way to pass complicated, arbitrary data from PHP to Perl, including binary data or strings with newlines. For complex results, it is also convenient to assign a JSON-encoded value to a single PHP global variable.
... use Mojo::JSON; ... app->plugin('MojoX::Plugin::PHP', { php_header_processor => \&my_header_processor }; sub my_header_processor { my ($field,$value,$replace) = @_; if ($field eq 'X-collatz') { my $payload = Mojo::JSON::decode_json($value); my $n = $payload->{n}; my $result_var = $payload->{result}; $n = 3 * $n + 1; PHP::assign_global( $result_var, $n ); return 0; # don't include this header in response } return 1; # do include this header in response } ...
The PHP code merely has to set a response header that looks like X-collatz:payload where payload is a JSON-encoded associative array with the number to operate on the variable to receive the results in. Then it must read the result out of that variable.
... function triple_plus_one($x) { global $collatz_result; $payload = encode_json( // requires php >=v5.2.0 array( "n" => $x, "result" => "collatz_result") ); header("X-collatz: $payload"); return $collatz_result; }
Now we can not only run PHP scripts in Mojolicious, our PHP templates can execute code in Perl.
$ perl our_app.pl get /collatz.php?n=5 number of Collatz steps is 5 $ perl our_app.pl get /collatz.php?n=42 number of Collatz steps is 8
Other ways you might use this feature include:
have PHP execute functions or use modules that are hard to implement in Perl or only available in Perl
have PHP manipulate data in your app's Perl model
perform authentication or other function in PHP that changes the state on the Perl side of your application
MojoX::Template::PHP, Mojolicious::Plugin::EPRenderer, Mojolicious::Plugin::EPLRenderer, Catalyst::View::Template::PHP, PHP, PHP::Interpreter.
Marty O'Brien <mob@cpan.org>
Copyright 2013-2015, Marty O'Brien. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Sortware Foundation; or the Artistic License.
See http://dev.perl.org/licenses for more information.
To install MojoX::Plugin::PHP, copy and paste the appropriate command in to your terminal.
cpanm
cpanm MojoX::Plugin::PHP
CPAN shell
perl -MCPAN -e shell install MojoX::Plugin::PHP
For more information on module installation, please visit the detailed CPAN module installation guide.