<!DOCTYPE html>
<html>
<head>
<title>PHP: Hypertext Processor: WASD</title>

<style type="text/css">
body { margin:1em; font-family:arial,helvetica,sans-serif; }

h1 {
  font-size:150%; font-weight:bold; text-decoration:underline;
}

h2 {
  font-size:130%; font-weight:bold; text-decoration:underline;
  letter-spacing:1px;
  padding-top:1.2em;
}

h3 {
  font-size:120%; font-weight:bold;
  padding-top:0.8em;
}

blockquote { font-size:100%; }

tt { font-family:courier,monospace; padding:0 4px 0 4px; }

hr { color:#888888; background-color:#888888; height:1px; border:0; }

.phprte {
  font-size:110%; letter-spacing:-1px; padding:0 1px 0 1px;
}

.code {
  font-family:courier,monospace;
  border-style:solid; border-color:#888888; border-left-width:1px;
  border-top-width:0; border-right-width:0; border-bottom-width:0;
  background-color:#eeeeee;
  margin-left:2em;
  margin-right:5em;
  padding:0.3em;
  padding-left:1em;
}

pre {
  margin-left:2em;
  margin-right:5em;
  padding:0.3em;
  padding-left:1em;
}

.quote {
  border-style:dotted; border-color:#888888; border-width:1px;
  font-size:90%;
  background-color:#eeeeee;
  margin-left:2em;
  margin-right:5em;
  padding:0.3em;
  padding-left:1em;
}

.refer {
  font-size:90%; width:90%; text-align:right;
}

.refer {
  font-size:90%; width:90%; text-align:right;
}

.which table, .which th, .which td {
  border-collapse:collapse;
  border-style:solid;
  border-width:1px;
  border-color:#888888; 
  background-color:#eeeeee;
  padding:5px; margin:0;
  font-size:90%;
  vertical-align:top;
}
.which th {
   font-weight: bold;
}
@media screen { a[target=_blank]::after { font-size:80%; content:"\2924"; } }
</style>

</head>
<body bgcolor="#ffffff" text="#000000" link="#0000cc" vlink="#0000cc">

<center>

<h1>PHP: Run-Time Environment for WASD</h1>
<h3>Version 2.0.0, 1st October 2024</h3>

<p><b>Copyright &copy; 2002-2024 Mark G. Daniel</b>
<br>This program, comes with ABSOLUTELY NO WARRANTY.
<br>This is free software, and you are welcome to redistribute it...
</center>

<div style="display:block;text-align:center;padding-left:2em;">
<pre style="display:inline-block;text-align:left;">
--------------------------------------------------------------------
                   The PHP License, version 3.01
    Copyright (c) 1999 - 2019 The PHP Group. All rights reserved.
--------------------------------------------------------------------

Redistribution and use in source and binary forms, with or without
modification, is permitted provided that the following conditions
are met:

  1. Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

  <i>8&lt; snip 8&lt;</i>
</pre>
</div>

<center>
<a target="_blank"
href="https://www.php.net/license/3_01.txt">
https://www.php.net/license/3_01.txt</a>
</center>

<h2 style="margin-left:1.5em;">Contents</h2>

<ul>
<li><a href="#Prehistory">Prehistory</a> </li>
<li><a href="#Installation">Installation</a> </li>
<li><a href="#Configure_WASD">Configure WASD</a> </li>
<li><a href="#Configure_PHP">Configure PHP</a> </li>
<li><a href="#Example_Scripts">Example Scripts</a> </li>
<li><a href="#Performance">Performance</a> </li>
<li><a href="#DCLsymbol">DCLsymbol Extension</a> </li>
<li><a href="#MB_Installation">Mark Berryman PHP</a> </li>
<li><a href="#Problems">Problems?</a> </li>
<li><a href="#Releases">Releases</a> </li>
<li><a href="#Acknowlegements">Acknowlegements</a> </li>
</ul>

<br><hr align="left" size="1" noshade><br>

<p> This is an interface to a PHP interpreter engine and environment for the
WASD OpenVMS Web server. It is designed to be able to be used in standard
CGI and CGIplus/RTE persistent scripting modes.  The persistent modes provide
substantial improvement in script activation times and reduced load on server
and system. <span class="phprte">phpRTE</span> cannot be used interactively or
at the command line, it is only for scripting use.

<p> This version 2 of <span class="phprte">phpRTE</span> has been tailored to
the <a target="_blank" href="https://vmssoftware.com/">VMS Software</a>
<i>official</i> PHP releases, version 8 and later.

<blockquote>
<a target="_blank" href="https://vmssoftware.com/products/php/">
https://vmssoftware.com/products/php/</a>
</blockquote>

<p> Where previous <span class="phprte">phpRTE</span> versions have been installed it is <i>strongly</i>
suggested the existing <span class="phprte">phpRTE</span> kit be renamed out of
the way  (as described in step 2 below) before installing this kit so there can
be no interactions between kit contents. After successful installation and
testing the previous directory trees may be deleted.

<p> The WASD kit supplies the RTE source code, build procedure, some elementary
scripts, and this document &mdash; the WASD  <i>infrastructure</i>.  Optional
object code kits are available for those for whom compilation is not an option.

<a name="Prehistory">
<h2><span class="phprte">phpRTE</span> prehistory</h2>
</a>

<p> If your site has not previously used <u>PHPWASD</u> kits this is only of
historical interest.
<br> If you have used kits preceding v2.0.0 (PHPRTE) this <i>may</i> concern
you.  Read on &hellip;

<p> WASD's PHP history goes back to the early <i>noughties</i> (and here we are
a quarter through 21st century).  WASD PHP originated with a CSWS (HP) release. 
To allow WASD to use the CSWS kit without having CSWS installed, portions of the
CSWS kit were extracted into the WASD tree at <tt>WASD_ROOT:[PHP]</tt>.  The
WASD PHP RTE kit was installed at <tt>WASD_ROOT:[SRC.PHP]</tt>.

<p> Ten years following the initial release,
<a href="#MB_Installation">Mark Berryman</a> PHP releases
were <b>so in advance</b> of the HP releases that WASD PHP began to use those
as a default.  To ease that transition and not to disturb current WASD PHP
sites the MB files were located in the same <tt>WASD_ROOT:[PHP]</tt> directory
as the original HP CSWS files.  And so it remained for a further ten years. 
Then two decades on, VSI entered the scene with a vendor release.

<p> As a vendor release, VSI was at liberty to integrate the kit within the O/S
disk structure and use the dollar symbol (<tt>$</tt>) without unsettling anyone.

<pre class="code">
(LNM$SYSTEM_TABLE)

  "PHP$ROOT" = "X86VMS$DKA0:[SYS0.SYSCOMMON.PHP.]"
  "PHP$SHR" = "PHP$ROOT:[LIB]PHP$SHR.EXE"

Directory SYS$COMMON:[000000]

php.DIR;1             0.50KB  30-JUL-2024 14:58:37.88

Directory SYS$SYSROOT:[SYS$STARTUP]

PHP$STARTUP.COM;1     0.50KB  30-JUL-2024 14:58:51.76
</pre>

<p> This was an opportunity for WASD to alter direction with its PHP support,
using the vendor environment, simplifying the WASD support.  Objectives
within the change were to allow the revised environment to coexist with the
previous, and to allow the MB releases to continue to be used as a site
preference.  The new(ish) <span class="phprte">phpRTE</span> is distinct from
the historical PHPWASD environment, so to <b>avoid confusion</b> either remove
any existing environment (<tt>WASD_ROOT:[PHP]</tt>,
<tt>WASD_ROOT:[SRC.PHP]</tt> and any <tt>CGI-BIN:[000000]PHPWASD.EXE</tt>)
or <b>be aware of the overlap</b> and follow the <span class="phprte">phpRTE</span>
installation instructions closely.

<a name="Installation">
<h2>Installation</h2>
</a>

<ol>

<li> If PHP for OpenVMS is not currently installed, or if the version is not
up-to-date, obtain the latest kit from

<blockquote>
<a target="_blank"
href="https://vmssoftware.com/products/php/">https://vmssoftware.com/products/php/</a>
</blockquote>

and install according to the instructions available.

<p><li> Obtain the <span class="phprte">phpRTE</span> kit(s) from
<blockquote>
<a target="_blank" href="http://wasd.vsm.com.au/wasd/">http://wasd.vsm.com.au/wasd/</a>
</blockquote>

<li> It is suggested that any existing <span class="phprte">phpRTE</span> kit be renamed out of the way
before installing this kit so there can be no interactions between kit
contents.  After successful installation the previous directories may be
deleted.

<pre class="code">
$ RENAME WASD_ROOT:[000000]PHPRTE.DIR WASD_ROOT:[000000]PHPRTE_<i>nnn</i>.DIR
</pre>

<p><li> UNZIP the <span class="phprte">phpRTE</span> archive and optional
object modules

<pre class="code">
$ SET DEFAULT WASD_ROOT:[000000]
$ UNZIP <i>location:</i>PHPRTE200.ZIP
$ UNZIP <i>location:</i>PHPRTE200-<i>arch</i>.ZIP
</pre>

<p><li> Install the WASD infrastructure and PHP engine
<pre class="code">
$ SET DEFAULT WASD_ROOT:[SRC.PHPRTE]
$ @BUILD_PHPRTE [BUILD|LINK]
$ COPY WASD_EXE:PHPRTE.EXE CGI_EXE:
$ COPY PHPRTE.COM CGI_BIN:
</pre>

<p><li>
<a href="#Configure_WASD">Configure</a> the Web server

<p><li>
<a href="#Configure_PHP">Configure</a> the PHP environment

<p><li> Start scripting &nbsp;:^)&nbsp;
Try the <a href="#Example_Scripts">example scripts</a>. </p>

<pre class="code">
$ COPY WASD_ROOT:[SRC.<span class="phprte">phpRTE</span>.SCRIPTS]*.PHP CGI_BIN:
</pre>

<p><li> Also see <a href="#MB_Installation">Mark Berryman PHP</a> </li>

</ol>

<a name="Configure_WASD">
<h2>Configure WASD</h2>
</a>

<p> There are various ways to employ the WASD PHP interpreter. It can be
used in vanilla CGI mode (not recommended), or in persistent CGIplus/RTE mode.
Benchmarking indicates the CGIplus/RTE use reduces activation time to 10% of
CGI (yes, an order of magnitude). There are subtle differences in the way
CGIplus and RTE parse and provide the PATH_INFO data. See the "WASD Scripting"
document for more detail.

<h3>Configuration and Mapping</h3>

<p> One or more of the following approaches can be implemented.

<ul>

<li> Server global configuration (WASD_CONFIG_GLOBAL) can be used to indicate
to directory listings and file access the role of the file and its
content-type.

<pre class="code">
# WASD_CONFIG_GLOBAL
[AddType]
.INI   text/plain  initialization file
.PHP   text/plain  PHP source
.PHPS  text/plain  PHP source
.PHTML text/plain  PHP source
</pre>

<p> Server global configuration may also be used to activate the CGI PHP
engine (not recommended).
<br><b>Do not mix CGI and RTE configurations (below). Choose one or the
other.</b>

<pre class="code">
# WASD_CONFIG_GLOBAL
[DclScriptRunTime]
.PHP $PHP_ROOT:[000000]PHP_CGI.EXE
</pre>

<p><li> The following rule requires the PHP script files to be located in
the site administrator controlled /cgi-bin/ path. This may be changed
using appropriate rules.

<pre class="code">
# WASD_CONFIG_MAP
exec+ /cgi-bin/*.php* (@cgi-bin:[000000]phprte.com)/cgi-bin/*.php* \
      script=query=relaxed
</pre>

<p><li> The following rule would allow <tt>.php</tt> type files anywhere in the
mapped directory structure to be executed. Deploy with caution as this allows
<b>any</b> PHP script in the tree to be activated. PHP <i>applications</i>
often require this approach to mapping.  See <a href="#PHP_Applications">PHP
Applications</a> for further comment. The <i>script=as=</i> is optional but it
is often recommended to run applications in a dedicated account separate to the
rest of the server environment.  Note immediately following the <i>exec</i>
rule is a <i>pass</i> rule providing access to all the non-PHP resources (style
sheets, icons, images, etc.) often associated with an application.

<pre class="code">
# WASD_CONFIG_MAP
exec+ /app/**.php* (@cgi-bin:[000000]phprte.com)/app_root/*.php* \
      script=query=relaxed map=once ods=5 script=as=APP_ACCOUNT
pass /app/* /app_root/*
</pre>

</ul>

<h3><a name="PHP_Applications"></a>PHP Applications</h3>

<p> A PHP <i>application</i> is a package of PHP scripts and associated
resources such as style-sheets, icons and other non-script files, in a single
directory tree, often with various elements collected together, such as icons
and scripts, but sometimes with multiple instances of these or with them
interspersed amongst each other.  That is, as a complex mix of file purposes.

<p> The following rule allows <tt>.php</tt> type files anywhere in the
application tree to be executed. Deploy exercising due diligence. The
<i>script=as=</i> is optional but the recommended approach for the
reasons provided above.  Note immediately following the <i>exec</i> rule is a
<i>pass</i> rule providing access to all the non-script resources associated
with the application. 

<pre class="code">
# WASD_CONFIG_MAP
exec+ /app/**.php* (@cgi-bin:[000000]phprte.com)/app_root/*.php* \
      script=query=relaxed map=once ods=5 script=as=APP_ACCOUNT
pass /app/* /app_root/*
</pre>

<p> The WASD serving model uses two independent accounts, one for more
static resources and the other for overtly dynamic content, that is scripts,
and is considered the minimum best practise from a security perspective.  A
breach in the scripting environment has less chance to compromise or damage the
server core, and vice versa.  Better practise is an account for every major
processing system (web-based application) handled by the server.  In either
case the multiple accounts needing to access the application tree potentially
complicates the file protection requirements.

<p> With an interpreter such as PHP, the scripting engine, and therefore the
scripting account, requires only <i>read</i> access to the source files and
directories.  If the application additionally needs to write into some portion
of the file-system then of course this needs to be carefully considered and
implemented.  At the very least the server account requires read access to the
directories so that the script may be located before activating the scripting
engine.  If the application tree contains non-script resources to be served
then they also require read access for the server account.

<p> There are three basic approaches.  The examples are illustrative only.

<ol>

<li> Other considerations ignored, the simplest is to make the directory tree
WORLD READ (with or without propagation ACL).

<pre class="code">
APP.DIR;1             0.50KB    1-FEB-2014 05:16  [SYSTEM]
  (RWED,RWED,R,R)
          (DEFAULT_PROTECTION,SYSTEM:RWED,OWNER:RWED,GROUP:R,WORLD:R)
</pre>

<pre class="code">
EXAMPLE.PHP;1            1KB    1-FEB-2014 05:16  [SYSTEM]
  (RWED,RWED,R,R)
</pre>

<li> The second involves an ACL that provides access to the specific accounts
involved in serving up the application (this is the WASD model).

<pre class="code">
APP.DIR;1             0.50KB    1-FEB-2014 05:16  [SYSTEM]
        (RWED,RWED,,)
          (IDENTIFIER=WASD_HTTP_SERVER,ACCESS=READ)
          (IDENTIFIER=WASD_HTTP_NOBODY,ACCESS=READ)
          (IDENTIFIER=*,ACCESS=NONE)
          (IDENTIFIER=WASD_HTTP_NOBODY,OPTIONS=DEFAULT,ACCESS=READ)
          (IDENTIFIER=*,OPTIONS=DEFAULT,ACCESS=NONE)
          (DEFAULT_PROTECTION,SYSTEM:RWED,OWNER:RWED,GROUP:,WORLD:)
</pre>

<pre class="code">
EXAMPLE.PHP;1            1KB    1-FEB-2014 05:16  [SYSTEM]
        (RWED,RWED,,)
          (IDENTIFIER=WASD_HTTP_SERVER,ACCESS=READ)
          (IDENTIFIER=WASD_HTTP_NOBODY,ACCESS=READ)
</pre>

<li> The third involves creating a rights identifier, granting that to both the 
server and scripting(/application) accounts, and then applying an ACL to the
directory tree providing READ access to that rights identifier.

<pre class="code">
APP.DIR;1             0.50KB    1-FEB-2014 05:16  [SYSTEM]
        (RWED,RWED,,)
          (IDENTIFIER=APP_ACCESS,ACCESS=READ)
          (IDENTIFIER=*,ACCESS=NONE)
          (IDENTIFIER=APP_ACCESS,OPTIONS=DEFAULT,ACCESS=READ)
          (IDENTIFIER=*,OPTIONS=DEFAULT,ACCESS=NONE)
          (DEFAULT_PROTECTION,SYSTEM:RWED,OWNER:RWED,GROUP:,WORLD:)
</pre>

<pre class="code">
EXAMPLE.PHP;1            1KB    1-FEB-2014 05:16  [SYSTEM]
        (RWED,RWED,,)
          (IDENTIFIER=APP_ACCESS,ACCESS=READ)
          (IDENTIFIER=*,ACCESS=NONE)
</pre>

</ol>

<h3><a name="logos"></a>No PHP or Zend Logos?</h3>

<p> By default WASD validates query strings in its own inimitable fashion
(correctly in the author's HO). This validation interferes with the requesting
of the internally generated PHP and Zend logos (as are included by the
<tt>php_info.php</tt> script) and may similarly for other PHP scripts. To
disable query string validation by WASD include the following WASD_CONFIG_MAP
rule at an appropriate location before or at mapping of PHP scripts.

<pre class="code">
set /**.php* script=query=relaxed
</pre>

<h3><a name="script_syntax_unix"></a>PHP on ODS-5 Volumes</h3>

<p> For scripts requiring <i>extended file specification</i> (EFS, located on
ODS-5 volumes) the script path needs to be mapped as ODS-5.

<pre class="code">
set /**.php* script=query=relaxed ods=5
</pre>

<p> When a script environment is mapped as residing on an ODS-5 volume, any
VMS-syntax file specifications contained in PATH_TRANSLATED and SCRIPT_NAME are
automatically translated to Unix-style syntax. This has been demonstrated
to better support PHP applications derived from such environments, in
particular allowing relative directory references. This occurs whether or
not the path is SET using <i>script=syntax=unix</i>.

<p>For example; by default a request's underlying CGI variables might be:

<p><table class="which" style="margin-left:2em;border-collapse:collapse">
    <tbody>
      <tr>
        <td>REQUEST_URI</td>
        <td>/php-bin/php_info.php/wasd_root/src/phprte/</td>
      </tr>
      <tr>
        <td>PATH_INFO</td>
        <td>/wasd_root/src/phprte/</td>
      </tr>
      <tr>
        <td>PATH_TRANSLATED</td>
        <td>WASD_ROOT:[SRC.PHPRTE]</td>
      </tr>
      <tr>
        <td>SCRIPT_NAME</td>
        <td>/php-bin/php_info.php</td>
      </tr>
      <tr>
        <td>SCRIPT_FILENAME</td>
        <td>PHP-BIN:[000000]PHP_INFO.PHP</td>
      </tr>
    </tbody>
  </table>

<p> After mapping being on ODS-5 and subsequent translation they are presented
as:

<p><table class="which" style="margin-left:2em;border-collapse:collapse">
    <tbody>
      <tr>
        <td>_SERVER["REQUEST_URI"]</td>
        <td>/php-bin/php_info.php/wasd_root/src/phprte/</td>
      </tr>
      <tr>
        <td>_SERVER["PATH_INFO"]</td>
        <td>/wasd_root/src/phprte/</td>
      </tr>
      <tr>
        <td>_SERVER["PATH_TRANSLATED"]</td>
        <td>/WASD_ROOT/SRC/PHPRTE/</td>
      </tr>
      <tr>
        <td>_SERVER["SCRIPT_NAME"]</td>
        <td>/php-bin/php_info.php</td>
      </tr>
      <tr>
        <td>_SERVER["SCRIPT_FILENAME"]</td>
        <td>/PHP-BIN/000000/PHP_INFO.PHP</td>
      </tr>
    </tbody>
  </table>

<h3>Script Default or Home Directory</h3>

<p> The <span class="phprte">phpRTE</span> engine will by default <i>chdir()</i> to the Unix-style syntax
equivalent of the directory containing the PHP script file. It also does
a <i>setenv()</i> against the environment variable PATH to this same string.
This location may be explicitly provided using the value of CGI variable
SCRIPT_DEFAULT and set on a per-script or general basis using the mapping rule
<i>Set script=default=&lt;string&gt;</i>. It will accept either VMS and
Unix specifications depending on the requirements of the script itself.

<pre class="code">
set /php-bin/mumble.php* script=default="/mumble_device/000000"
set /php-bin/mumble.php* script=default="mumble_device:[000000]"
</pre>

<h3>"Watch" Mode</h3>

<p> This is a basic facility to assist in debugging the interactions
between the WASD server, <span class="phprte">phpRTE</span> scripting engine, script activation and
input/output. It does not provide for debugging of the script itself but
may be of some elementary assistance when investigating the environment the
script is activating under. There are a number of methods for activating
"watch" mode.

<ul>

<li>Defining the logical name <tt>PHPRTE$WATCH</tt> to any value.

<pre class="code">
$ define /system phprte$watch *
</pre>

<li>Defining the logical name <tt>PHPRTE$WATCH_SCRIPT_NAME</tt>
to contain a (case-sensitive) string from the SCRIPT_NAME variable.

<pre class="code">
$ define /system phprte$watch_script_name "php_info"
</pre>

<p><li> Defining the logical name <tt>PHPRTE$WATCH_REMOTE_ADDR</tt>
to contain the IP address of the "watching" browser.

<pre class="code">
$ define /system phprte$watch_remote_addr "192.168.0.2"
</pre>

<p><li> Adding the string "#watch" to the first line of the PHP script.<br>

<pre class="code">
&lt;?php #watch
echo "&lt;h1&gt;&lt;center&gt;Testing the PHPINFO () function&lt;/center&gt;&lt;/h1&gt;&lt;br&gt;\n";
phpinfo (INFO_ALL);<br>?&gt;
</pre>
  </li>
  <li>
    <p>Having a string "#watch:remote_addr=..." in the first line of
the PHP script, specifying the IP address of the "watching" browser.<br>
    </p>
<pre class="code">
&lt;?php #watch:remote_addr=192.168.0.2
echo "&lt;h1&gt;&lt;center&gt;Testing the PHPINFO () function&lt;/center&gt;&lt;/h1&gt;&lt;br&gt;\n";
phpinfo (INFO_ALL);<br>?&gt;
</pre>

</ul>

<p> When either of the logical names is defined without the other each
operates to enable "watch" completely independently. When defined
concurrently both must match for "watch" to be enabled. For example; when
<tt>PHPRTE$WATCH_SCRIPT_NAME</tt> is defined only that script is "watch"ed;
when <tt>PHPRTE$WATCH_REMOTE_ADDR</tt> is defined, all scripts activated by
the specified host are "watch"ed; when both are defined only the specified
script can be "watch"ed by the specified host. Similar (but different :-)
constraints apply to the script-embedded string.

<p> A WATCH statement contains a statement number, timestamp, and then some
free-form text (that hopefully is self-explanatory). WATCH output
can also comprise a hex-dump of a block of data.

<h2><a name="Configure_PHP"></a>Configure PHP</h2>

<p> The author of <span class="phprte">phpRTE</span> is (still) only a PHP novice, so anything in this
section  should be taken with a large pinch of salt. Any scripting environment
should be approached with due caution and diligence. Please ensure you are
familiar with PHP and its security requirements in particular before betting
the company on anything in this section.

<p> PHP configuration is accomplished using the <tt>PHP.INI</tt> file, by
default located in the <tt>PHP_ROOT:[000000]</tt> directory.

<p> Mapping rules configure on a per-request basis. Logical names and
configuration file content are loaded once at persistent <span class="phprte">phpRTE</span> engine
startup. Changes to configuration need to be loaded into any instantiated PHP
engine(s) using <tt>$HTTPD/DO=DCL=PURGE</tt>.

<h3>PHPRTE$INI</h3>

<p> The PHP engine has a set of default configuration parameters and so can be
used without specific configuration. This not a tutorial on which
changes should be made for any give circumstance, just how to pass those
changes into the <span class="phprte">phpRTE</span> scripting engine. To change the defaults a
configuration file PHP.INI should be provided. The default location of
this for VMS PHP and WASD is <tt>PHP_ROOT:[000000]PHP.INI</tt>.
To use a PHP.INI&nbsp; from a location other than the VMS PHP default
define the logical name <tt>PHPRTE$INI</tt> to locate the file. This
logical name can be in any table the scripting process can access (e.g.
process, job, system).

<h3>PHPRTE$INI2</h3>

<p> <span class="phprte">phpRTE</span> also has a secondary PHP.INI which contains directives that
override those from the primary PHP.INI. This can be useful when
maintaining the site-wide PHP configuration in the primary PHP.INI while
placing only those directives required to be added or modified for the
particular application. To have the <span class="phprte">phpRTE</span> engine process this file
define the logical name <tt>PHPRTE$INI2</tt> to contain the location of the
file. This can be defined in any table the scripting process can access
(e.g. process, job, system). To suppress use of the primary PHP.INI file
and rely entirely on the secondary for configuration define the primary logical
name to the NL: device.

<pre class="code">
$ DEFINE PHPRTE$INI NL:
</pre>

<h3>PHPRTE$INIS</h3>

<p> To specify PHP.INI directives directly (and avoid the overhead of file
processing) the logical name <tt>PHPRTE$INIS</tt> can be
defined. The format for this string is <span
 style="font-style: italic;">name="value"[;name="value"]</span>, where
a semicolon is used<span style="font-style: italic;"></span> to
separate directives. Any directive used in this logical overrides
the same directive in the primary and secondary PHP.INI. This is
an example of such a logical value string and its definition
(continued for printed page clarity).

<pre class="code">
short_open_tag=1 ; expose_php=0 ; include_path="/phprte/application3/include"

$ DEFINE PHPRTE$INIS "short_open_tag=1 ; expose_php=0 ; include_path=""/phprte/application3/include"""
</pre>

<a name="Mapping_Rules">
<h3>Mapping Rules</h3>
</a>

<p> It is possible to pass parameters to PHP scripts and applications using
the <i>script=param=(name=value)</i> mapping rule. The <span class="phprte">phpRTE</span> scripting
engine checks for a number of reserved identifiers and will use the contents of
those present to perform the indicated function. The primary PHP.INI
cannot be supplied via mapping rule due to PHP module startup requirements.

<p><table class="which" style="margin-left:2em;border-collapse:collapse">
  <tbody>
    <tr>
      <th><nobr>Parameter Name</nobr></th>
      <th>Purpose</th>
    </tr>
    <tr>
      <td>PHP_INI</td>
      <td>Provides the location for the primary PHP.INI configuration file.</td>
    </tr>
    <tr>
      <td>PHP_INI2</td>
      <td>Provides the location for the secondary PHP.INI configuration file.</td>
    </tr>
    <tr>
      <td>PHP_INIS</td>
<td>Allows the specification of a value for any of the configuration directives
allowed in PHP.INI.  The format for these parameters is
name="value"[;name="value"], where a semi-colon is used to separate directives.
See examples below.
      </td>
    </tr>
  </tbody>
</table>

<p> The first example shows the specification of a primary PHP.INI file,
the second of a secondary PHP.INI file,
and the third the use of a configuration directive string.<br>

<pre class="code">
set /phprte/application_a/* script=param=(PHP_INI="php:[application_a]php.ini")

set /phprte/application_b/* script=param=(PHP_INI2="php:[application_b]php.ini")

# continuation lines used for printed page clarity
set /phprte/application_c* script=param=(PHP_INIS=\
'short_open_tag=1 ; expose_php=0 ; include_path="/phprte/application_c/include"')
</pre>

<a name="Example_Scripts">
<h2>Example Scripts</h2>
</a>

<p> After configuration the following scripts may be used to confirm the
environment is functioning.

<ul>

<li> <a target="_blank" href="/cgi-bin/php_rules.php">/cgi-bin/php_rules.php</a>

<li> <a target="_blank" href="/cgi-bin/php_info.php">/cgi-bin/php_info.php</a>&nbsp;&nbsp;
(no PHP or Zend <a href="#logos">logos</a>?)

</ul>

<p>Script sources:&nbsp;
<a target="_blank" href="/wasd_root/src/phprte/scripts/*.*">WASD_ROOT:[SRC.PHPRTE.SCRIPTS]</a>

<a name="Performance">
<h2>Performance</h2>
</a>

<p> The performance of <span class="phprte">phpRTE</span> is quite respectable.

<p> This test bench was an <u>innotek GmbH VirtualBox "Intel(R) Core(TM)
i7-9700 CPU @ 3.00GHz" with 3 CPUs and 7GB running VMS V9.2-2</u> and
VSI TCP/IP Services for OpenVMS x86_64 Version V6.0.

<pre class="code">
X86VMS$ @kits:vups
innotek GmbH VirtualBox with 3 CPU and 7936MB running VMS V9.2-2
Approximate System VUPs Rating : 653.4 ( min: 653.4 max: 653.4 )
</pre>

The data have been collected using the h2load utility
(<a target="_blank" href="https://nghttp2.org/documentation/h2load.1.html">https://nghttp2.org/documentation/h2load.1.html</a>)
from the HTTP/2 C Library
(<a target="_blank" href="https://nghttp2.org">https://nghttp2.org</a>).
This utility can be used to configurably load HTTP, HTTPS and HTTP/2 servers.
Note that the number of client threads (-t) is explicitly set to the connection
concurrency (-c) to maximise h2load processing. The h2load utility maintains
connection persistence between HTTP/1.1 requests so the network connection
setup is generally only a factor for the first of many.

<pre class="code">
% h2load --h1 -n 1000 -c 2 -t 2 https://x86vms.lan/cgi-bin/php_info.php
starting benchmark...
spawning thread #0: 1 total client(s). 500 total requests
spawning thread #1: 1 total client(s). 500 total requests
TLS Protocol: TLSv1.3
Cipher: TLS_AES_256_GCM_SHA384
Server Temp Key: X25519 253 bits
Application protocol: http/1.1
progress: 10% done
 <i>8&lt; snip 8&lt;</i>
progress: 100% done

finished in 8.62s, 115.95 req/s, 6.17MB/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 53.20MB (55783147) total, 265.63KB (272000) headers (space savings 0.00%), 52.72MB (55280147) data
                     min         max         mean         sd        +/- sd
time for request:    11.62ms    119.16ms     16.96ms      7.93ms    99.10%
time for connect:    30.91ms     50.70ms     40.80ms     13.99ms   100.00%
time to 1st byte:    66.03ms     69.92ms     67.98ms      2.75ms   100.00%
req/s           :      57.98       59.36       58.67        0.98   100.00%
</pre>

<p> And for the simpler script (with far less output):

<pre class="code">
% h2load --h1 -n 1000 -c 2 -t 2 https://x86vms.lan/cgi-bin/php_rules.php
starting benchmark...
 <i>8&lt; snip 8&lt;</i>
finished in 3.93s, 254.49 req/s, 130.97KB/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 514.65KB (527000) total, 265.63KB (272000) headers (space savings 0.00%), 175.78KB (180000) data
                     min         max         mean         sd        +/- sd
time for request:     7.23ms     38.63ms      7.77ms      1.13ms    98.20%
time for connect:    29.92ms     50.24ms     40.08ms     14.37ms   100.00%
time to 1st byte:    68.54ms     72.45ms     70.49ms      2.77ms   100.00%
req/s           :     127.25      127.39      127.32        0.10   100.00%
</pre>

<p> Apache/2.4.54 (OpenVMS) PHP/8.0.10 OpenSSL/3.0.12

<pre class="code">
% h2load --h1 -n 1000 -c 2 -t 2 https://x86vms.lan:7443/php_info.php
starting benchmark...
spawning thread #0: 1 total client(s). 500 total requests
spawning thread #1: 1 total client(s). 500 total requests
TLS Protocol: TLSv1.3
Cipher: TLS_AES_128_GCM_SHA256
Server Temp Key: X25519 253 bits
Application protocol: http/1.1
progress: 10% done
 <i>8&lt; snip 8&lt;</i>
progress: 100% done

finished in 6.38s, 156.80 req/s, 9.42MB/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 60.08MB (62997112) total, 166.13KB (170120) headers (space savings 0.00%), 59.87MB (62775000) data
                     min         max         mean         sd        +/- sd
time for request:    10.32ms     21.14ms     12.33ms      1.30ms    78.80%
time for connect:    30.51ms     32.19ms     31.35ms      1.19ms   100.00%
time to 1st byte:    42.77ms     44.63ms     43.70ms      1.31ms   100.00%
req/s           :      78.40       79.87       79.14        1.04   100.00%
</pre>

<p> And <b>again</b> for the simpler script (with far less output):

<pre class="code">
% h2load --h1 -n 1000 -c 2 -t 2 https://x86vms.lan:7443/php_rules.php
starting benchmark...
 <i>8&lt; snip 8&lt;</i>
finished in 4.12s, 242.79 req/s, 94.08KB/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 387.50KB (396800) total, 166.13KB (170120) headers (space savings 0.00%), 175.78KB (180000) data
                     min         max         mean         sd        +/- sd
time for request:     7.07ms     19.25ms      7.93ms      1.22ms    94.80%
time for connect:    26.04ms     26.47ms     26.25ms       304us   100.00%
time to 1st byte:    37.83ms     39.67ms     38.75ms      1.30ms   100.00%
req/s           :     121.40      122.09      121.74        0.48   100.00%
</pre>

<a name="DCLsymbol">
<h2>DCLsymbol Extension</h2>
</a>

<p> A practical solution to a WASD site requiring data passback from a PHP
script to a wrapping DCL procedure.  This extension allows DCL local and global
symbols to be assigned, deleted, and values accessed from within PHPRTE.

<p> Further information is available in the source code of
<a target="_blank" href="dclsymbol.c">DCLSYMBOL.C</a>

<a name="MB_Installation">
<h2>Mark Berryman PHP</h2>
</a>

<p> To customise WASD <span class="phprte">phpRTE</span> for a Mark Berryman (MB) release.

<blockquote>
&bull;&nbsp; <span class="phprte">phpRTE</span> has a different structure to previous MB expectations.
<br>&bull;&nbsp;  The MB PHP kit is integrated into the the WASD scripting
(cgi-bin) structure.
<br>&bull;&nbsp;  MB PHP executables are placed into the CGI_EXE directory.
<br>&bull;&nbsp;  MB PHP extensions are placed into an [.EXTENSIONS]
subdirectory of the CGI_EXE directory. 
<br>&bull;&nbsp;  A
<a target="_blank" href="./phprte.com"><i>wrapper procedure</i></a>
massages the MB expectations (from PHPWASD.EXE days) into VSI PHP directory
expectations.
</blockquote>

<ol>

<li> Obtain a relevant kit from

<blockquote>
<a target="_blank" href="https://www.theberrymans.com/php_kits/">
https://www.theberrymans.com/php_kits/</a>
</blockquote>

<p><li> Suggest creating a version-specific directory for the kit inside the
WASD directory structure (simplfies the copying files).

<pre class="code">
$ create /directory [src.php_x86_8_1_23]
$ set default [src.php_x86_8_1_23]
$ unzip <i>&lt;location&gt;</i>php_x86_8_1_23.zip
</pre>

<p><li> Then integrating the MB executables into the scripting environment.

<pre class="code">
$ extensions = f$trnlnm("cgi_exe") - "]" + ".extensions]"
$ create /directory 'extensions'
$ copy [src.php_x86_8_1_23]php.exe,php_cgi.exe,phpdbg.exe,phpshr.exe,phpwasd.exe cgi_exe:
$ copy /exclude=(php_cgi.exe) [src.php_x86_8_1_23]php_*.exe 'extensions'
$ httpd /do=dcl=purge
</pre>

</ol>

<p> To remove MB PHP environment or before upgrading.

<pre class="code">
$ extensions = f$trnlnm("cgi_exe") - "]" + ".extensions]"
$ delete cgi_exe:phprte.exe;*,php_cgi.exe;*,phpdbg.exe;*,phpshr.exe;*,phpwasd.exe;*
$ delete 'extensions'php_*.exe;*
$ delete cgi_exe:extensions.dir;*
$ httpd /do=dcl=purge
</pre>

<a name="Problems">
<h2>Problems?</h2>
</a>

<ul>
<li> With the <span class="phprte">phpRTE</span> script ...
<a href="mailto:Mark.Daniel@wasd.vsm.com.au">mark.daniel@wasd.vsm.com.au</a>
<li> The info-WASD mailing list
<li> With the PHP for OpenVMS kit ... the
<a target="_blank" href="https://forum.vmssoftware.com/">VSI Forum</a>
<li> Perhaps <a href="news:comp.os.vms">comp.os.vms</a> 
</ul>

<p> Unfortunately the author of the <span class="phprte">phpRTE</span> interface is such a PHP novice he
is not in any position to answer queries about PHP "programming" or
usage. If there's an obvious behavioural problem with <span class="phprte">phpRTE</span> 
(preferably diagnosed by someone with PHP experience) then he's it though.

<a name="Releases">
<h2>Releases</h2>
</a>

<dl>

<dt>v2.0.0&nbsp<i>(again)</i>&nbsp;06-JAN-2025</dt>
<dd>&bull;&nbsp; revise a couple of (relevant) typos in the original
<i>readmore</i>
<dd>&bull;&nbsp; add the <span class="phprte">phpRTE</span> prehistory section

<dt>v2.0.0&nbsp; 01-OCT-2024</dt>
<dd>&bull;&nbsp; VSI PHP 8
<br>&bull;&nbsp; reframe PHPWASD as <span class="phprte">phpRTE</span>
<br>&bull;&nbsp;<tt>[src.php]</tt> and now <tt>[src.phprte]</tt> allows
concurrent support for previous
release(s)

<dt>v1.4.5&nbsp; 02-FEB-2014</dt>
<dd>&bull;&nbsp; tweak for PHP 5.4.<i>n</I> (future release at this date)

<!--
<dt>v1.4.4&nbsp; 01-FEB-2014</dt>
<dd>&bull;&nbsp; employ Mark Berryman PHP kit (eliminate use of CSWS kit)
<dd>&bull;&nbsp; intial development against 5.3.28

<dt>v1.4.3&nbsp; 10-FEB-2011</dt>
<dd>&bull;&nbsp; extend PHPRTE$ABSORB_PRE_WRITESAPI to &lt;stderr&gt;

<dt>v1.4.2&nbsp; 17-JUL-2010</dt>
<dd>&bull;&nbsp; WASD v10.1 ProctorDetect()
<dd>&bull;&nbsp; bugfix; initialise SG(request_info), SG(sapi_headers)
<dd>&bull;&nbsp; bugfix; ImageIdent() for __ia64

<dt>v1.4.1&nbsp; 02-JUN-2009</dt>
<dd>&bull;&nbsp; The CSWS PHP v2.0 kit (May 2009) session management extension
outputs spurious debug(?) data <br>&nbsp;&nbsp;&nbsp; which as an interim
measure has been suppressed using the PHPRTE$ABSORB_PRE_WRITESAPI logical name

<dt>v1.4.0&nbsp; 20-MAY-2009</dt>
<dd>&bull;&nbsp; CPQ AXPVMS CSWS_PHP V2.0 (based on PHP v5.2.6)

<dt>v1.3.0&nbsp; 29-JAN-2005</dt>
<dd>&bull;&nbsp; PHPRTE$WATCH_... logical names and script-embedded
"&lt;?php #watch" to activate PHPRTE 'watch' mode 
<dd>&bull;&nbsp; SetCrtlFeature ("DECC$FILE_SHARING"),
<dd>&bull;&nbsp; PHPRTE$INI2, PHPRTE$INIS, PHPRTE$NO_TRANSLATE,
PHP_INI2, PHP_INIS, PHP_NO_TRANSLATE,

<dt>v1.2.0&nbsp; 14-FEB-2004</dt>
<dd>&bull;&nbsp; CSWS PHP 1.2 (PHP 4.3.2)
<dd>&bull;&nbsp; minor conditional mods to support IA64

<dt>v1.1.0&nbsp; 26-DEC-2002</dt>
<dd>&bull;&nbsp; CSWS PHP v1.1
-->
<br>&#8942;
<dt>v1.0.0&nbsp; 16-JAN-2002</dt>
<dd>&bull;&nbsp; initial

</dl>


<a name="Acknowlegements">
<h2>Acknowlegements</h2>
</a>

<p> VMS Software for their <i>official</i>, <u>supported</u> port.
<br> Of course, thanks to the PHP development team!

<p><hr align="left" size="1" noshade><p>

</body>
</html>