PHP began life as a simple little cgi wrapper written in Perl.
I wrote it in an afternoon during a period between contracts when
I needed a quick tool to get an idea of who was reading my online
resume. It was never intended to go beyond my own private use.
The web server where I had my resume was extremely overloaded and
had constant problems forking processes. I rewrote the Perl
wrapper in C to get rid of the considerable overhead of having to
fork Perl each time my resume was accessed.

Eventually other people on the same web server came across my
wrapper and asked if they could use it. Then, as inevitably
happens, they started asking for more features. I added more
features and finally put together a semi-complete distribution
along with documentation, a mailing-list and a FAQ. The name of
this first package was Personal Home Page Tools, which later
became Personal Home Page Construction Kit.

At the same time I started playing with databases and wrote a
tool to easily embed SQL queries into web pages. It was basically
another CGI wrapper that parsed SQL queries and made it easy to
create forms and tables based on these queries. This tool was
named FI (Form Interpreter).

PHP/FI version 2.0 is a complete rewrite of these two packages
combined into a single program. It has now evolved to the point
where it is a simple programming language embedded inside HTML
files. The original acronym, PHP, has stuck. It isn't really
appropriate any longer. PHP/FI is used more for entire web sites
today than for small Personal Home Page setups. By whatever name,
it eliminates the need for numerous small Perl cgi programs by
allowing you to place simple scripts directly in your HTML files.
This speeds up the overall performance of your web pages since
the overhead of forking Perl several times has been eliminated.
It also makes it easier to manage large web sites by placing all
components of a web page in a single html file. By including
support for various databases, it also makes it trivial to
develop database enabled web pages. Many people find the embedded
nature much easier to deal with than trying to create separate
HTML and CGI files.

PHP Version 3.0 is yet another rewrite. If you are just
starting out with PHP, I suggest that you start with Version 3.0
instead of continuing with 2.0 at this point. PHP3 is quickly
going to replace PHP/FI 2.0 and all development efforts are now
focused on PHP3. Any remaining bugs in PHP/FI 2.0 are unlikely to
be fixed unless they are straightforward. More information on
PHP3 can be found at http://www.lerdorf.on.ca/php3.

Throughout this documentation any references to PHP, FI or
PHP/FI all refer to the same thing. The difference between PHP
and FI is only a conceptual one. Both are built from the same
source distribution. When I build the package without any access
logging or access restriction support, I call my binary FI. When
I build with these options, I call it PHP.

If you have absolutely no Unix experience, you may want to
ask around for someone with a little bit of Unix knowledge to
help you through this installation. Every attempt has been
made to make it as simple as possible, but since the software
is quite involved and relies on a number of different
components, it is not realistic to assume it will go smoothly
on all systems. You will probably need someone around who
knows the particulars of the destination system well.

Things You Need To Know Before
Installing

- Can you run both get and post method cgi programs on
your server?This is not relevant if you installing the Apache module
version. If not, you can not use this package. On many
public ISP's CGI programs are either disallowed or severely
restricted. If this is the case on your system, talk to your
system administrator and ask him/her to have a look at this
package and see if they will install it for you.

- If you have mSQL installed on your system, you need to
know the base directory of this installation.

- If you have Postgres95 or PostgreSQL installed on your
system, you need to know the base directory of this
installation.

- If you are going to be storing log and access
configuration files in an NFS-mounted directory and your
system does not provide NFS file locking then you will need
to define the NFS_HACK variable manually in the src/Makefile
and you may want to use a slightly modified version of the
gdbm library. See the nfs_hack.txt file in
the doc directory for more information on this.

- Note that if you are not interested in using PHP to
track accesses to your pages, do not compile this option into
the binary. You should also leave out the access restriction
code. There is considerable overhead in including these
options.

- If you are installing the Apache module version, you
will need to know the Apache src code directory location.

Installation Steps

Step 1.

Run the install program: ./install

You will be asked a number of questions. If you do not
understand what is being asked, simply hit return. The
default choice should be safe on most systems. This doesn't
apply for the questions asking you to specify a directory for
your configuration and log files however. Choose any
directory to which the httpd (usually "nobody") has write
privileges. You may create this directory manually somewhere
and simply chown nobody
directory.

Step 2.

Go into the src directory: cd src

Have a look at the php.h file. There are a number of
compile-time options that can be set here.

Step 3.

type: make

This will create the actual executable program file named
php.cgi by default, or if you are installing the
Apache module, it will create a libphp.a file.

Step 4. (if you are not installing the Apache
module version)

Copy the php.cgi binary to your system's
cgi-bin directory. If you do not have access to do this and
wish to install it in your own personal directory, you may do
so, but you should set the setuid bit on the executable with:
chmod u+s /path/php.cgi

If you do not make set the setuid bit on the binary then
any files created by the binary will be owned by the user id
under which the web server runs. If this is acceptable, then
you can safely leave the setuid bit off.

Step 4. (if you are installing the Apache
module version)
Change to your Apache src directory where the
mod_php.c and mod_php.h files should have
been copied to. If they weren't which usually happens because
of permission problems, copy these two files there manually.
Edit your Apache Configuration file and add the EXTRA_LIBS
line which was produced at the end of Step
3. And add:

Module php_module mod_php.o

to the very end of the file. Then type:
./Configure and then make
to rebuild your Apache httpd binary. Install this binary.

Next you need to edit your Apache conf/srm.conf file and
add a line like:

AddType application/x-httpd-php
.phtml

This defines a new MIME, application/x-httpd-php, which
will trigger the PHP module to parse any file ending with the
.phtml extension. You can pick any extension you
like for this.

You may not want to enable everyone to run PHP parsed
files. You can place the above AddType line within
<Location /path>....</Location> directives in the
access.conf file to only allow PHP-parsed documents
in certain directories on your server.

Now you are ready to restart your httpd server. See the
Apache Module Notes for more details on
configuring the PHP Module.

Testing the software

Once installed you can test to see if your executable
works by entering a URL similar to the following in your
browser:

http://your.site.domain/cgi-bin/php.cgi

This should show you a page which contains the version
number along with various other useful information.

To test the Apache module version, create any file with a
.phtml extension and put a tag like: <?phpinfo()> in
the file and see if it gets parsed.

Using the software

To actually use the software on an existing HTML file, you
can simply append the path to your file to the above URL.
ie.

http://your.site.domain/cgi-bin/php.cgi/path/file.html

You should have a look at the CGI
Redirection section of this documentation. Running PHP/FI
through a redirect means you can automatically have a URL
like http://your.site.domain/file.phtml be parsed by
PHP/FI.

The first thing you will notice if you run a page through
PHP/FI is that it adds a footer with information about the number
of times your page has been accessed (if you have compiled access
logging into the binary). This is just a very small part of what
PHP/FI can do for you. It serves another very important role as a
form interpreter cgi, hence the FI part of the name. For example,
if you create a form on one of your web pages, you need something
to process the information on that form. Even if you just want to
pass the information to another web page, you will have to have a
cgi program do this for you. PHP/FI makes it extremely easy to
take form data and do things with it.

It's that simple! PHP/FI automatically creates a variable for
each form input field in your form. You can then use these
variables in the ACTION URL file.

The next step once you have figured out how to use variables
is to start playing with some logical flow tags in your pages.
For example, if you wanted to display different messages based on
something the user inputs, you would use if/else logic. In our
above example, we can display different things based on the age
the user entered by changing our display.html to:

PHP/FI provides a very powerful scripting language which will
do much more than what the above simple example demonstrates. See
the section on the PHP/FI Script Language
for more information.

You can also use PHP/FI to configure who is allowed to access
your pages. This is done using a built-in configuration screen.
With this you could for example specify that only people from
certain domains would be allowed to see your pages, or you could
create a rule which would password protect certain pages. See the
Access Control section for more
details.

PHP/FI is also capable of receiving file uploads from any
RFC-1867 compliant web browser. This feature lets people upload
both text and binary files. With PHP/FI's access control and
logical functions, you have full control over who is allowed to
upload and what is to be done with the file once it has been
uploaded. See the File Upload section for
more details.

PHP/FI has support for a database package called mSQL. This
allows you to put information into a database and access this
information through simple embedded SQL queries right in your
.HTML files. Adding a database back-end to a web page has never
been easier. See the section on mSQL
Support for more information.

PHP/FI has support for the Postgres95/PostgreSQL database
package. It supports embedded SQL queries in your .HTML files.
See the section on Postgres95/PostgreSQL
Support for more information.

PHP/FI also has support for the mysql database package. It
supports embedded SQL queries in your .HTML files. See the
section on mysql Support for more
information.

A good way to run PHP/FI is by using a cgi redirection
module with the Apache server. Please note that you do not
need to worry about redirection modules if you are using the
Apache module version of PHP/FI. There are two of these
redirection modules available. One is developed by Dave
Andersen <angio@aros.net> and it is available at
ftp://ftp.aros.net/pub/util/apache/mod_cgi_redirect.c
and the other comes bundled with Apache and is called
mod_actions.c. The modules are extremely similar. They differ
slightly in their usage. Both have been tested and both work
with PHP/FI.

One large caveat at the time of this writing (Apr.20/96)
is that the current official Apache release (1.0.5) has a
severe limitation which prevents cgi redirected requests from
having any post-method data associated with them. I have
tracked this down and fixed it in my version of Apache, and
there is an official patch available in the File Archives on the
PHP Home Page.

A second rather large caveat with Apache 1.0.x is that it
does not align double types correctly on most architectures.
You may find yourself getting strange bus errors from your
httpd when using mod_php, either upgrade to Apache 1.1 or
edit the alloc.c Apache source file. In this file you
will find the following piece of code:

union align
{
/* Types which are likely to have the longest RELEVANT alignment
* restrictions... we don't do much with doubles.
*/
char *cp;
void (*f)();
long l;
FILE *fp;
};

You will need to add a double to this line and recompile
your Apache server. The correct block of code is:

Check the Apache documentation on how to add a module.
Generally you add the module name to a file called
Configuration. The line to be added if you want to
use the mod_actions module is:

Module action_module mod_actions.o

If you are using the mod_cgi_redirect.c module add this
line:

Module cgi_redirect_module mod_cgi_redirect.o

Then compile your httpd and install it. To configure the
cgi redirection you need to either create a new mime type in
your mime.types file or you can use the
AddType command in your srm.conf
file to add the mime type. The mime type to be added should
be something like this:

application/x-httpd-php phtml

If you are using the mod_actions.c module you need to add
the following line to your srm.conf file:

Action application/x-httpd-php
/cgi-bin/php.cgi

If you are using mod_cgi_redirect.c you should add this
line to srm.conf:

CgiRedirect application/x-httpd-php
/cgi-bin/php.cgi

Don't try to use both mod_actions.c and mod_cgi_redirect.c
at the same time.

Once you have one of these cgi redirection modules
installed and configured correctly, you will be able to
specify that you want a file parsed by php/fi simply by
making the file's extension .phtml.
Furthermore, if you add index.phtml to your
DirectoryIndex configuration line in your
srm.conf file then the top-level page in a directory
will be automatically parsed by php if your index file is
called index.phtml.

Netscape HTTPD

You can automatically redirect requests for files with a
given extension to be handled by PHP/FI by using the Netscape
Server CGI Redirection module. This module is available in
the File Archives
on the PHP/FI Home Page.
The README in the package explicitly explains how to
configure it for use with PHP/FI.

NCSA HTTPD

NCSA does not currently support modules, so in order to do
cgi redirection with this server you need to modify your
server source code. A patch to do this with NCSA 1.5 is
available in the PHP/FI file archives.

The CGI version of PHP/FI does not read any
.htaccess files which may be present in a directory.
This means that if you have files that are protected using the
standard .htaccess server-based access control feature, people
could potentially circumvent this security by loading the page
through PHP/FI. Note that this is not an issue for the Apache
module version of PHP/FI.

A second problem with the CGI version is that if it is placed
in the system's cgi-bin directory it can be used to view any file
on your system as long as the user id it runs as has access to
it.

There are a couple of different solutions to this problem. The
easiest is probably to use the PATTERN_RESTRICT
feature found in php.h. This lets you define an
extension (or a pattern of extensions) which are allowed to be
parsed by PHP/FI. If a file does not have this extension and
someone tries to load it with PHP/FI, an access denied
message will appear.

Another solution is to use the PHP/FI access control mechanism
to mimic the access control setup you have in your .htaccess
file. Keeping this information in two places can be tedious
though, and the two systems don't share all of the same
features.

The problem can also be solved using file permissions. PHP/FI
can be set up to run setuid as any user you wish. Then files that
are to be read by PHP/FI can be given appropriate permissions and
files not to be read by PHP/FI should be owned by another user id
and have their permissions changed accordingly.

For additional security options related to sites which provide
shared access to PHP, see the Safe Mode
section.

PHP's Safe Mode tries to solve the common problem faced by
many ISP's regarding letting all their users run CGI programs.
The common mechanism for making shared CGI access more secure is
to use a cgi wrapper like the su_exec utility that comes with
Apache. This will not work for PHP when it is running as a module
because it is not a separate process that can be setuid'ed.

It is based on a file permission scheme. Simply put, if a file
is either owned by the same user id as the script that is trying
to access it, or if the file is in a directory that is owned by
the same user as the script that is trying to access it, then the
access is allowed. One caveat here is that you must make sure
that your OS does not allow non-root user to chown away the
ownership on one of their files. Many older SysV systems allow
this. The most common one is Irix. It is possible to change this
behaviour at the OS level on Irix.

Safe Mode applies to each function which could possibly be a
security risk. Below is the current list of checks applied to
each relevant function. In the following list, PHP UID refers to
the user id of the owner of the current file being parsed by PHP,
and HTTP UID refers to the user id the httpd process is running
as (usually nobody).

Owner of file to be included must either be the PHP UID or
the directory in which the file resides must be owned by the
PHP UID.

Exec, System, PassThru and Popen

Executables to be forked and executed must reside in the
directory defined by the PHP_SAFE_MODE_EXEC_DIR #define in
php.h when PHP is compiled.

Mysql_Connect

This function takes an optional username to use to connect
to an MySQL database. When in safe mode, this username must
either be the username of the owner of the current file being
parsed, or the name of the httpd user (usually nobody).

HTTP Authentication

The numerical user id of the owner of the script containing
the HTTP Authentication code will be prepended to the
authentication realm. This is to prevent someone from writing a
password grabbing script which spoofs another authenticated
page on the same server.

If you build the CGI version of PHP/FI, you can use it from
the command line simply typing: php.cgi filename where
filename is the file you want to parse. You can also create
standalone PHP/FI scripts by making the first line of your script
look something like:

#!/usr/local/bin/php.cgi -q

The "-q" suppresses the printing of the HTTP headers. You can
leave off this option if you like.

The HTTP Authentication hooks in PHP/FI are only available
when it is running as an Apache module. In an Apache module
PHP/FI script, it is possible to use the Header() command to send
an "Authentication Required" message to the client browser
causing it to pop up a Username/Password input window. Once the
user has filled in a username and a password, the URL containing
the PHP/FI script will be called again with the variables,
$PHP_AUTH_USER, $PHP_AUTH_PW and $PHP_AUTH_TYPE set to the user
name, password and authentication type respectively. Only "Basic"
authentication is supported at this point.

An example script fragment which would force client
authentication on a page would be the following:

Instead of simply printing out the $PHP_AUTH_USER and
$PHP_AUTH_PW, you would probably want to check the username and
password for validity. Perhaps by sending a query to a database,
or by looking up the user in a dbm file.

Watch out for buggy Internet Explorer browsers out there. They
seem very picky about the order of the headers. Sending the
WWW-authenticate header before the HTTP/1.0 401
header seems to do the trick for now.

In order to prevent someone from writing a script which
reveals the password for a page that was authenticated through a
traditional external mechanism, the PHP_AUTH variables will not
be set if external authentication is enabled for that particular
page.

Note however that the above does not prevent someone who
controls a non-authenticated URL from stealing passwords from
authenticated URL's on the same server. The PHP_AUTH_VARS define
in php.h can be undefined to make sure that these
variables will never be set and thus disable anybody from using
mod_php to try to steal passwords.

When running PHP as an Apache module, you may access the
request header variables sent by the remote browser by prepending
$req_ to the beginning of the header value you would like
to use. If the request name contains a - character such as
User-Agent, then you need to map the - to _ (an underscore). ie.
reference it as $req_User_Agent. The phpinfo() function can be used to display all the
request headers.

Running PHP/FI as an Apache module is the most efficient way
of using the package. Running it as a module means that the
PHP/FI functionality is combined with the Apache server's
functionality in a single program. There are a number of
advantages to running it as a module:

Performance

Performance-wise it is a lot faster than traditional CGI
programs. In fact, when running PHP/FI as a module, there is
no CGI involved. The script code in the HTML files is
executed directly by the Apache web server process.

Security

When running as a module, the normal httpd-based access
restriction rules defined either in the Apache conf files or
in private .htaccess files are first applied before the
module is allowed to parse the file. Alternatively, you can
also create PHP/FI scripts that control the normal
httpd-based authentication. See HTTP
Authentication.

Configurability

Since the parser is always active inside the httpd
process, it can be configured on startup using the same
configuration files used to configure the httpd process. The
module can even be configured on a per-directory basis by
placing the PHP configuration
directives in the .htaccess files.

Basis for custom server-based
function

For C programmers interested in accessing their functions
from within Apache, the PHP/FI framework provides a very
simple interface to Apache and to PHP itself. It is much
easier to add a function to PHP and call that from a parsed
page than it is to write an entire Apache module from
scratch. See the Adding your own internal
functions to PHP/FI sections at the end of this document
for further details.

The following directives can be placed either in the
srm.conf file, or within
<Directory>...</Directory> tags in
access.conf or in <Location
/path>...</Location> tags in access.conf or in
individual .htaccess files. In order for the directives
to work in .htaccess files, the Options override must be set on
the AllowOverride Apache directive, with the exception of the
phpEngine directive which is only available in the *.conf
files.

phpShowInfo on|off

Turn the PHP info footers on or off. Default is on.

phpLogging on|off

Turn logging on or off. Default is on.

phpDebug on|off

Turn automatic ?info debug screen on or off. Default is
off.

phpUploadTmpDir directory

Set the directory where form-uploaded files will be
placed.

phpDbmLogDir directory

Set the directory where dbm-based logging files will be
written.

phpSQLLogDB database

Set name of SQL database to use for logging. Default is
"phpfi"

phpSQLLogHost hostname

Set hostname where SQL database to use for logging is
found. Default is localhost.

phpAccessDir directory

Set the directory where PHP-internal access control files
are stored.

phpMaxDataSpace KiloBytes

Max size a sub-pool can grow to within the PHP module.
Setting this value to a low number will minimize the impact
that mod_php will have on your system, but it may also limit
people from writing complex scripts. The default is 8K.

phpIncludePath colon-separated
path

A colon-separated list of directories where php will look
for files in when running include(). The
default is to look only in the current directory.

phpAutoPrependFile file name

Before the actual PHP/FI file is parsed, you may give a
file name here that is parsed before the "main file", using
PHP's Include() function (which means phpIncludePath applies
for the file name). Keep in mind that you can make it difficult
for yourself to use the Header() function in the main file if
you write HTML from an auto-prepended file.

phpAutoAppendFile file name

The name of a file parsed (using PHP's Include()
function)after the actual PHP/FI file has been parsed, similar
to phpAutoPrependFile.

phpAdaDefDB database

Default Adabas database to use. No default value

phpAdaUser username

Default Adabas database user. No default value

phpAdaPW password

Default Adabas database password. No default value

phpEngine on|off

Turn the PHP parsing engine on or off. The default is
on and this directive is only useful for sites that
wish to allow directives from the AllowOverride Options list of
directives to function in .htaccess files while at the same
time restricting mod_php access. The common way to handle
per-virtual host php installs is to enable the PHP mime type
with an AddType directive on a per virtual host basis and then
put "phpEngine off" in the non-PHP virtual host blocks. If a
non PHP customer tries to circumvent things by placing the PHP
mime type in their .htaccess, the phpEngine off setting
restricts the PHP parser from functioning.

phpLastModified
on|off

Since php pages are dynamic, they are processed and sent to
the browser each time you access them. But sometimes, when you
use php for basic includes, the parsed page does not change as
long as the source doesn't. It that case, you may want to avoid
page regeneration/reloading. If phpLastModified is turned on
Apache will send the Last-Modified tag to the browser, so that
the page will only be reloaded when it changes. (not that if
you are using page logging, multiple accesses will not be
logged!)

All of these directives are optional. If a directive is not
specified anywhere, the compile-time default will be used.

PHP/FI can be compiled with FastCGI support. You will need
fetch and compile FCGI
Development Kit for your platform before compiling PHP/FI.
You will also need to get CGI Redirection
working. Then follow the instructions in the FastCGI
documentation for configuring FastCGI for your platform. If you
are using the mod_fastcgi module with the Apache server, here are
the step-by-step instructions:

Now, any pages with the .fhtml extension will be handed off to
the FastCGI php.fcgi process which is already running. The
php.fcgi binary will still work as a normal CGI binary, so you
could just create a symbolic link from php.cgi to php.fcgi.

If you are not using Apache, the above steps will be similar,
but not identical. CGI Redirection mechanisms are available for
NCSA and Netscape servers at the PHP/FI File Archive.

Note that the built-in PHP/FI based access control is likely
to be discontinued in future versions. You should seriously
consider using the security mechanism that comes with your web
server instead.

If you chose to include access control when you compiled the
package, you may append ?config to any URL to edit the
access control file. ie.

http://your.machine.domain/cgi-bin/php.cgi/path/file.html?config

Your configuration password will initially be set to your user
id. If your user id does not work as your password, it probably
means that PHP could not read the /etc/passwd file to locate your
user id. If this is the case, the initial password will be set to
"php". It is a good idea to change this
password. Note that multiple users may maintain their own
personal configuration files through a single PHP/FI binary.

Access Control can be quite confusing initially. The ?config
screen is divided up into a number of sections. The top section
is for changing the password used to make sure that only people
who know this password can change access control characteristics.
In a system-wide installation, each user has his or her own
configuration screen with his or her own password.

The second section of the ?config screen consists of a number
of tables. Each table defines a rule-set. The first rule-set is
always the default rule-set. This default rule-set is used if a
page does not have a rule-set defined specifically for it. After
the default rule-set, any number of specific rule-set tables will
follow.

To add a rule-set for a specific file, enter the URL of the
file in your browser and add ?config to
the end of the URL. On the ?config screen that comes up you will
see that a rule-set has been added for this page, if it wasn't
already there. When a new rule-set is added, it is initially set
to be the same as the default rule-set. The following picture
shows two simple rule-sets. First a default rule-set which just
indicates that hits from all domains should be logged, and
second, for the file /~rasmus/test.html and only that file, any
users coming from a ".edu" domain will not be granted
access.

To edit a rule-set modify the fields until the desired
configuration is reached within a rule-set and then hit the
"Submit Changes" button. If more rules are needed, hit
the "Add Rule" button and then edit the added rule.

To delete a rule, select the checkbox to the right of the rule
and hit the "Submit Changes" button. The screen will
redraw and the rule should disappear.

Note that you need to enter a regular expression in the
pattern field. See the section on regular expressions in this
documentation for more details.

Access Logging is another optional feature which can be
enabled at compile-time by answering Yes to the question
in the install script. You may either store your access log data
in dbm files, in an mSQL database, or in an mysql database. The
latter two are more powerful, but is also a bit more difficult to
set up.

To use dbm files for storing your access logs, you will need
to specify a directory in which log files can be written. PHP
will try to create this directory if it doesn't exist, but to
make sure it has the proper permissions, you may want to create
this directory yourself before running PHP for the first time.
The permissions on the directory should be such that the user id
under which the PHP cgi program will run can write to the
directory.

To use an mSQL or mysql database for storing your access log
data, you need to first make sure you have mSQL or mysql
installed and running on your system. Then you need to create a
database. The default name is "phpfi" although this can be
changed in src/php.h. To create this database for mSQL,
type:

msqladmin create phpfi

or for mysql type:

mysqladmin create phpfi

Then for mSQL, edit your msql.acl file and make sure
the permissions on the database are correct. Something like the
following should suffice:

database=phpfi
read=*
write=nobody,<your user id>
access=local

For mysql, you need to make sure the httpd user (usually
"nobody") has access to the database. Unlike mSQL, mysql stores
access control data in a database. Assuming default permissions,
you should be able to simply execute the following command:

For each user id for whom you want to store log data, you need
to create two tables. The msqllog shell script in the
scripts directory will do this for you. Simply type:

msqllog <user id>

or for mysql, type:

mysqllog <user id>

and the script will create the appropriate tables. You may
need to edit the script to make it reflect where things are
stored on your system.

You may want to have a look at this script. It defines the
field sizes of your log tables. If, for example, you know that
your file paths exceed 64 characters, you need to bump up the
filename size in both the logN and the lastN
tables in this msqllog or mysqllog file.

Access logging stores information about each "hit" on a page.
This information can then be summarized by examining these log
files. An example log file summarizing script is included in the
package. It is the log.html file in the
examples directory. This is the dbm log file analyzer.
The mSQL log file analyzer is called mlog.html. And the
mysql log file analyzer is called mylog.html. To run it,
copy it and the other mlog.* files to a directory accessible from
your web server and type:

http://your.machine.domain/cgi-bin/php.cgi/path/mlog.html

Or, if you are using the Apache module version, you can give
the script a ".phtml" extension and call it with:

http://your.machine.domain/path/mlog.phtml

By default, if you have compiled PHP with access logging
enabled, then your pages will appear with a footer containing
some access information. You may not want to see this footer, but
still log hits. You can turn off this footer with a "phpShowInfo
off" line in your Apache httpd.conf or .htaccess files if you are
running Apache. If you are not running Apache, you may turn these
log footers off either by creating a rule in the ?config section for the page, or by adding a tag
like this to your page:

A problem common to all CGI wrappers is that the HTTPD program
changes the current directory to the directory where whatever it
is loading is stored. In the case of a CGI program, the current
directory is set to the directory where the CGI program resides.
This is normally not a problem, except when it comes to relative
URL's.

A relative URL is a URL which relies upon the current
directory being the same as the directory where the current HTML
file is located. So, for example, if I had the URL:

http://my.machine/~rasmus/file.html

the actual HTML file might be:

~rasmus/public_html/file.html

If within the file.html file I had the tag:

<IMG SRC="pic.gif">

when loaded normally this file gif file is expected to be in
~rasmus/public_html/pic.gif. However, when loaded
through a CGI wrapper with a URL like:

http://my.machine/cgi-bin/php.cgi/~rasmus/file.html

then HTTPD sets the current directory to /cgi-bin (or
wherever the ScriptAlias might point) and subsequently when the
page is loaded the pic.gif file is expected to be in:
/cgi-bin/pic.gif which is usually not the desired
effect.

The quick way around this problem is to use absolute URL's. In
the above example if the image tag had been:

<IMG SRC="/~rasmus/pic.gif">

then there would have been no problem. Using absolute URL's is
not always desirable as it makes pages less portable. An obvious
question you may have at this point is, "Why doesn't PHP just
change the current directory to the right place?". The answer is
that PHP actually does change the current directory to the
location of the HTML file it is displaying. Any file paths used
inside PHP Script tags, can be relative. The problem is that tags
outside of PHP's control such as <img > and <a href >
will not be passed through PHP. When they are parsed, PHP is no
longer active and the current working directory has been set back
to the directory specified by the HTTP Daemon.

The Solution is a compromise. PHP provides a
variable called PATH_DIR. It contains the
directory portion of the current HTML file at all times. If this
PATH_DIR variable is used in the <img > and <a href >
tags then the effect of a relative URL can be achieved, although
to the server it will look like an absolute URL when parsed. From
our above example, the only change we would need to make would be
to change the img tag to:

<IMG SRC="<?echo $PATH_DIR>/pic.gif">

By using the above, you can move the file containing this tag
around, and the tag will always refer to a pic.gif file in
the same directory as the source HTML file.

Another way to handle this is to use the traditional <BASE
HREF=...> in the HTML file.

PHP will detect both GET and POST method data coming from HTML
forms. One important point to understand is that POST method data
is always treated first if both are present. If a PHP variable is
defined by the POST method data, or if the variable is defined by
the HTTP daemon in the Unix environment, then GET method data
cannot overwrite it. This is to prevent somebody from adding
?REMOTE_HOST=some.bogus.host to their URL's and thus
tricking the PHP logging mechanism into recording this alternate
data. POST method data is however allowed to overwrite these
variables.

Any component of the GET data (the data following a '?' in the
URL) which is of the form, word=something will define
the variable $word to contain the value
something. Even if the data is not of this form, it can
be accessed with the $argv built-in array. For example, in a URL
like:

Notice how the EMAIL_ADDR part of the data shows up both as
$argv[2] where it is unparsed, and the $EMAIL_ADDR variable is
created to contain rasmus@lerdorf.on.ca.

The $EMAIL_ADDR variable was used as an example in the above
because it is a useful variable if you are using the logging
features of PHP. By adding:

?EMAIL_ADDR=

to any links on a page where the user's email address is
known, you may propagate it to the next page. The PHP logging
system will automatically look for this variable and record its
value as the user's e-mail address in the logs. For any users of
PHP1, the above serves the same function as adding
?<!--$email--> to the URL used to do in PHP1. It
looks a little bit more complex now, but it is also completely
general allowing you to build your own complex pages.

In the above example you can also see how multiple variables
can be defined right in the GET method data by separating each
with the "&" character. This "&" separated list of
variables must be the last (or only) component of the GET method
data for it to be valid.

The SELECT MULTIPLE tag in an HTML construct allows users to
select multiple items from a list. These items are then passed to
the action handler for the form. The problem is that they are all
passed with the same widget name. ie.

<SELECT NAME="var" MULTIPLE>

Each selected option will arrive at the action handler as:

var=option1
var=option2
var=option3

Each option will overwrite the contents of the previous $var
variable. The solution is to use PHP/FI's non-indexed array
feature. The following should be used:

<SELECT NAME="var[]" MULTIPLE>

This tells PHP/FI to treat var as an array an each
assignment of a value to var[] adds an item to the array. The
first item becomes $var[0], the next $var[1], etc. The count() function can be used to determine how many
options were selected, and the sort()
function can be used to sort the option array if necessary.

When submitting a form, it is possible to use an image instead
of the standard submit button with a tag like:

<input type=image src=image.gif name=sub>

When the user clicks somewhere on the image, the accompanying
form will be transmitted to the server with two additional
variables, sub_x and sub_y. These contain the
coordinates of the user click within the image. The experienced
may note that the actual variable names sent by the browser
contains a period rather than an underscore, but PHP converts the
period to an underscore automatically.

PHP supports the GD
library version 1.2 written by Thomas Boutell. There is no GD
code in PHP itself. If you wish to use the GD support in PHP/FI,
you must obtain the GD library from http://www.boutell.com/gd/http/gd1.3.tar.gz,
install it, and then re-install PHP.

Not all of the GD features are supported by PHP. For a list of
supported functions see the Alphabetical List of
Functions. All the GD functions start with the word,
Image.

PHP works fine on virtual host setups supported by
some http daemons. The one problem that may occur on such a setup
is related to an inconsistency in the way httpd sets the
SCRIPT_NAME environment variable. Normally it is set to the path
of the current CGI program in relation to the top-level ROOT_DIR
on the httpd server. However, when a virtual domain is used, some
httpd's do not correctly set the SCRIPT_NAME variable as the
relative path from the virtual domain's top level directory as it
should. If the ?config screen gives you an invalid URL error
message, you know that this problem exists on your setup. You
will need to edit the php.h file and set the
VIRTUAL_PATH #define to the path to your php.cgi binary
relative to your top-level directory.

The _URL_ should point to a php html file. The MAX_FILE_SIZE
hidden field must precede the file input field and its value is
the maximum filesize accepted. The value is in bytes. In this
destination file, the following variables will be defined upon a
successful upload:

$userfile

The temporary filename in which the uploaded file was
stored on the server machine.

$userfile_name

The original name of the file on the sender's system.

$userfile_size

The size of the uploaded file in bytes.

$userfile_type

The mime type of the file if the browser provided this
information. An example would be "image/gif".

The $userfile basename of the above
variables will match the NAME field in the upload form.

Files will by default be stored in the server's default
temporary directory. This can be changed by setting the
environment variable TMPDIR in the environment in which PHP/FI
runs. Setting it using a PutEnv() call from within a PHP/FI
script will not work though. Alternatively, you may hard-code in
a temporary directory by editing php.h and defining the
UPLOAD_TMPDIR variable.

The PHP/FI script which receives the uploaded file should
implement whatever logic is necessary for determining what should
be done with the uploaded file. You can for example use the
$file_size variable to throw away any files that are either too
small or too big. You could use the $file_type variable to throw
away any files that didn't match a certain type criteria.
Whatever the logic, you should either delete the file from the
temporary directory or move it elsewhere.

Please note that the CERN httpd seems to strip off everything
starting at the first whitespace in the content-type mime header
it gets from the client. As long as this is the case, CERN httpd
will not support the file upload feature.

PHP/FI transparently supports HTTP cookies as defined by
Netscape's
Spec. Cookies are a mechanism for storing data in the remote
browser and thus tracking or identifying return users. You can
set cookies using the SetCookie()
function. Cookies are part of the HTTP header, so the SetCookie()
function must be called before any output is sent to the browser.
This is the same restriction as for the Header() function.

Any cookies sent to you from the client will automatically be
turned into a PHP/FI variable just like GET and POST method
data.

If you wish to assign multiple values to a single cookie, just
add [] to the cookie name. For example:

SetCookie("MyCookie[]","Rasmus Lerdorf", time()+3600);

Note that a cookie will replace a previous cookie by the same
name in your browser unless the path or domain is different. So,
for a shopping cart application you may want to keep a counter and
pass this along. ie.

In addition to these functions, PHP/FI can also be compiled to
automatically escape any forward single quote ( ' ) characters
found in GET or POST data. If the MAGIC_QUOTES variable is
defined in the php.h file then these quotes will be
automatically escaped making it easier to pass form data directly
to msql queries.

Postgres95/PostgreSQL is a powerful public domain database
that implements a significant subset of the SQL language. It
supports many datatypes and commands that are not available in
mSQL. More information about Postgres and the software itself can
be found at this URL: http://www.postgreSQL.org/.

In addition to these functions, PHP/FI can also be compiled to
automatically escape any forward single quote ( ' ) and double
quote ( " ) characters found in GET or POST data. If the
MAGIC_QUOTES variable is defined in the php.h file then
these quotes will be automatically escaped making it easier to
pass form data directly to Postgres queries.

Here is a sample script that connects to Postgres database on
localhost called 'mydb' and retrieves the names and ages of
people in a table:

In addition to these functions, PHP/FI can also be compiled to
automatically escape any forward single quote ( ' ) characters
found in GET or POST data. If the MAGIC_QUOTES variable is
defined in the php.h file then these quotes will be
automatically escaped making it easier to pass form data directly
to mysql queries.

The Solid server is a high-volume SQL server. It supports the
ANSI SQL2, ODBC, SAG CLI and X/Open SQL standards. More
information about the Solid server is available at www.solidtech.com. The Solid
interface to PHP was developed by DigiFace Internet Services.

In addition to these functions, PHP/FI can also be compiled to
automatically escape any forward single quote ( ' ) characters
found in GET or POST data. If the MAGIC_QUOTES variable is
defined in the php.h file then these quotes will be
automatically escaped making it easier to pass form data directly
to Solid queries.

Here is the same script that was shown in the Postgres
section, adapted for the Solid server.

Illustra is a commercial database sold by Informix. It has
several features that are not fully supported by this interface
(yet). The main claim to fame for Illustra is that it is an
object-relational database capable of being extended in an
object-orientated fashion. For example, it is possible to have an
Image as a base type within the database. More information can be
obtained from The illustra
home page.

Adabas D is an advanced RDBMS that is available on many
platforms. A special version, the so called Personal Edition is
available for Linux and Win32 at no cost. It is resticted to 5
simulataneous users and 100 MB of data. For more information on
Adabas D refer to http://www.softwareag.com.

The following PHP functions are available for accessing Adabas
databases:

Regular expressions are used for complex string manipulation
in PHP/FI. The script interface to the regular expression support
is through the following functions: EReg(),
ERegi(), EReg_Replace(), ERegi_Replace(), Reg_Match(), Reg_Replace(), and Reg_Search(). The first argument to all three
functions is a regular expression string. The EReg functions use
the Posix Extended regular expressions as defined by POSIX
1003.2, while the Reg functions implement Basic regular
expressions. For a complete description of regular expressions
see your regex(7) man page. If you do not have this page, the
regex(7) man page written by Henry Spencer can be found in the
src/regex directory in the PHP/FI distribution. Ask your system
administrator to install this man page for you.

Some examples of regular expressions and what they do:

ereg("abc",$string);

Returns true if "abc" is found anywhere in $string.

ereg("^abc",$string);

Returns true if "abc" is found at the beginning of
$string.

ereg("abc$",$string);

Returns true if "abc" is found at the end of
$string.

eregi("(ozilla.[23]|MSIE.3)",$HTTP_USER_AGENT);

Returns true if client browser is Netscape 2, 3 or MSIE
3.

ereg("([[:alnum:]]+) ([[:alnum:]]+)
([[:alnum:]]+)",$string,$regs);

Places three space separated words into $regs[1],
$regs[2] and $regs[3].

A couple of functions in the PHP/FI script language epxect
octal arguments to denote Unix-style permission parameters. In
this octal notation 3 bits are used to represent the values 0-7.
Each bit of the three represents a specific permission. Octal is
traditionally noted in some contexts by a leading 0, such as
0755. You do not need to use this leading 0 in PHP since the
functions that expect octal parameters are will simplyassume that
the parameter is octal. Using the leading 0 is however good
practise to remind yourself that you are no longer dealing with a
base 10 value.

The PHP script language is similar in syntax to the C language
in many ways. It supports variables, arrays, function calls,
different variable types and most things you might need to write
complex cgi programs.

Each PHP/FI function is described in the following section and
can be quickly found by simply appending #function_name to the
url for this document since each function description has been
tagged with its name.

Each PHP instruction starts with <? and
ends with a >. Or, instructions may be
grouped inside a single <? > pair and
separated by ; characters.

Variables are supported and are indicated by preceding the
variable name with a $. So, for example, to set
a variable to 5 and then display this variable, the following is
valid:

<?$a = 5>
<?echo $a>

This is the same as writing:

<? $a = 5; echo $a >

Or even:

<?
$a = 5;
echo $a;
>

Extra white space characters such as spaces, tabs and
new-lines are ignored. This fact should be used to format the PHP
script blocks to make them easier to read. Case is relevant in
variable names, but not in function calls. In the functional
overview later on in this documentation, case is only used to
make the function names easier to read. In the actual script
language you can use any case you wish.

Comments are supported. A comment is written just like
comments in the C language. /* starts a comment
and */ ends a comment. Comments can be placed
anywhere within the <? ... > block.

Three types of variables are supported. Long
integer, Double precision floating
point and character strings. They are
automatically detected. For example:

<?$a = 5>

causes $a to become a variable of type INTEGER.

<?$a = 5.0>

causes $a to become a variable of type DOUBLE.

<?$a = "5">

causes $a to become a variable of type STRING.

The type of the variable is not generally important. Every
variable regardless of its type is converted to all three types
internally and the various functions will try to use the correct
type. There are only a few functions affected by the type of the
variable.

All three variable types may also be treated as arrays by
appending [value] to their names. Unlike C,
these are actually associative arrays similar to those used in
Perl. The following would be valid:

<?
$a[0] = 5;
$a["hello"] = 6;
echo $a[0];
echo $a["hello"];
>

Note that if a variable is used both as an array and as a
normal variable, the normal variable is synonymous with the index
"0" entry in the array. ie.

$a = 1;

Is the same as writing:

$a[0] = 1;

PHP/FI also supports non-indexed arrays. A non-indexed array
will generate its own index as items are added to it. For
example:

$a[] = "Hello";
$a[] = "There";

The first item inserted into a non-indexed array always gets
assigned index 0, the second index 1, etc. Therefore the above
items may be printed out with:

echo $a[0];
echo $a[1];

Arrays can be copied by a simple assignment. If $b is an
array, then all the values can be copied to a new array named $a
with:

$a = $b;

Please not that if PHP does not force you to define variables
before using them. If in the above statement, $b was undefined,
then $a would be set to an empty string ("").

The [] notation is also used to indicate that arrays are to be
appended. If $a and $b are both arrays, then $b can be appended
to $a by:

$a[] = $b;

In the above, there will be a difference between associative
arrays and normal numbered arrays. Numbered arrays will be
renumbered such that all elements from $b will come after the
original elements from $a. While with associative arrays,
elements in $b will be merged with elements in $a. Any elements
(items with the same index name) which already exist in $a will
be overwritten by $b elements.

You can use the count() function to
determine the number of items in any array.

Also inherent to the language is the fact that the type of the
variable determines how certain basic operations will be carried
out. For example:

$a = $b + $c;

can do a couple of different things. If $b is a number, the
numerical value of $c is added to $b and the sum is stored in $a.
In this case the type of $c is irrelevant. The operation is
guided by the type of the first variable. If $b is a string, then
the string value of $c is appended to $b and the resultant string
is placed in $a. This also leads to some caveats. You should read
the section on overloaded operators to
get a better understanding of how to deal with them.

The previous section introduced associative arrays. An
associative array is an array in which the index need not be a
numerically sequential value. The array index can be any number
or string. PHP/FI provides a set of functions to manipulate these
associative arrays. These include, Next(),
Prev(),Reset(),End(), and Key().

As far as language constructs are concerned, the PHP language
is quite simple. The following commands are used to guide the
control flow through a file:

if (condition)

else

elseif (condition)

endif

switch(expression)

case expression

default

break

endswitch

while

endwhile

include

exit

The syntax of conditions are similar to that of the C
language. == tests for equality.
!= means not equal. Also supported are:
>, <,
>=, <=. Conditional AND
is &&, conditional OR is
||.

Examples:

<?
if($a==5 && $b!=0 );
$c = 100 + $a / $b;
endif;
>

The above may also be written in standard C syntax:
In this case, there is no need for a semicolon after the closing
curly brace.

<?
if($a==5 && $b!=0) {
$c = 100 + $a / $b;
}
>

There is no difference between the two syntaxes. I personally
like to use endif, endswitch and endwhile so I explicitly know
which construct I am ending. However, these ending constructs can
always be replaced with a closing curly brace.

It is important to note that the flow of the language is not
dependent on the organization of the script blocks within the
code. You can start an if expression in one block and have the
end of the expression in another. For example:

<?if($a==5 && $b!=0)>
<b>Normal html text</b>
<?endif>

In this example it is easy to see why it is sometimes more
desirable to use the endif keyword as opposed to a
closing brace. The above is much more readable than the
following:

You may define a function within a PHP script with the
following syntax:

<?
Function Test (
echo "This is a test\n";
);
>

This function can now be called from anywhere in the script as
long as the call comes after the function definition. A sample
call might be:

<?
Test();
>

User defined functions like this act exactly like PHP's
internal functions in that you can pass arguments to them and
have them return a value. Here is the syntax for a function
definition of a function which takes 3 arguments and returns the
sum of these arguments:

<?
Function Sum $a,$b,$c (
return($a+$b+$c);
);
echo Sum($a,$b,$c);
>

The return statement is used to return a value from
the function. Only a single value can be returned using this
mechanism, however, if more values need to be communicated back
and forth between the main code and functions, global variables
can be used. This brings us to the section on the scope of
variables.

The scope of a variable is the context within which it is
defined. For the most part all PHP/FI variables only have a
single scope. However, within user-defined functions a local
function scope is introduced. Any variable used inside a function
is by default limited to the local function scope. For
example:

This script will not produce any output because the
echo statement refers to a local version of the
$a variable, and it has not been assigned a value within
this scope. You may notice that this is a little bit different
from the C language in that global variables in C are
automatically available to functions unless specifically
overridden by a local definition. This can cause some problems in
that people may inadvertently change a global variable. In PHP/FI
global variables must be declared global inside a function if
they are going to be used in that function. An example:

The above script will output "3". By declaring $a and $b
global within the function, all references to either variable
will refer to the global version. There is no limit to the number
of global variables that can be manipulated by a function.
However, the variable must exist in the global scope prior to the
function being called. You cannot create new global variables
from within a function.

Another important feature of variable scoping is the
static variable. A static variable exists only in a
local function scope, but it does not lose its value when program
execution leaves this scope. Consider the following example:

Function Test (
$a=0;
echo $a;
$a++;
);

This function is quite useless since every time it is called
it sets $a to 0 and prints "0". The $a++ which increments the
variable serves no purpose since as soon as the function exits
the $a variable disappears. To make a useful counting function
which will not lose track of the current count, the $a variable
is declared static:

Function Test (
static $a=0;
echo $a;
$a++;
);

Now, every time the Test() function is called it will print
the value of $a and increment it.

Static variables are also essential when functions are called
recursively. A recursive function is one which calls itself. Care
must be taken when writing a recursive function because it is
possible to make it recurse indefinitely. You must make sure you
have an adequate way of terminating the recursion. The following
simple function recursively counts to 10:

You can loop within a PHP script by using the while();
endwhile; construct.

<?
$a=0;
while($a<100) {
$a++;
echo $list[$a];
}
>

The above example shows the use of a while loop to display the
contents of an array. WARNING although the PHP
language supports incremental operators such as
++ and -<!>- to increment
and decrement a variable, they are not treated exactly like they
would be in the C language. The variable is incremented right
away. There is no concept of incrementing the variable before or
after the operation as there is in C.

As explained in the Language Constructs
section above, the same can be obtained with while();
endwhile;.

The above is an example of a switch construct. It is similar
to a series of if/elseif/else constructs but easier to read. The
only difference between the PHP switch construct and that of the
C language is that semi-colons are used to terminate every line.
There are no colons.

As explained in the Language Constructs
section above, the same can be obtained with switch();
endswitch;.

All of these constructs can of course be nested and used
inside each other just like C. The various files in the
examples directory of the PHP distribution should
provide a good starting point for learning the language.

A previous section talked about GET and POST method data and
variables. If you think about it, you may be able to envision a
security issue. For example, if on a web page I have obtained
some data from a database and I pass this data along in a
variable called "data" in a POST method form. In the ensuing page
I can access this variable and do something with it. However, if
someone accessed this second page directly and put a
"?data=something" right in the URL thereby doing a GET method
variable set, they have effectively circumvented the original
POST method form.

PHP provides a SecureVar() function which is used to
mark variables names as being secure variables. These secure
variables can only be set directly in a PHP script, or they can
come from a POST method form. They cannot be set using the GET
method variable definition mechanism. From our above scenario, if
we placed the line:

<?SecureVar("data")>

Near the beginning of our second page, then the GET method
trick would not work. The "data" variable would appear to be
empty unless it came directly from the POST method form on the
first page.

The SecureVar() actually takes a regular expression
as its argument, so you can mark patterns of variable names that
should be treated in this secure manner. For example,

<?SecureVar(".*data.*")>

Would mark any variable with the word "data" anywhere in their
name as being secure.

Please note that POST-method forms are not intrinsically
secure. People can emulate the posting of any data to a form by
simply telnetting to the HTTP port on your system. You need to
take appropriate security measures to stop people from doing this
if in fact security is a concern.

The parser looks at the first part of the arithmetic
expression and uses that to type the result and thus also the
nature of the arithmetic that is to be done. In the above case
since $a is an integer, $d will be an integer and an integer
addition is done giving the result:

$d = 2 Type is integer

Therefore:

$d = $c + $a

Results in:

$d = "11" Type is string

The above makes sense to me, and once you understand it, it is
probably workable. However, when more complex expressions are
used it can get extremely confusing.

The solution is a simple type casting mechanism. In reality
all variables are automatically converted to all 3 types, and an
internal flag just marks what type the variable actually is. So,
when I say:

$a = 1;

Internally in the symbol table I store 3 versions.

Integer: 1 <-- flag
Double : 1.0
String : "1"

The SetType() function can move this flag indicating
the type of the variable.

SetType($a,"double");

This would force $a to be treated as a double from then
on.

The GetType() function returns the type.
GetType($a) would return "double" in this case.

Functions also exist to return the 3 various types without
moving the type flag.

IntVal($a) returns 1
DoubleVal($a) returns 1.0
StrVal($a) returns "1"

This doesn't change the overloaded operator nature of the PHP
variables, but it does give you some tools to better deal with
them. PHP is not not a full-fledged Perl look-alike. It has to be
small and fast. Perl deals with the overloaded operator pitfall
by forcing something like the '+' operator to only work on
numbers. If you want to add strings, you must use the '.'
operator. Once you start having separate operators for each type
you start making the language much more complex. ie. you can't
use '==' for stings, you now would use 'eq'. I don't see the
point, especially for something like PHP where most of the
scripts will be rather simple and in most cases written by
non-programmers who want a language with a basic logical syntax
that doesn't have too high a learning curve.

It may be desirable in certain circumstances to ignore fatal
errors which may be reported by specific PHP functions. For
example, you may want to ignore errors from a dbmopen() call and
simply check the return value of the call without having error
messages appear on the web screen. This can be done by putting
the "@" character in front of the function call. ie.

$err_code = @dbmopen($filename,"w");

The actual error message that would have been printed can be
checked by looking at the PHP internal variable,
$phperrmsg.

A more general approach to suppress error message printing is
to use the SetErrorReporting()
function. With this function error printing can be disabled for
entire blocks of code by preceding the block with a call
like:

PHP has a number of built-in functions. Functions are called
in the same manner as they are called in the C language. Some
take one or more arguments, and some return values which can then
be assigned to a variable or used as an argument to another
function. For example:

<?$t=time()>

This assigns the return value of the time() function
to the t variable.

Ada_Connect opens a connection to a Adabas server. Each of
the arguments should be a quoted string. The first parameter
(data source name) is a string in the form
"servername:databasename". The servername (but not the colon)
can be omitted if you want to access a local database. This
function returns a connection_id. This identifier is needed
by other Adabas functions. You can have multiple connections
open at once. This function will return 0 on
error.

This function is only available if Adabas support has been
enabled in PHP.

Ada_Exec will send an SQL statement to the Adabas server
specified by the connection_id. The connection_id must be a
valid identifier that was returned by Ada_Connect or the
special value 0. If connection_id is 0,
ada_exec tries to establish or to use a connection with the
parameters given with the configuration
directivesphpAdaDefDB, phpAdaUser and
phpAdaPW.
The return value of this function is an identifier to be used
to access the results by other Adabas functions. This
function will return 0 on error. It will
return 1 when the command executed correctly
but is not expected to return data (insert or update
commands, for example). Note that selects which return no
data will still return a valid result greater than 1.

This function is only available if Adabas support has been
enabled in PHP.

Ada_FetchRow fetches a row of the data that was returned
by Ada_Exec. After Ada_FetchRow is called, the fields of that
row can be access with Ada_Result. If no rownumber is given,
Ada_FetchRow will try to fetch the next row in the result
set. Every time Ada_FetchRow is called a new row can be
accessed by Ada_Result. If Ada_FetchRow was succesful (there
was a row), 1 is returned, if there are no
more rows, Ada_FetchRow will return 0. The
return value of Ada_FetchRow can be used as the condition of
a while loop. Calls to Ada_FetchRow() with and without
rownumber can be mixed. To step through the result more than
once, you can call Ada_FetchRow() with rownumber 1 and then
continue with Ada_FetchRow() without rownumber to review the
result.

This function is only available if Adabas support has been
enabled in PHP.

Ada_FreeResult only needs to be called if you are worried
about using too much memory while your script is running. All
result memory will automatically be freed when the script is
finished. But, if you are sure you are not going to need the
result data anymore in a script, you may call Ada_FreeResult
with the result identifier as an argument and the associated
result memory will be freed.

This function is only available if Adabas support has been
enabled in PHP.

Ada_NumRows will return the number of rows in a Adabas
result. The argument is a valid result identifier returned by
Ada_Exec. This function will return -1 on
error. For INSERT, UPDATE, DELETE statements Ada_NumRows()
returns the number of rows affected. For a SELECT clause this
is the number of rows available.

This function is only available if Adabas support has been
enabled in PHP.

Ada_Result will return values from a result identifier
produced by Ada_Exec. The field name specify what cell in the
row to return. Instead of naming the field, you may use the
field index as an unquoted number. Field indices start from
0. If the requested field is of code type BYTE (binary) or is
longer than 4096 bytes, the contents is sent directly to the
client. Hint: [VAR]CHAR BYTE fields can be returned into a
php variable by using the HEX() db function; e. g. SELECT
HEX(SYSKEY) SYSKEY FROM MYTABLE.

This function is only available if Adabas support has been
enabled in PHP.

Ada_ResultAll will print all rows from a result identifier
produced by Ada_Exec. The result is printed in HTML table
format. With the optional formatstring additional overall
table formatting can be done (e. g. bgcolor= will set
background color, >caption> </caption to set
caption). Note: The contents of "format" will be inserted
into the HTML table tag like this <table format
>...

This function is only available if Adabas support has been
enabled in PHP.

Sort is used to sort a PHP associative array in ascending
order. Use ARSort() for descending order. Unlike the Sort() function, ASort() maintains index-value
pairings. It understands the three variable types and will
sort alphabetically if the array contains strings, and
numerically if the array contains numbers. In the case of an
array which contains a mixture of types, the first type in
the array will specify the sort method. Note that if you are
going to sort a non-associative array, you should use the
Sort() function.

BinDec returns the decimal equivalent of the binary number
represented by the binary_string argument. The largest number
that can be converted is 31 bits long or 4294967295 in
decimal. See also the DecBin()
function.

Ceil() rounds a floating point value up to the next
integer. The return value is of type double (floating point)
such that it can be used properly in complex equations. To
get an integer type back, use: $new =
IntVal(Ceil($value));
See also Floor().

The ClearStack() function is a hack/workaround for a
deficiency in the PHP parser. This dificiency is that PHP
only has a single expression stack. When inside a
user-defined function this expression stack is never cleared
because its contents may be needed within a complex
expression in the context from which the user-defined
function was called. This means that if you have a while loop
with a lot of iterations inside a user-defined function, you
may be chewing up a lot of stack space. You may even be
hitting the max data space limit. You can put a call to
ClearStack() inside your while loop to prevent this memory
consumption, but the trade-off is that you cannot use your
function within any sort of context. ie. you have to assign
the output of the function to a temporary variable and then
use this temporary variable in whatever context you need.

The stat() system call is normally an expensive operation
on most operating systems. In order to make sure that
repeated calls to the various File* functions like FilePerms(), FileInode(), etc. the result of the last
stat() call is always cached. If one of the File* functions
is called again with the same argument, the cached stat()
result will be used. In order to force a new stat() system
call this ClearStatCache() function may be called to clear
the cached stat() result.

Count returns the number of items in an array variable. If
the variable is not an array, the return value will be 1
(because a normal variable is similar to an array with only
one item). If the variable is not defined, the return value
will be 0.

Crypt will encrypt a string using the standard Unix DES
encryption method. Arguments are a string to be encrypted and
an optional two-character salt string to base the encryption
on. See the Unix man page for your crypt function for more
information. If you do not have a crypt function on your Unix
system, you can use Michael Glad's public domain UFC-Crypt
package which was developed in Denmark and hence not
restricted by US export laws as long as you ftp it from an
non-US site.

The Date function is used to display times and dates in
various ways. The function takes a format string and a time
as arguments. If the time argument is left off, the current
time and date will be used. The time argument is specified as
an integer in number of seconds since the Unix Epoch on Jan.1
1970. The format string is used to indicate which date/time
components should be displayed and how they should be
formatted. The following characters are recognized within the
format string. Any unrecognized character is printed
verbosely:

dbmFirstKey returns the first key in the dbm file. Note
that no particular order is guaranteed since the order
depends on hash table values calculated within the dbm
implementation. You may use the Sort
function to sort arrays of data from the dbm file if
necessary.

dbmOpen() opens a dbm file. The first argument is the
full-path filename of the dbm file to be opened and the
second is the file open mode which is one of "r",
"n" or "w" for read, new (implies write) and
write respectively. If ndbm support is used, ndbm will
actually create filename.dir and
filename.pag files. gdbm only uses one file, as does
the internal flat ascii file support, and Berkeley's libdb
create a filename.db file. Note that PHP does its
own file locking in addition to any file locking that may be
done by the dbm library itself. PHP does not delete the
.lck files it creates. It uses these files simply as
fixed inodes on which to do the file locking. For more
information on dbm files, see your Unix man pages, or obtain
GNU's gdbm from ftp://prep.ai.mit.edu/pub/gnu.

DecBin returns a string containing a binary representation
of the given number argument. The largest number that can be
converted is 31 bits long or 4294967295 in decimal. See also
the BinDec() function.

Echo is not a function. ie. you do not put brackets around
the arguments to it. It is used to display results of PHP
functions or PHP variables. See the Escape
Character Section for a list of special characters
supported. The format_string is optional and if not present,
no output formatting will be done. The format string is
similar to the format string of the C printf
function. See the man page for printf for more
details. Up to 5 expressions can be printed with a single
echo command. If you try to print more you will get a parser
error. Note that the types of the expressions are not
relevant. The expressions are automagically converted to the
appropriate types as specified by the format string if one is
present. If you want to format something and assign the
formatted string to a variable instead of displaying it, use
the sprintf() function.

The following conversions are supported,

%d %i

Print a signed decimal number.

%o

Print an octal number.

%u

Print an unsigned decimal number.

%x %X

Print a hexadecimal number.

%f

Print a floating-point number.

%e %E

Print a floating-point number in scientific
notation.

%g %G

Print a floating-point number in scientific notation
or normal notation, as appropriate.

%c

Print a single character.

%s

Print a string of characters.

%%

Print a literal percent-sign.

The following flags are accepted.

'-'

Left-justify the output within the field-width.

'+'

Ensure that all integers are signed (with a
plus/minus sign).

' '

Similar to '+', but uses a space instead of a
plus-sign.

'#'

Print prefixes in front of hex and octal numbers
designating them as such.

'''

Separate the digits into groups (usually
comma-separated groups of three).

'0'

Pad the field-width with zeros.

All of these flags are dependent upon whether or not
your C library's printf function supports them (the ''',
for example, is a GNU extension).

Most conversions will accept a field width and a
precision, as shown in the demo_echo.html file in
the directory /examples. It is not necessary to specify any
type modifiers, and, in fact, PHP will complain if the type
modifier does not make sense (which is almost always the
case). PHP will complain about (and refuse to accept)
anything that it does not recognize. Any extra arguments
given that are not required by the format-string are
ignored.

End moves the internal array pointer for the given
variable to the last item of the array and returns the value
of this item. This is useful for traversing an associative
array in reverse order. See also Reset()
and Prev(). The following example would
traverse an associative array in reverse order:

ereg returns non-zero if the regular expression is matched
in the argument string. For example, the condition,
<?if (ereg("^This.*", "This is an example
string")> would be true since the "^This.*"
expression says to match the word This at
the beginning of the string and then match any characters
afterwards. If the regs argument is present, then
match registers are filled into positions 0-10 in the array
named by the regs argument. Register 0 will always
contain the full matched string. For more information on
regular expressions, see the regular
expression section of this document.

ereg_Replace scans the entire argument string and replaces
any portions of the string matched by the given expression
with the replacement string. For example, in the string,
"This is an example string" we could very easily
replace every space with a dash with the command:
ereg_replace(" ","-","This is an example
string").For more information on regular
expressions, see the regular expression
section of this document.

EscapeShellCmd escapes any characters in a string that
might be used to trick a shell command into executing
arbitrary commands. This function should be used to make sure
that any data coming from user input is escaped before this
data is passed to the Exec() or System() functions. A standard use would
be:

Eval takes the contents of the string argument and treats
it like a mini PHP/FI script. It will execute it as a
separate PHP/FI script. Any variables set or accessed from
inside the eval will be from the global reference frame in
the current context of the eval statement in the script.
Variable substitution is done on the string arguments, so if
variables are to be used in the string expression they should
be escaped. Some examples:

Exec executes the given unix command, however it does not
output anything. It simply returns the last line from the
result of the command. If you need to execute a command and
have all the data from the command passed directly back
without any interference, use the PassThru() function. If the array argument is
present, then the specified array will be filled with every
line of output from the unix command starting at the end of
the array. Make sure you UnSet the array
before the call if your array already contains elements and
you want to start filling it at array element 0. If the
return_var argument is present along with the array argument,
then the return status of the executed unix command will be
written to this variable. Note that if you are going to allow
data coming from user input to be passed to this Exec
function, then you should be using the EscapeShellCmd() function to make sure
that users cannot trick the system into executing arbitrary
commands. See also the system()
function.

fgets() reads a line from a file opened by fopen(). Arguments are a file pointer index as
returned by fopen() and the max number of bytes to read.
Reading ends when max number of bytes have been read, or on
an end of line. This is similar to the C fgets() call. See
also fputs().

fileAtime returns the time of last data access. If the
file does not exist, or if it for some other reason could not
be accessed, this function returns -1. If repeated calls to
fileAtime and the rest ofthe file* functions are to be made
and the file being accessed might change or disappear, the
ClearStatCache() should be
called before the call to the file* function.

fileCtime returns the time of last status change. If the
file does not exist, or if it for some other reason could not
be accessed, this function returns -1. If repeated calls to
fileCtime and the rest ofthe file* functions are to be made
and the file being accessed might change or disappear, the
ClearStatCache() should be
called before the call to the file* function.

fileGroup returns the group id of the owner of the file.
If the file does not exist, or if it for some other reason
could not be accessed, this function returns -1. If repeated
calls to fileGroup and the rest ofthe file* functions are to
be made and the file being accessed might change or
disappear, the ClearStatCache()
should be called before the call to the file* function.

fileInode returns the file's inode. If the file does not
exist, or if it for some other reason could not be accessed,
this function returns -1. If repeated calls to fileInode and
the rest ofthe file* functions are to be made and the file
being accessed might change or disappear, the ClearStatCache() should be called
before the call to the file* function.

fileMtime returns the time of last data modification. If
the file does not exist, or if it for some other reason could
not be accessed, this function returns -1. If repeated calls
to fileMtime and the rest ofthe file* functions are to be
made and the file being accessed might change or disappear,
the ClearStatCache() should be
called before the call to the file* function.

fileOwner returns the uid of the owner of the file. If the
file does not exist, or if it for some other reason could not
be accessed, this function returns -1. If repeated calls to
fileOwner and the rest ofthe file* functions are to be made
and the file being accessed might change or disappear, the
ClearStatCache() should be
called before the call to the file* function.

filePerms returns the permission bits of the file. This is
the st_mode field of the Unix C stat structure. If
the file does not exist, or if it for some other reason could
not be accessed, this function returns -1. If repeated calls
to filePerms and the rest ofthe file* functions are to be
made and the file being accessed might change or disappear,
the ClearStatCache() should be
called before the call to the file* function.

fileSize returns the size of the file in bytes. If the
file does not exist, or if it for some other reason could not
be accessed, this function returns -1. If repeated calls to
fileSize and the rest ofthe file* functions are to be made
and the file being accessed might change or disappear, the
ClearStatCache() should be
called before the call to the file* function.

fileType returns the type of the file. The return values
are one of: "dir", "file","fifo","char", "block", or "link".
These are for, directory, regular file, fifo special,
character special, block special and symbolic link,
respectively.

Floor() rounds a floating point value down to the previous
integer. The return value is of type double (floating point)
such that it can be used properly in complex equations. To
get an integer type back, use: $new =
IntVal(Floor($value));
See also Ceil().

The Flush() function is used to Flush the output buffer.
For the Apache module, it flushes Apache's output buffer, and
for the CGI version it simply flushes stdout. When running as
a CGI under Apache, the server will buffer the CGI script's
output, so this Flush() function won't help much there. Look
at running your script as an nph- script if you are running
the CGI version of PHP under the Apache web server. Or,
alternatively, run the Apache module version of PHP.

fopen() opens a file and returns a file pointer index. If
the file could not be opened the function returns -1. It is
similar to the C fopen() call. The filename argument is the
relative or absolute path to the file to be opened, and the
mode argument is one of, "r", "r+", "w", "w+", "a", "a+". See
the Unix man page on the fopen() call for more information.
See also the popen() function
description. See also the fclose()
function description.

fputs() writes a line to a file opened by fopen(). Arguments are a file pointer index as
returned by fopen() and the string to write. Note that the
string argument may contain the special escape characters,
\n, \r and
\t to output newlines, carriage returns and
tabs respectively. See also fgets().

FPassThru() outputs all remaining data on fp
directly. It is different from ReadFile() in that it can also handle files
opened with fsockopen(). It differs
from PassThru() in that it does not
handle commands, but opened files. FPassThru() returns the
number of bytes read and written.

fseek() positions a file pointer identified by the $fd
argument which is the return value of the fopen() call. The file pointer is positioned at
the beginning of the file plus the offset specified by the
pos argument. See also ftell() and rewind().

fsockopen() opens a socket connection and returns a file
pointer index. This file pointer index can be used by
fgets, fputs and
fclose. Arguments are a hostname and a
port number. Return values are: -3 if the socket couldn't be
created, -4 if the dns lookup on the hostname failed, -5 if
the connection was refused or it timed out, -6 if the actual
fdopen() call failed or -7 if the setvbuf() call failed. If
the port number is 0, then the hostname argument will be
treated as a filename of a Unix domain socket if your
operating system support Unix domain sockets.

ftell() returns the position of a file pointer identified
by the fp argument which is the return value of the fopen() call. The position can later be used as
an argument to fseek(). See also fseek()
and rewind().

GetEnv returns the value of the environment value
specified by string. Normally this function is not
used because environment variables are available to PHP/FI
directly. If a reference is made to a variable which is not
found in the internal symbol table, then the environment
space is automatically searched. GetEnv should be used when
it is necessary to ensure that an environment variable has
not been overwritten by normal PHP/FI variable. Security
mechanisms that rely on http server-defined variables like
REMOTE_ADDR and REMOTE_HOST should load these variables using
GetEnv as opposed to referencing them directly as
$REMOTE_ADDR to avoid someone making up a fake form and
posting the data to your server and thereby bypassing
whatever security mechanism you might have.

The GetImageSize() function takes either a full path
filename, or a relative path relative to the location of the
calling script. It returns a 3 element array consisting of
width, height and type. Width and height are in pixels, and a
type of 1 means GIF, a 2 indicates a JPG file and a 3
indicates a PNG file. Other file types are not supported. The
fourth element in the returned array is a string containing,
"width=x height=y" that is suitable for using directly in an
IMG tag. It is important to note that the GD image library is
not needed to use this function. An example follows:

getLastAccess returns the date and time in unix time
format of the last time the current page was access. This
value can be passed to the Date()
function for formatting.
This function is only available if PHP was compiled with
Access Logging enabled.

getLastMod returns the date and time in unix time format
of the last time the current page was modified. This value
can be passed to the Date() function for
formatting.
This function is only available if PHP was compiled with
Access Logging enabled.

getLogDir returns the top-level directory under which PHP
log files can be found. The actual log files are in
directories under this directory. Each subdirectory is the
numerical user id of the user to whom the log files belong.
Then within each directory a series of dbm log files are
found, each with the numerical inode of the file they
represent as the primary component of the filename.

getRandMax returns the maximum random number the Rand function will return. If the value returned
does not seem to be accurate, have a look in the php.h source
file in the PHP distribution for more information.

getStartLogging returns the time and date in Unix time
format when logging commenced on the current page. This is
more accurate when mSQL-based logging is used since a
timestamp is kept in each log file. For dbm-logging the time
returned is the time the user's log directory was
created.

The Header command is used at the top of an HTML file to
send raw HTTP header strings. See the HTTP
Specification for more information on raw http headers.
Remember that the Header() command must be used before any
actual output is sent either by normal HTML tags or by PHP
echo commands.
Usage examples can be found in the HTTP
Authentication section.

HtmlSpecialChars converts any characters with ascii codes
in the string argument between 160 and 255 inclusive to their
corresponding HTML Entity names. The function returns the
converted string. The <, >, &
and " are also converted.

ImageArc draws a partial ellipse centered at cx,cy (top
left is 0,0) in the image represented by im. w and h specifies the ellipse's width
and height respectively while the start and end points are
specified in degrees indicated by the s and e
arguments.
This function is only available if GD support has been
enabled in PHP.

ImageChar draws the character c in the image identified by
im at coordinates x,y (top left is
0,0) in colour col. The size argument can be 1, 2, 3, 4 or 5
indicating the size of the font to be used. 1 is the smallest
and 5 is the largest.
This function is only available if GD support has been
enabled in PHP.

ImageCharUp draws the character c vertically in the image
identified by im at coordinates
x,y (top left is 0,0) in colour col. The size argument can be
1, 2, 3, 4 or 5 indicating the size of the font to be used. 1
is the smallest and 5 is the largest.
This function is only available if GD support has been
enabled in PHP.

ImageColorAllocate returns a colour identifier
representing the colour composed of the given RGB components.
The im argument is the return from the ImageCreate function. ImageColorAllocate
must be called to create each colour that is to be used in
the image represented by im.
This function is only available if GD support has been
enabled in PHP.

ImageColorTransparent sets the transparent colour in the
im image to col. im is the image identifier returned by
ImageCreate and col is the colour
identifier returned by ImageColorAllocate. This function
is only available if GD support has been enabled in PHP.

ImageCopyResized copies a rectangular portion of one image
to another image. dst_im is the destination image,
src_im is the source image identifier. If the source
and destination coordinates and width and heights differ,
appropriate stretching or shrinking of the image fragment
will be performed. The coordinates refer to the upper left
corner. This function can be used to copy regions within the
same image (if dst_im is the same as
src_im) but if the regions overlap the results will
be unpredictable.
This function is only available if GD support has been
enabled in PHP.

ImageFilledPolygon creates a filled polygon in image
im. points is a PHP array
containing the polygon's vertices. ie. points[0] = x0,
points[1] = y0, points[2] = x1, points[3] = y1, etc.
num_points is the total number of vertices.
This function is only available if GD support has been
enabled in PHP.

ImageFilledRectangle creates a filled rectangle of colour
col in image im starting at upper left coordinate x1,y1 and
ending at bottom right coordinate x2,y2. 0,0 is the top left
corner of the image.
This function is only available if GD support has been
enabled in PHP.

ImageFillToBorder performs a flood fill whose border
colour is defined by border. The starting point for the fill
is x,y (top left is 0,0) and the region is filled with colour
col.
This function is only available if GD support has been
enabled in PHP.

ImageGif creates the GIF file in filename from the image
im. The im argument is the return from the ImageCreate function. The filename
argument is optional, and if left off, the raw image stream
will be returned directly. By sending an image/gif
content-type using the Header()
function, you can create a PHP/FI script which returns GIF
images directly using this function.
This function is only available if GD support has been
enabled in PHP.

ImageInterlace turns the interlace bit on or off. If
interlace is 1 the im image will be interlaced, and if
interlace is 0 the interlace bit is turned off. This
functions is only available if GD support has been enabled in
PHP.

ImagePolygon creates a polygon in image im. points is a PHP array containing the
polygon's vertices. ie. points[0] = x0, points[1] = y0,
points[2] = x1, points[3] = y1, etc. num_points is the total
number of vertices.
This function is only available if GD support has been
enabled in PHP.

ImageRectangle creates a rectangle of colour col in image
im starting at upper left coordinate x1,y1 and ending at
bottom right coordinate x2,y2. 0,0 is the top left corner of
the image.
This function is only available if GD support has been
enabled in PHP.

ImageString draws the string s in the image identified by
im at coordinates x,y (top left is
0,0) in colour col. The size argument can be 1, 2, 3, 4 or 5
indicating the size of the font to be used. 1 is the smallest
and 5 is the largest.
This function is only available if GD support has been
enabled in PHP.

ImageStringUp draws the string s vertically in the image
identified by im at coordinates
x,y (top left is 0,0) in colour col. The size argument can be
1, 2, 3, 4 or 5 indicating the size of the font to be used. 1
is the smallest and 5 is the largest.
This function is only available if GD support has been
enabled in PHP.

The Include command can be used to insert other files into
the current html file. This is extremely handy for headers
and footers which may need to be included in hundreds of HTML
files. By using an include command you then only need to
modify the header or footer file in one place when it needs
to be changed. Since full PHP parsing is done on the included
file, you can also use the include command to include common
PHP scripts you may have written. Sort of like having a
primitive shared library of scripts you can call from your
HTML file. You can place such common library files in one
directory and set PHP's include path and not have to refer to
the files with pathnames. For Apache module users this can be
configured with the phpIncludePath
directive, for CGI users with the PHP_INCLUDE_PATH
environment variable. This path is colon-separated just like
$PATH is in your UNIX shell. eg.

InitSyslog() defines some PHP variables that you need when
using OpenLog() and Syslog(). These variables are not defined
by default for efficiency reasons. The variables are named in
the same way as in the <syslog.h> C include file (such
as $LOG_LOCAL0). See your syslog(3) UNIX manual page for more
details. See also InitSyslog(),
Syslog() and CloseLog().

Key returns the key of the current array item. The current
item is determined by the position of the array pointer for
the given variable. This array pointer may be manipulated
with the Reset(), End(), Next(), and Prev() functions. This function is mainly used
for determining the key value for an item in an associative
array, although it will work for normal array as well.

LinkInfo returns the st_dev field of the UNIX C stat
structure returned by the lstat system call. This function is
used to verify if a link (pointed to by path) really exists
(using the same method as the S_ISLNK macro defined in
stat.h). Returns -1 in case of error.

Max returns the maximum value of a PHP array. ie. it will
search through the entire array looking for the max element.
If it is an array of strings, the returned string is the
string which would be alphabetically last in the array if it
were sorted.

mi_Connect opens a connection to an Illustra database.
Each of the arguments should be a quoted string. This
function returns a connection_id. This identifier is needed
by other Illustra functions. You can have multiple
connections open at once. The host to connect to is governed
by the MI_PARAMS file on the machine running the PHP
executable. No support as yet for remote invocation This
function will return -1 on error.

This function is only available if Illustra support has
been enabled in PHP.

mi_Exec will send an SQL statement to the Illustra
database specified by the connection_id. The connection_id
must be a valid identifier that was returned by mi_Connect.
The return value of this function is an identifier to be used
to access the results from other Illustra functions. This
function will return -1 on error.

This function is only available if Illustra support has
been enabled in PHP.

mi_Result will return values from a result identifier
produced by mi_Exec. The row_number and field name specify
what cell in the table of results to return. Row numbering
starts from 0. Instead of naming the field, you may use the
field index as an unquoted number. Field indices start from
0.

All values returned from the database are in String form,
since no type-detection is available at the present.

This function is only available if Illustra support has
been enabled in PHP.

Microtime() returns a string "msec sec" where sec is
number of seconds since 00:00 GMT, Jan 1, 1970, and msec is
the microseconds part (as fraction of seconds). Ex
"0.87633900 825010464".
This function is only available on operating systems that
support the gettimeofday() system call.

Min returns the minimum value of a PHP array. ie. it will
search through the entire array looking for the min element.
If it is an array of strings, the returned string is the
string which would be alphabetically first in the array if it
were sorted.

MkTime returns a time in Unix timestamp (long integer)
format which corresponds to the date and time specified by
the arguments. Arguments may be left out in which case the
given component is set to the current value according to the
current local time and date. These left out arguments may
only be left out from right to left. ie.
MkTime(hour,min,sec) is valid, but
MkTime(mon,day,year) is not valid. Note that this
function can be very handy as a tool for doing both date
arithmetic and date validation. You can feed it invalid
parameters, such as a month greater than 12, or a day greater
than 31 and it will figure out the right date anyway. It will
also generate an error message if any of the parameters are
outside the normal values. Use the SetErrorReporting(0) function to
turn this error reporting off before calling the function and
you may then check the $phperrmsg for any errors that may
have occurred.

msql sends an mSQL query. Arguments are the database name
and the query string. ie. <?msql("MyDatabase"
, "select * from table")>. The return value
from this function is a result identifier to be used to
access the results from the other msql_ functions. A result
identifier is a positive integer. The function returns
0 when no result identifier is created. This
is the case with any queries that do not return anything,
such as create, update, drop,
insert and delete. The function will return
-1 if an error occurs. A string describing
the error will be placed in $phperrmsg, and unless the
function was called as @msql() then this
error string will also be printed out. For mSQL 2.0, the
$result variable will contain the number of rows affected by
the SQL command performed. If you want your application to be
portable to mSQL 1.0, do not rely on this.
This function is only available if mSQL support has been
enabled in PHP.

msql_Close closes the socket connection to the msql
daemon, if an open connection exists. Note, since only one
concurrent mSQL session can be open at any one time, this
function does not take an argument.

msql_Connect specifies the host name or IP on which the
mSQL database engine resides. This is equivalent to the
msqlConnect() function in the mSQL C API. The one difference
between this function and the C API equivalent is that if the
function isn't called, a connection to the local host is made
by default on the first call to the msql() function. And,
there is no need for an msql_close function since only one
connection may be active at any one time. If a second call to
msql_connect() is made in a file, then the connection to the
first host is automatically closed. To explicitly connect to
the msql daemon on the local host, use:
<?msql_connect("localhost")>
This function is only available if mSQL support has been
enabled in PHP.

msql_dbName returns the database name stored in position
$i of the result pointer returned from the msql_ListDbs() function. The msql_NumRows() function can be used to
determine how many database names are available.
This function is only available if mSQL support has been
enabled in PHP.

msql_FieldFlags returns the field flags of the specified
field. Currently this is either, "not null", "primary key", a
combination of the two or "" (an empty string).
This function is only available if mSQL support has been
enabled in PHP.

msql_FieldName returns the name of the specified field.
Arguments to the function is the result identifier and the
field index. ie. msql_FieldName($result,2); will
return the name of the second field in the result associated
with the result identifier.
This function is only available if mSQL support has been
enabled in PHP.

msql_FieldType is similar to the msql_FieldName()
function. The arguments are identical, but the field type is
returned. This will be one of "int", "char" or "real".
This function is only available if mSQL support has been
enabled in PHP.

msql_FreeResult only needs to be called if you are worried
about using too much memory while your script is running. All
result memory will automatically be freed when the script is
finished. But, if you are sure you are not going to need the
result data anymore in a script, you may call msql_freeresult
with the result identifier as an argument and the associated
result memory will be freed.
This function is only available if mSQL support has been
enabled in PHP.

msql_ListDBs will return a result pointer containing the
databases available from the current mSQL daemon. Use the
msql_dbName() function to traverse
this result pointer.
This function is only available if mSQL support has been
enabled in PHP.

msql_listfields retrieves information about the the given
tablename. Arguments are the database name and the table
name. A result pointer is returned which can be used with
msql_fieldflags, msql_fieldlen, msql_fieldname,
msql_fieldtype. A result identifier is a positive integer.
The function returns -1 if a error occurs. A string
describing the error will be placed in $phperrmsg, and unless
the function was called as @msql() then this error string
will also be printed out.
This function is only available if mSQL support has been
enabled in PHP.

msql_ListTables takes a database name and result pointer
much like the msql() function. The
msql_TableName() function
should be used to extract the actual table names from the
result pointer.
This function is only available if mSQL support has been
enabled in PHP.

msql_NumRows simply returns the number of rows in a
result. The argument is the result identifier returned by the
msql() function.
This function is only available if mSQL support has been
enabled in PHP.

msql_RegCase takes a string argument and converts it to
the regular expression needed to send to mSQL in order to get
a case insensitive match. This turns a string like "abc" into
"[Aa][Bb][Cc]".
This function is only available if mSQL support has been
enabled in PHP.

msql_Result displays a field from a returned record.
Arguments are the result identifier returned by the msql()
function, an integer which is the index of the record to be
viewed and a field name. The field argument supports the
"table.field" syntax for handling results from a join. This
function is perhaps best illustrated with a complete
example:

The above script connects to the mSQL engine on the local
machine, sets the name variable to bob and
sends a query which asks for all the fields from a table
where the firstname field is set to bob. It
then displays the number of records it found after which it
loops through each of the found records and displays the
fullname and address fields for each
record. As you can see, it would be trivial to add HTML
markup tags around the printed fields to format the results
in a table or in whatever manner is desired. Note that there
is no msql_connect() call. msql_connect need only be called
if a connection to a remote database is desired.

This function is only available if mSQL support has been
enabled in PHP.

msql_TableName takes a result pointer returned by the
msql_ListTables() function as
well as an integer index and returns the name of a table. The
msql_NumRows() function may be
used to determine the number of tables in the result pointer.
An example would be:

mysql sends a mysql query. Arguments are the database name
and the query string. ie. <?mysql("MyDatabase"
, "select * from table")>. The return value
from this function is a result identifier to be used to
access the results from the other mysql_ functions. A result
identifier is a positive integer. The function returns
0 when no result identifier is created. This
is the case with any queries that do not return anything,
such as create, update, drop,
insert and delete. The function will return
-1 if an error occurs. A string describing
the error will be placed in $phperrmsg, and unless the
function was called as @mysql() then this
error string will also be printed out.
This function is only available if mysql support has been
enabled in PHP.

mysql_Connect specifies the host name or IP on which the
mysql database engine resides. This is equivalent to the
mysqlConnect() function in the mysql C API. The one
difference between this function and the C API equivalent is
that if the function isn't called, a connection to the local
host is made by default on the first call to the mysql()
function. And, there is no need for an mysql_close function
since only one connection may be active at any one time. If a
second call to mysql_connect() is made in a file, then the
connection to the first host is automatically closed.

An optional username and password may be provided. Note
that when PHP is compiled to run in SAFE
MODE then the username must either be the same as the
owner of the file being processed, or the owner of the httpd
process (usually nobody). Any other username will fail.

To explicitly connect to the mysql daemon on the local
host, use:
<?mysql_connect("localhost")>
This function is only available if mysql support has been
enabled in PHP.

mysql_dbName returns the database name stored in position
$i of the result pointer returned from the mysql_ListDbs() function. The mysql_NumRows() function can be used to
determine how many database names are available.
This function is only available if mysql support has been
enabled in PHP.

mysql_FieldFlags returns the field flags of the specified
field. Currently this is either, "not null", "primary key", a
combination of the two or "" (an empty string).
This function is only available if mysql support has been
enabled in PHP.

mysql_FieldName returns the name of the specified field.
Arguments to the function is the result identifier and the
field index. ie. mysql_FieldName($result,2); will
return the name of the second field in the result associated
with the result identifier.
This function is only available if mysql support has been
enabled in PHP.

mysql_FieldType is similar to the mysql_FieldName()
function. The arguments are identical, but the field type is
returned. This will be one of "int", "char" or "real".
This function is only available if mysql support has been
enabled in PHP.

mysql_FreeResult only needs to be called if you are
worried about using too much memory while your script is
running. All result memory will automatically be freed when
the script is finished. But, if you are sure you are not
going to need the result data anymore in a script, you may
call mysql_freeresult with the result identifier as an
argument and the associated result memory will be
freed.
This function is only available if mysql support has been
enabled in PHP.

mysql_ListDBs will return a result pointer containing the
databases available from the current mysql daemon. Use the
mysql_dbName() function to
traverse this result pointer.
This function is only available if mysql support has been
enabled in PHP.

mysql_listfields retrieves information about the the given
tablename. Arguments are the database name and the table
name. A result pointer is returned which can be used with
mysql_fieldflags, mysql_fieldlen, mysql_fieldname,
mysql_fieldtype. A result identifier is a positive integer.
The function returns -1 if a error occurs. A string
describing the error will be placed in $phperrmsg, and unless
the function was called as @mysql() then this error string
will also be printed out.
This function is only available if mysql support has been
enabled in PHP.

mysql_ListTables takes a database name and result pointer
much like the mysql() function. The
mysql_TableName() function
should be used to extract the actual table names from the
result pointer.
This function is only available if mysql support has been
enabled in PHP.

mysql_NumFields returns the number of fields in a result.
The argument is the result identifier returned by the mysql()
function.
This function is only available if mysql support has been
enabled in PHP.

mysql_NumRows simply returns the number of rows in a
result. The argument is the result identifier returned by the
mysql() function.
This function is only available if mysql support has been
enabled in PHP.

mysql_Result displays a field from a returned record.
Arguments are the result identifier returned by the mysql()
function, an integer which is the index of the record to be
viewed and a field name. The field argument supports the
"table.field" syntax for handling results from a join. One
difference between mSQL 1.0 and mysql is that mysql supports
functions that can act on the result data. These functions
can be applied in this function. This function is perhaps
best illustrated with a complete example:

The above script connects to the mysql engine on the local
machine, sets the name variable to bob and
sends a query which asks for all the fields from a table
where the firstname field is set to bob. It
then displays the number of records it found after which it
loops through each of the found records and displays the
fullname and address fields for each
record. The lcase() call in the result function changes the
returned string to lower case. For a complete set of
functions that can be applied to the result data, see your
mysql documentation. As you can see, it would be trivial to
add HTML markup tags around the printed fields to format the
results in a table or in whatever manner is desired. Note
that there is no mysql_connect() call. mysql_connect need
only be called if a connection to a remote database is
desired.

This function is only available if mysql support has been
enabled in PHP.

mysql_TableName takes a result pointer returned by the
mysql_ListTables() function
as well as an integer index and returns the name of a table.
The mysql_NumRows() function may
be used to determine the number of tables in the result
pointer. An example would be:

Next moves the internal array pointer to the next item in
the array. This happens automatically when an array is
accessed using the non-indexed method ($array[]). The
function returns the value of the new item. This function can
be used to move the pointer forward without having to access
the array explicitly. One use would be to traverse an
associative array and only printing out the keys of the array
and not the actual contents.

openDir opens the specified directory and places an
internal pointer to the beginning of the directory. Directory
entries are read using the readDir
function, and an opened directory should be closed with the
closeDir function.

cursor_id - oracle cursor id for _parsed_ SQL
query or PL/SQL block;php_variable_name - variable name in PHP script
without leading '$'sql_variable_name - variable name in SQL with
leading colonsize - maximal number of bytes to be taken into
account at binding

Notes:
1) PHP variable SHOULD be initialised with at least
size bytes length string even it is return-only
variable.
2) Ora_Bind() SHOULD be used after Ora_Parse and
before Ora_Exec. In case of re-parsing the SQL sentence, all
used variables have to be re-bound.

Commits the current transaction on conn_ind. The
current transaction starts from the Ora_Logon() call or from the last Ora_Commit()
or Ora_Rollback(), and lasts until
an Ora_Commit(), Ora_Rollback() or
Ora_Logoff() call is issued.
Ora_Commit() returns -1 (and an error message) upon
failure.

The PassThru() function is similar to the Exec() function in that it executes a Unix
command. If the return_var argument is present, the return
status of the Unix command will be placed here. This command
should be used in place of Exec or System when the output
from the Unix command is binary data which needs to be passed
directly back to the browser. A common use for this is to
execute something like the pbmplus utilities that can output
an image stream directly. By setting the content-type to
image/gif and then calling a pbmplus program to
output a gif, you can create PHP/FI scripts that output
images directly.

pg_Connect opens a connection to a Postgres database. Each
of the arguments should be a quoted string, including the
port number. The options and tty arguments are optional and
can be empty strings. This function returns a connection_id.
This identifier is needed by other Postgres functions. You
can have multiple connections open at once. This function
will return 0 on error.

This function is only available if Postgres support has
been enabled in PHP.

pg_Exec will send an SQL statement to the Postgres
database specified by the connection_id. The connection_id
must be a valid identifier that was returned by pg_Connect.
The return value of this function is an identifier to be used
to access the results from other Postgres functions. This
function will return 0 on error. It will
return 1 when the command executed correctly
but are not expected to returned data (insert or update
commands, for example). Note that selects which return no
data will still return a valid result greater than 1.

This function is only available if Postgres support has
been enabled in PHP.

pg_FieldSize will return the internal storage size (in
bytes) of the named field in the given Postgres result. A
field size of 0 indicates a variable length field. This
function will return -1 on error.

This function is only available if Postgres support has
been enabled in PHP.

pg_FreeResult only needs to be called if you are worried
about using too much memory while your script is running. All
result memory will automatically be freed when the script is
finished. But, if you are sure you are not going to need the
result data anymore in a script, you may call pg_freeresult
with the result identifier as an argument and the associated
result memory will be freed.

This function is only available if Postgres support has
been enabled in PHP.

pg_GetLastOid can be used to retrieve the Oid assigned to
an inserted tuple if the last command sent via pg_Exec was an
SQL Insert. This function will return a positive integer if
there was a valid Oid. It will return -1 if
an error occured or the last command sent via pg_Exec was not
an Insert.

This function is only available if Postgres support has
been enabled in PHP.

pg_Result will return values from a result identifier
produced by pg_Exec. The row_number and field name specify
what cell in the table of results to return. Row numbering
starts from 0. Instead of naming the field, you may use the
field index as an unquoted number. Field indices start from
0.

Postgres has many built in types and only the basic ones
are directly supported here. All forms of integer, boolean
and oid types are returned as integer values. All forms of
float, and real types are returned as double values. All
other types, including arrays are returned as strings
formatted in the same default Postgres manner that you would
see in the 'monitor' or 'psql' programs.

Support for returning PHP arrays of numerical and string
data from a Postgres result is planned for a later date.

This function is only available if Postgres support has
been enabled in PHP.

phpInfo prints the same page you get when adding "?info"
to a PHP/FI parsed URL or when you run the php.cgi binary by
itself. It is especially useful for debugging scripts in the
Apache module version since it displays a number of useful
internal data.

Popen opens a pipe to a command and returns a file pointer
index. This file pointer index can be used by fgets, fputs and fclose. Arguments are the command to run and
the mode. The mode can be either "r" for read or "w" for
write. See the UNIX C library popen man page for more
details. Any file opened with popen() should be closed using
the pclose() function.

Prev moves the internal array pointer for the given
variable to the previous item in the array. If already at the
beginning of the list, the pointer will point to the first
item. The function returns the value of the new item. This
function is useful for traversing an associative array in
reverse order. See the example in the End() definition. Also see Next().

PutEnv puts the given string in the environment. Not
extremely useful since the local environment variables are
wiped out when PHP is done with a page, but in some cases it
is useful if other things called from within a PHP script
checks environment variables. For example, if you want to run
multiple mSQL daemon processes, you will need to use PutEnv
to switch back and forth between the different sockets.

Rand returns a random number between 0 and RANDMAX.
Remember to seed your random number generator with a
call to srand() before calling rand().
You only need to seed the random number generator once.
RANDMAX can be determined with the getRandMax function. Normally a specific
range is chosen by simply using the modulus operator on the
result.

readDir reads the next entry from the currently open
directory structure. Once an entry is read, the pointer is
advanced to the next entry in the directory and the next call
to this function will return the next entry in the directory.
Use the openDir function to open a
directory before calling this function.

$size = ReadFile(Filename) - Reads the file filename and
simply outputs it directly. It returns the number of bytes
actually read. It is different from the File() command in
that it does not store the file in memory, and it is safe for
use on binary files. This function is generally used where
one might otherwise do a PassThru("cat filename"). Using
ReadFile is more efficient.

This function has been replaced by the ereg() function. It is however still available
for backwards compatibility.
reg_Match returns non-zero if the regular expression is
matched in the argument string. For example, the condition,
<?if (reg_match("^This.*", "This is an example
string")> would be true since the "^This.*"
expression says to match the word This at
the beginning of the string and then match any characters
afterwards. If the regs argument is present, then
match registers are filled into positions 0-10 in the array
named by the regs argument. Register 0 will always
contain the full matched string. For more information on
regular expressions, see the regular
expression section of this document.

This function has been replaced by the ereg_replace() function. It is however
still available for backwards compatibility.
reg_Replace scans the entire argument string and replaces any
portions of the string matched by the given expression with
the replacement string. For example, in the string, "This
is an example string" we could very easily replace every
space with a dash with the command: reg_replace("
","-","This is an example string").For more
information on regular expressions, see the regular expression section of this
document.

This function has been replaced by the ereg() function. It is however still available
for backwards compatibility.
reg_Search will scan the entire argument string for any
matches to the given regular expression. If a match is found,
it will return the portion of the string starting at where
the match occurred. If no match is found a zero-length string
is returned. If the regs argument is present, then
match registers are filled into positions 0-10 in the array
named by the regs argument. Register 0 will always
be assigned the full matched string. For more information on
regular expressions, see the regular
expression section of this document.

Reset moves the internal array pointer for the given array
variable to the first item of the array and returns the value
of this item. This is useful for traversing associative and
non-indexed arrays. See also End() and
Next(). The following example traverses
an associative array:

SetCookie() defines a cookie to be sent along with the
rest of the header information. All the arguments except the
name argument are optional. If only the name argument is
present, the cookie by that name will be deleted from the
remote client. You may also replace any argument with an
empty string ("") in order to skip that argument. The
expire and secure arguments are integers and cannot be
skipped with an empty string. Use a zero (0) instead.
The expire argument is a regular Unix time integer as
returned by the time() or mktime() functions. Some examples follow:

Note that the value portion of the cookie will
automatically be urlencoded when you send the cookie, and
when it is received, it is automatically decoded and assigned
to a variable by the same name as the cookie name. ie. to see
the contents of our test cookie in a script, simply do:

SetErrorReporting sets the current error reporting state
to the value of arg. If non-zero, errors will be
printed, and if 0 they won't be. The function returns the
previous error reporting state. This is a more general way of
disabling error reporting than by preceding individual
functions with a '@' character. See the section on Suppressing Errors from function calls for more
information.

Solid_Connect opens a connection to a Solid server. Each
of the arguments should be a quoted string. The first
parameter (data source name) can be an empty string,
resulting in a connection to the default server on the
localhost. This function returns a connection_id. This
identifier is needed by other Solid functions. You can have
multiple connections open at once. This function will return
0 on error.

This function is only available if Solid support has been
enabled in PHP.

Solid_Exec will send an SQL statement to the Solid server
specified by the connection_id. The connection_id must be a
valid identifier that was returned by Solid_Connect. The
return value of this function is an identifier to be used to
access the results by other Solid functions. This function
will return 0 on error. It will return
1 when the command executed correctly but
are not expected to returned data (insert or update commands,
for example). Note that selects which return no data will
still return a valid result greater than 1.

This function is only available if Solid support has been
enabled in PHP.

Solid_FetchRow fetches a row of the data that was returned
by Solid_Exec. After Solid_FetchRow is called, the fields of
that row can be access with Solid_Result. Every time
Solid_FetchRow is called a new row can be accessed by
Solid_Result. If Solid_FetchRow was succesful (there was a
new row), 1 is returned, if there are no
more rows, Solid_FetchRow will return 0. The
return value of Solid_FetchRow can be used as the condition
of a while loop.

This function is only available if Solid support has been
enabled in PHP.

Solid_FreeResult only needs to be called if you are
worried about using too much memory while your script is
running. All result memory will automatically be freed when
the script is finished. But, if you are sure you are not
going to need the result data anymore in a script, you may
call Solid_FreeResult with the result identifier as an
argument and the associated result memory will be freed.

This function is only available if Solid support has been
enabled in PHP.

Solid_NumRows will return the number of rows in a Solid
result. The argument is a valid result identifier returned by
Solid_Exec. This function will return -1 on
error. Large Caveat: The SOLID SQL server uses ODBC as
it's primary (and only) interface. SolidNumRows() uses
SQLRowCount at the low-level to get the number of rows.
SQLRowCount follows the age-old Microsoft tradition of
unnecessary limitations, strange exceptions and other odd
things. This means that the function will only return the
number of rows affected by an INSERT, UPDATE or a DELETE
clause. No SELECT! As a workaround you can try the count()
statement of SQL or a while-loop that counts the number of
rows. If you need Solid_NumRows() to figure out how many
records to read after a SELECT clause, try checking the
return value from Solid_FetchRow() instead. So instead
of:

Solid_Result will return values from a result identifier
produced by Solid_Exec. The field name specify what cell in
the row to return. Instead of naming the field, you may use
the field index as an unquoted number. Field indices start
from 0.

This function is only available if Solid support has been
enabled in PHP.

Sort is used to sort a PHP array in ascending order. To
sort in descending order, use the RSort() function. It
understands the three variable types and will sort
alphabetically if the array contains strings, and numerically
if the array contains numbers. In the case of an array which
contains a mixture of types, the first type in the array will
specify the sort method. Note that if you are going to sort
an associative array, you should use the ASort() function.

This function takes a string argument and returns the
soundex key for the string. Soundex keys have the property
that words pronounced similarly produce the same soundex key,
and can thus be used to simplify searches in databases where
you know the pronunciation but not the spelling. This soundex
function returns a string 4 characters long, starting with a
letter.
This particular soundex function is one described by Donald
Knuth in "The Art Of Computer Programming, vol. 3: Sorting
And Searching", Addison-Wesley (1973), pp. 391-392.
Example:

Euler and Ellery map to E460
Gauss and Ghosh map to G200
Hilbert and Heilbronn map to H416
Knuth and Kant map to K530
Lloyd and Ladd map to L300
Lukasiewicz and Lissajous map to L222

Sprintf returns the string created by the formatted output
defined by the format argument and arg. It is similar to the
formatted version of the echo command,
except this just returns the string while echo displays it.
It is also similar to the C function by the same name. The
difference being that this version does not accept more than
5 arg arguments. If you need to format more than 5
arguments into a single string, simply call sprintf()
multiple times for each group of arguments. Note that the
type of the argument doesn't affect the output. The argument
type is automagically converted to match the type specified
in the format string.

Srand seeds the random number generator. This function
takes any integer as an argument. One choice for a seed value
is to use the date function to give you the
current number of seconds past the minute. Note that this
function does not return a value! This function simply
seeds the random number generator for subsequent calls to the
rand() function. eg.

strchr and strstr are actually
identical functions. They can be used interchangeably and
both are included for completeness sake. They will return the
portion of the string argument starting at the point where
the given sub-string is found. For example, in the string,
"This is an example string" above, the call: <?echo
strchr($string,"an ")> would return the string:
"an example string".

strtr() translates each character of "string" that is in
"set1" to the corresponding character in "set2". Characters not
in set1 are passed through unchanged. When a character appears
more than once in "set1" and the corresponding characters in
"set2" are not all the same, only the final one is used. When
one of "set1" or "set2" is longer, longer "set?" is truncated
to length of shorter "set?".

strrchr will search for a single character starting at the
end of the argument string and working its way backwards. It
returns the string starting with the search character if the
character was found and an empty string if it wasn't.

strstr and strchr are actually
identical functions. They can be used interchangeably and
both are included for completeness sake. They will return the
portion of the string argument starting at the point where
the given sub-string is found. For example, in the string,
"This is an example string" above, the call: <?echo
strstr($string,"an ")> would return the string:
"an example string".

strtok is used to tokenize a string. That is, if you have
a string like "This is an example string"
you could tokenize this string into its individual words by
using the space character as the token. You would use the
following script code:

Note that only the first call to strtok uses the string
argument. Every subsequent call to strtok only needs the
token to use, as it keeps track of where it is in the current
string. To start over, or to tokenize a new string you simply
call strtok with the string argument again to initialize it.
Note that you may put multiple tokens in the arg
parameter. The string will be tokenized when any one of the
characters in the argument are found.

substr returns a part of the given string. The start
position is given by the start argument. The first position
in a string is position 0. And the length argument specifies
the number of characters to return from the start
position.

This function opens a network connection to the sybase
server. This function depends on several environment
variables which must be set by the caller before calling this
function.

The environment variables are:

DSQUERY - the alias of the sybase server as defined
in the sybase interface file.DBUSER - connect to the sybase server as this
user.DBPW - password of the user.

These variables can be set in several ways. If php/fi is
running as a CGI program, then a shell wrapper can be used to
set these variables or you can set these variables directly
in the HTML page using the builtin PHP/FI function
putenv(). Instead of using the
values directly in putenv(), the
values can be obtained from form input. The variables can be
defined in a file and included in the html files with PHP/FI
include statement.

This function gets the value of a specific column of the
current result row. The only argument to the function is the
string specifying the field. Example:
$value=sybsql_getfield("@10");NOTE:
sybsql_nextrow() must be called
before calling this function. sybsql_nextrow() must be called
if the row pointer needs to be incremented, because this
function only reads the current row in the row buffer.

If the specified column has a value, the function returns
the value as a string otherwise the function returns an empty
string ("").

This function returns the number of rows in the current
result buffer. NOTE: when this function is called, it
will seek to the first row right away, then it will call
dbnextrow() until there are no more rows and increment a
internal counter to calculate the number of rows in the
result buffer. Then it points back to the very first row.
Therefore, after calling this function row counter always
points to the very first row. It's ugly but I don't know any
other way at this time.

If there are no rows in the result buffer, the function
will return 0.

This function prints specific fields of the current result
row. The only argument to the function is a string which
holds information about the fields to be printed. A field is
specified with a @ followed by a number. For example, @0
means first row, @10 means 11th row. Note that the field
number starts at 0. The function is perhaps best illustrated
with a complete example:

This function prints all rows in the current result
buffer. The result is printed in a hard coded HTML table
format. Note that this function should not be called inside a
loop. The function will print the name of the columns if
there are any column headings in the output.

This function sets the requested row number as the current
row in the row buffer. The only argument to the function is
the row number. Example: $rc=sybsql_seek(10);
Note, row number starts at 0.

The function returns 1 if the seek succeeds and 0 if the
seek fails. When all of the rows in the current result buffer
have been visited, the row pointer points to the last row. If
it is needed to go backward and visit some more rows, this
function can be used for this purpose.

System is just like the C system() command in
that it executes the given unix command and outputs the
result. If a variable is provided as the second argument,
then the return status code of the executed unix command will
be written to this variable. Note, that if you are going to
allow data coming from user input to be passed to this System
function, then you should be using the EscapeShellCmd() function to make sure
that users cannot trick the system into executing arbitrary
commands. The System() call also automatically flushes the
Apache output buffer after each line of output if PHP is
running as an Apache module. If you need to execute a command
and have all the data from the command passed directly back
without any interference, use the PassThru() function. See also the Exec function.

Time simply returns the current local time in seconds
since Unix epoch (00:00:00 Jan. 1 1970). It is equivalent to
calling Date("U"). If you need better
than per-second granularity, use the Microtime function.

Umask(mask) sets PHP's umask to mask &
0777 and returns the old umask. If PHP/FI is an Apache
module, Apache's old umask is restored when PHP/FI has
finished. mask must be specified in octal notation, like for ChMod(). Umask() without arguments simply
returns the current umask.

UniqId returns a prefixed unique identifier based on
current time in microseconds. The prefix can be useful for
instance if you generate identifiers simultaneously on
several hosts that might happen to generate the identifier at
the same microsecond. The prefix can be up to 114 characters
long.

UrlDecode decodes a string encoded with the UrlEncode function. In typical use, it is
not necessary to decode URL Encoded strings because these are
automatically decoded when strings are passed between pages.
However, for completeness sake, this function has been
included.

Virtual is an Apache-specific function which is equivalent
to <!--#include virtual...--> in mod_include. It
performs an Apache sub-request. It is useful for including
CGI scripts or .shtml files, or anything else that you would
parse through Apache (for .phtml files, you'd probably want
to use <?Include>.

It may well be that the set of
functions provided by PHP/FI does not include a particular
function that you may need. By carefully following the steps
described below, it is possible for you to add your own functions
to PHP/FI.

Before you start hacking away at the internals of PHP/FI you
need to grab a copy of the latest version of Bison. Bison is
GNU's implementation of YACC (Yet Another Compiler Compiler). The
YACC that came with your operating system may or may not be good
enough, but just to make sure, go grab Bison. You can find it at
ftp://prep.ai.mit.edu/pub/gnu.

You should also have a look at the Makefile and turn on
debugging. Simply uncomment the DEBUG line in
the Makefile. The output file of debug information is specified
by DEBUG_FILE in php.h. It is by
default set to /tmp/php.err. You can change this to suit
your needs.

A final thing you might want to keep in mind is that php runs
as the same user id as httpd on your system, unless of course you
are running it with the setuid bit set, and this httpd user does
not generally have write access to the various directories. This
means that if you do something that causes php to core dump, you
will not get a core file. The easy way around this is to make the
directory where you keep your test .html files writable to all.
PHP changes its current directory to the directory of the .html
file it is reading and will thus dump its core there if it
can.

In the following steps we will use the Time()
function to illustrate how to add a function.

Step 1 - Defining the grammar of your
Function

If your function takes 0 to 6 arguments, there are
predefined grammars available. You can skip this step.

The grammar of your function is defined in the
parse.raw file. The first thing to add is a token. A
token is an upper case keyword which is usually the same as
your function name. All the tokens are defined near the top
of the parse.raw file. The order doesn't matter. Then you
need to build your actual YACC grammar rule. Look at the
existing rules and find a function that is similar to the one
you are adding. Keep in mind that most normal functions are
standard functions that read their arguments from the
expression stack. Your function will most likely fall into
this group in which case you won't need to touch the
parse.raw file.

Step 2 - Adding your function to the lexical
analyzer hash table

To do this, edit lex.c and find the hash table
near the top of the file. Look for the line, static
cmd_table_t cmd_table[22][30] = {, which defines the
beginning of the hash table. The [22][30] defines
the size of the 2 dimensional array which holds the hash
table. The 22 is one greater than the maximum function name
length and the 30 refers to the maximum number of functions
in any one hash list. If you exceed either of these limits,
simply increase them right here.

This hash table would probably rate as the absolute
simplest hash table in the entire world. The hash value is
the length of the string of the function name to be hashed.
So, for our Time() example, we need to add an entry
for hash value 4. Therefore we add the following line to the
hash list for 4:

{ "time",INTFUNC0,UnixTime },

This entry maps a string to the INTFUNC0 token. You can
look up the grammar for the INTFUNC0 token in
parse.raw and you will see that it is a generic
grammar for an internal function call with 0 arguments. The
string, in quotes above, is the actual string that you will
be using in the .html files to call your function. Keep in
mind that PHP/FI function names are not case
sensitive. And the final UnixTime element is the
actual function to be called.

Step 3 - Write your actual Function

You can actually write your function in any language you
like, as long as it is callable through the normal C function
call convention and you have a way of creating either an
object file or a library file compatible with the linker on
your system. In general, we will assume that you are writing
your function in C. All the functions that come with PHP/FI
have been written in C. The Time() function, or UnixTime() as
it is called internally in PHP can be found in
date.c and looks like this:

Note that the function is void. This indicates that it
doesn't return anything. This may seem confusing to you
because obviously the function needs to somehow return the
time. The time is returned, but not as the return value of
the function. It is pushed onto what is called an expression
stack. The expression stack is simply a stack of strings and
an associated type. PHP/FI understands only 3 basic variable
types: STRING, LNUMBER and DNUMBER. STRING is a character
string, LNUMBER is a long integer and DNUMBER is a double, or
floating point, value. In this Time() example, the value to
be returned is the time expressed in Unix format (number of
seconds since Jan.1 1970) and is thus an integer. The
expression stack only accepts strings, so we sprintf the long
integer into a string and push it onto the stack indicating
that it is actually a long integer with the line:
Push(temp,LNUMBER);

Step 4 - Add your function prototype to
php.h

In the bottom half of the php.h file you will
find a complete list of prototypes of all the functions in
php. They are grouped by the files in which they appear.
Simply add your prototype to an appropriate place in this
file. For our Time() example the following line is added:

void UnixTime(void);

Step 5 - Compile

You have to remember to re-make the parser whenever you
make a change to the parse.raw file. Type:
make parser to do this. You must have at
least version 1.25 of Bison in order to make the PHP parser.
Then do a normal compile by typing: make
once that is done.

Step 6 - Send me your additions!

If you would like your functions added to the next release
of PHP/FI, send them to me. The best way is probably to make
a context-sensitive diff. To do that, you need a copy of a
clean unmodified distribution. Simply do a, diff
-c on the files you have changed comparing them to
the original files. Please don't send me a diff of the
changes in parse.c since that file is automatically
generated. Send me the diff from parse.raw
instead.

The Time() example illustrated the steps involved in adding a
function. Chances are that the function you wish to add is quite
a bit more complex than this example. You will probably want to
be able to pass arguments to your function and have it manipulate
these arguments in some manner. You may even want to have it
callable in different ways. These concepts will be illustrated by
the PHP/FI crypt() function. See also the section entitled
Notes for Code Hacks for some more
technical details about writing code for PHP/FI.

Here it is shown how to define a grammar which lets you call a
function with either 1 or 2 arguments. You could write different
functions to handle the two cases, or simply send a mode
parameter as is done here to indicate the mode in which the
function is called. Note that in this case you cannot use one of
the pre-defined INTFUNCn grammars since your function can take a
variable number of arguments.

The other aspect that is shown is how to actually represent
function arguments. In most cases you will want to use the
expr identifier. This identifier means that the
argument is an expression. An expression can be a literal value,
a function call or a combination of many expressions. See
parse.raw for the complete yacc grammar definition for
expressions for more details.

The Hash Table entry in lex.c:

{ "crypt",CRYPT,NULL },

Notice that the last item is a NULL in this case since the
function call is handled in parse.raw directly. If you
used an INTFUNCn grammar, then you would put the name of your
function in place of this NULL. The actual Crypt() function in
crypt.c:

The most important aspect of this function is the s =
Pop() call. The arguments to the function must be popped
off the expression stack one by one. When you write a function
which takes multiple arguments, remember that a stack is a
LAST-IN, FIRST-OUT data structure. This means that you will be
popping your arguments off the stack in reverse order. The last
argument is popped off first. In the above example we check to
see if we are in the 2 argument mode. If we are, we pop the
argument off the stack and save it. Then we pop the next argument
off the stack. Pop() returns a pointer to a Stack structure (s).
The Stack structure looks like this (from php.h):

The type will generally be one of STRING, LNUMBER or
DNUMBER. The strval, intval, and
douval components are the string, integer and double
representations of the value respectively. If the expression is
actually a defined variable, the var component contains
a pointer to the variable structure which defines this
variable.

In our Crypt() function we are only interested in the string
value of the argument, so we use s->strval. Many
PHP/FI functions can do different things depending on the type of
the variable simply by checking s->type and using
s->strval, s->intval and/or
s->douval appropriately.

After calling the real crypt() function and
getting the encrypted string, our Crypt() function calls
Push(enc,STRING); to push the return value onto the
expression stack. It should be noted that the expression stack is
cleared after each PHP/FI line, so if you push expressions onto
this stack that are never popped by anything, it won't
matter.

The Debug() call in the Crypt() example shows how to
add debugging output to your function. Debug() is a varags
(variable argument list) function just like printf.

Memory management within PHP/FI is a tricky thing. Since we
can run as a server module, we have to be very careful about
memory resources. Not only do we need to be reentrant, but we
also need to be handle the fact that we can receive a timeout
signal at any time at which point we drop out of the module. We
get no warning, and we get no time to free any memory that we may
have allocated. And this memory has to be freed, or the data
space of the httpd process we are linked to could grow
indefinitely. This also applies when PHP is running in CGI mode
since it can be set up to run as a FastCGI persistent
process.

The solution is to use sub-pools of memory. These pools are
automatically cleared by Apache when a session is terminated, or
in the case of a FastCGI persistent process, these pools are
cleared in main.c every time the FastCGI wrapper loop
executes. Three such pools are used at the moment. They are
numbered 0,1 and 2. The sub-pool number is the first argument to
the emalloc and estrdup functions.

Pool 0 - Session lifespan

Any memory allocated from this pool will span the entire
session. It is a good idea to keep the use of this pool as low
as possible. For example, if someone makes a while loop that
iterates 1000 times and within this while loop they call
something which allocates memory from pool 0, then this memory
will be allocated 1000 times. This is a quick way to use up all
alloted data space.

Pool 1 - Temporary storage (shortest
lifespan)

If a temporary work buffer is needed for something within a
function, the memory for it must come from this pool. This pool
is cleared on every call to yylex(). ie. the memory is lost
just about as soon as you leave a function.

Pool 2 - Expression space (medium
lifespan)

This pool exists for the duration of an expression. An
expression in this context being a full PHP/FI command line. It
will not get cleared within functions since the higher level
expression which called the function has not been completed
until the function returns. The ClearIt flag in the yylex()
function indicates when it is safe to clear this pool.

The use of sub-pools completely eliminates the need to
explicitly free memory anywhere in the code, with the one
exception being memory allocated using a regular malloc call by
various libraries that could be linked into PHP. The gdbm library
is one such example.