PHP/FI Version 2.0
Table of Contents
- Brief History
- Installation Instructions
- So, what can I do with PHP/FI?
- CGI Redirection in Apache HTTPD
- Access Control
- Access Logging
- Relative vs. Absolute URL's - or, Why do my Images Break?
- How PHP/FI handles GET and POST method data
- GD (a graphics library for GIF creation) Support in PHP
- PHP/FI and Virtual Hosts
- File Upload Support
- mSQL Support
- PHP/FI Script Language
- Adding your own functions to PHP/FI
Brief History
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.
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. It eliminates the need for numerous small Perl
cgi programs by allowing you to place simple scripts directly in your
HTML file. 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.
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 loggin
or access restriction support, I call my binary FI. When I build
with these options, I call it PHP.
Installation Instructions
- Before You Begin
- 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?
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 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.
- 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. Any directory to which the httpd (usually "nobody")
has write priviledges. You may create this directory manually
somewhere and simply chown nobody directory.
Notes:
If you have gdbm installed on your system and this is not detected
by the install script, you have a number of options to fix this:
a) create a link to your libgdbm.a file to a place like /lib or
/usr/lib
or
b) change your system's LD_LIBRARY_PATH default setting to include
the directory where you keep libgdbm.a
or
c) after running ./install, edit config.h and change the
"/* #undef HAVE_GDBM */" to "#define HAVE_GDBM 1"
and then edit src/Makefile and add "-L/<directory/lib> -lmsql" to
the "LIBS" as well as "-I<directory/include>" to the CPPFLAGS
line. <directory/lib> should be the directory where the file,
libgdbm.a, is located and <directory/include> should be the
directory where the file, gdbm.h, is located.
Step 2.
Go into the src directory: cd src
Step 3.
type: make
This will create the actual executable program file named php.cgi
by default. Copy this file to your cgi-bin directory or any
directory from which the http daemon can execute cgi programs.
Don't worry about any shift or reduce conflicts reported by either
bison or yacc. They are not important.
Step 4.
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.
- 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.
- 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
So, what can I do with 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. 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.
A simple example
Suppose you have a form:
<FORM ACTION="/cgi-bin/php.cgi/~userid/display.html" METHOD=POST>
<INPUT TYPE="text" name="name">
<INPUT TYPE="text" name="age">
<INPUT TYPE="submit">
</FORM>
Your display.html file could then contain something like:
<?echo "Hi $name, you are $age years old!<p>">
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:
<?
if($age>50);
echo "Hi $name, you are ancient!<p>";
elseif($age>30);
echo "Hi $name, you are very old!<p>";
else;
echo "Hi $name.";
endif;
>
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 backend to a web page
has never been easier. See the section on mSQL Support
for more information.
CGI Redirection in Apache HTTPD
One of the best ways to run PHP/FI is by using a cgi redirection module
with the Apache server. There are two of these modules available. One
is developed by Dave Andersen 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 (Feb.11/96) is that the current
official Apache release (1.0.2) 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 a apache_1.0.2_patched.tar.gz file at
http://www.hyperreal.com/httpd/patches/for_Apache_1.0.2/ which fixes
this problem. It also includes a number of other useful patches.
Check the Apache documentation on how to add a module. Generally you
add the module name to a file called Configuration. However in
the interim apache_1.0.2_patched.tar.gz release you add the module name
to a file called config.in. 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.
Access Control
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 disppear.
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
Access Logging is another optional feature which can be enabled at compile-time
by answering Yes to the question in the install script. If you wish
to use this option, you will also 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.
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. To run it, copy it to a directory
accessible from your web server and type:
http://your.machine.domain/cgi-bin/php.cgi/path/log.html
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 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:
<?setshowinfo(0)>
Relative vs. Absolute URL's - or, Why do my Images Break?
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.
How PHP handles GET and POST method data
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:
/cgi-bin/php.cgi/file.html?abc+def+EMAIL_ADDR=rasmus@io.org&var=value
The relevant components of the PHP symbol table will be:
$argc = 4
$argv[0] = abc
$argv[1] = def
$argv[2] = EMAIL_ADDR=rasmus@io.org&var=value
$EMAIL_ADDR = rasmus@io.org
$var = value
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 create to contain rasmus@io.org.
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 propogate
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.
GD (a graphics library for GIF creation) Support in PHP
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/gd1.2.tar.Z, 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.
More information on the GD package is available at:
http://www.boutell.com/gd/.
GD 1.2 is copyright 1994, 1995 Quest Protein Database Center, Cold Springs Harbor Labs.
PHP/FI and Virtual Hosts
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.
File Upload Support
PHP/FI will automatically detect a file upload from a browser which supports the
form-based file upload features as proposed by
E. Nebel
and L. Masinter from Xerox and described in
RFC 1867.
A file upload screen can be built by creating a special form which looks
something like this:
<FORM ENCTYPE="multipart/form-data" ACTION="_URL_" METHOD=POST>
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="1000">
Send this file: <INPUT NAME="userfile" TYPE="file">
<INPUT TYPE="submit" VALUE="Send File">
</FORM>
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 hardcode 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.
mSQL Support
mSQL stands for mini-SQL and is a small and simple SQL database engine written
by David Hughes. It is available from
ftp://ftp.bond.edu.au/pub/Minerva/msql
PHP/FI supports has a rich set of mSQL support functions:
- msql()
- msql_Connect()
- msql_FieldFlags()
- msql_FieldLen()
- msql_FieldName()
- msql_FieldType()
- msql_FreeResult()
- msql_NumFields()
- msql_NumRows()
- msql_NumRows()
- msql_Result()
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.
PHP/FI Script Language
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.
Syntax
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.
Variables
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;
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.
Variable Variables
Sometimes it is convenient to be able to have variable variable names.
That is, a variable name which can be set and used dynamically.
A normal variable is set with a statement such as:
$a = "hello";
A variable variable takes the value of a variable and treats that as the
name of a variable. In the above example, hello, can
be used as the name of a variable by using two dollar signs. ie.
$$a = "world";
At this point two variables have been defined and stored in the PHP/FI
symbol tree:
Variable Name Variable Content
a hello
hello world
Therefore, this statement:
echo "$a $$a";
produces the exact same output as:
echo "$a $hello";
ie. they both produce: hello world
Language Constructs
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;
>
Note that another difference between the PHP language and the C language
is that no curly braces are used and that you need to put a separator
after if and while statements.
It is important to note that the flow of the language is not dependant
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>
Mathematical Expressions
Also introduced in the above example was a mathematical expression.
PHP supports full mathematical operations anywhere an expression is
expected. Order of operations are taken into account. The following
are the valid operators:
<? $a = 2 + 1 > Addition
<? $a = 2 - 1 > Subtraction
<? $a = 2 * 1 > Multiplication
<? $a = 2 / 1 > Division
<? $a = 2 % 1 > Modulus
Both bracketing and order of operations is supported, so the following
is valid:
<?$a = (2+1)*3+6/3>
The C-like incremental operators += and -= are
supported. ie.
<? $a += $b>
This is equivalent to:
<? $a = $a + $b>
The C-like bit-wise operators &= and |= are
supported. ie.
<? $a &= 4>
This is equivalent to:
<? $a = $a & 4>
While Loops
You can loop within a PHP script by using the while(); endwhile; construct.
<?
$a=0;
while($a<100);
$a++;
echo $list[$a];
endwhile;
>
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.
Switch Construct
PHP supports a switch construct very similar to the C equivalent.
<?
$a=0;
switch($a);
case 1;
echo "a is 1";
break;
case "hello";
echo "a is hello";
break;
default;
echo "a is unknown";
break;
endswitch;
>
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 braces nor colons.
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.
Secure Variables - Defeating GET method hacks
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 secure 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.
Overloaded Operators and dealing with variable types
An overloaded operator is an operator like '+' for example which can do different things
based on the types of the expressions it is asked to operate on.
The problem is that PHP understands 3 variable types. Integer,
Double and String. When a variable is first assigned, PHP
automatically figures out the variable type.
ie.
$a = 1; Type would be integer
$b = 1.5; Type would be double
$c = "1"; Type would be string
Now, what happens when you do something like:
$d = $a + $c;
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.
Supressing Errors from function calls
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.
Functions
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.
Alphabetical List of Functions
- BinDec(binary_string)
- 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.
- ChDir(dir)
- ChDir changes the current working directory to the directory
specified in the argument.
- ChGrp(file,group)
- ChGrp changes the group id of the specified file.
- ChMod(file,perms)
- ChMod changes the file permissions of the specified file. The perms
parameter must be specified in octal.
- ChOwn(file,owner)
- ChOwn changes the specified file to be owned by the specified owner. Note
that this will only work if the PHP/FI binary is running as root (which is not
generally a good idea).
- closeDir()
- closeDir closes a directory opened using the
openDir function.
- Count(array)
- Count returns the number of items in an array variable. If the
variable is not an array, the return value will be 1. If the variable
is not defined, the return value will be 0.
- Crypt(string,[salt])
- 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.
- Date(format,time)
- 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:
- Y - Year eg. 1995
- y - Year eg. 95
- M - Month eg. Oct.
- m - Month eg. 10
- D - Day eg. Fri.
- d - Day eg. 27
- z - Day of the year eg. 299
- H - Hours in 24 hour format eg. 13
- h - Hours in 12 hour format eg. 1
- i - Minutes eg. 5
- s - Seconds eg. 40
- U - Seconds since epoch eg. 814807830
- dbList(filename)
- dbList outputs information about the db support compiled into PHP.
- dbmClose(filename)
- dbmClose simply closes the specified dbm file. It will also
unlock any lock files, so it is important to close any dbm files that
have been opened.
- dbmDelete(filename,key)
- dbmdelete will delete the key/content pair specified by the given key argument.
- dbmFetch(filename,key)
- dbmFetch will return the content string associated with the given key.
- dbmFirstKey(filename)
- 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.
- dbmInsert(filename,key,content)
- dbmInsert inserts a new key/content data pair into a dbm file. If the
key already exists, the insert will fail.
- dbmNextKey(filename,key)
- dbmNextKey returns the next key after the specified key. By calling dbmfirstkey()
followed by successive calls to dbmnextkey() it is possible to visit every key/content
pair in the dbm file.
- dbmOpen(filename)
- dbmOpen() opens a dbm file. The argument is the full-path filename
of the dbm file to be opened. 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.
- dbmReplace(filename,key,content)
- dbmReplace is similar to the dbminsert() function, the only
difference being that if the key already exists, the old content string will
be replaced with the new.
- DecBin(number)
- 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.
- DecHex(number)
- DecHex converts a decimal number to a hexadecimal string. See also
the HexDec() function.
- DecOct(number)
- DecOct converts a decimal number to an octal number. See also
OctDec().
- doubleval(variable)
- strval returns the double (floating point) value of the variable. See also
the strval() and intval()
functions.
- Echo [format_string] expression
- 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. The special escape characters,
\n, \r and \t can be used to output newlines,
carriage returns and tabs respectively. 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. One
large restriction when using the format string is that only a single
argument can be formatted.
- Exec(command_string,[array])
- 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 the array argument is present, then the specified array will be filled
with every line of output from the unix command starting at array[0].
- Exit
- The Exit command is used to terminate parsing right away as soon
as this tag is parsed.
- fclose(fd)
- fclose() closes a file opened by fopen().
The argument is a file descriptor as returned by the fopen()
call.
- fgets(fd,bytes)
- fgets() reads a line from a file opened by fopen().
Arguments are a file descriptor 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(filename)
- fileAtime returns the time of last data access.
- fileCtime(filename)
- fileCtime returns the time of last status change.
- fileGroup(filename)
- fileGroup returns the group id of the owner of the file.
- fileInode(filename)
- fileInode returns the file's inode.
- fileMtime(filename)
- fileMtime returns the time of last data modification.
- fileOwner(filename)
- fileOwner returns the uid of the owner of the file.
- filePerms(filename)
- filePerms returns the permission bits of the file. This is the
st_mode field of the Unix C stat structure.
- fileSize(filename)
- fileSize returns the size of the file in bytes.
- fd = fopen(filename,mode)
- fopen() opens a file and returns a file descriptor. 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.
- fputs(fd,string)
- fputs() writes a line to a file opened by fopen().
Arguments are a file descriptor 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().
- fseek(fd,pos)
- 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().
- pos = ftell(fd)
- ftell() returns the position of a file pointer identified by the
fd argument which is the return value of the fopen()
call. The position can later be used as an argument to fseek().
See also ftell() and rewind().
- getAccDir()
- getAccDir returns the directory where PHP access configuration files
are kept. The access configuration filenames come from the numerical user
id of the user whose access configurations they represent.
- getHostByName(domain_name)
- getHostByName converts the given domain name into an IP address
in nnn.nnn.nnn.nnn format.
- getHostByAddr(ip_address)
- getHostByAddr converts the given IP address in nnn.nnn.nnn.nnn
format into a fully qualified domain name.
- getLastAccess()
- 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.
- getLastbrowser()
- getLastBrowser returns the identification string of browser the
last user to access the current page used. This function is only
available if PHP was compiled with Access Logging enabled.
- getLastEmail()
- getLastEmail returns the E-Mail address of the last user to access the
current page. This function is only available if PHP was compiled
with Access Logging enabled.
- getLastHost()
- getLastHost returns the hostname of the last user to access the
current page. This function is only available if PHP was compiled
with Access Logging enabled.
- getLastMod()
- 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.
- getLastref()
- getLastRef returns the URL of the referring document of the
last user to access the current page. This function is only available if
PHP was compiled with Access Logging enabled.
- getLogDir()
- 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.
- getMyInode()
- getMyInode returns the numerical inode of the current HTML file.
- getMyPid()
- getMyPid() returns the current process id of the php parsing
process.
- getMyUid()
- getMyUid returns the numerical user id of the owner of the current
HTML file.
- getRandMax()
- 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.
- getToday()
- getToday returns the total number of hits the current page has
had since 12 midnight local time. This function is only available if
PHP was compiled with Access Logging enabled.
- getTotal()
- getTotal returns the total number of hits the current page has
had since access logging was started on the page. This function is
only available if PHP was compiled with Access Logging enabled.
- GetType(variable)
- GetType returns the type of the variable. The return value is a string
and it is one of, "integer", "double" or "string".
See also the SetType() function
- gmDate(format,time)
- gmDate is identical to the Date function
except for the fact that it uses Greenwich Mean Time instead of the current
local time.
- Header "header_string"
- 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.
- HexDec(hex_string)
- HexDec converts a hexadecimal string to a decimal number. See also
the DecHex() function.
- ImageArc(im, cx, cy, w, h, s, e, col)
- 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(im, size, x, y, c, col)
- 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(im, size, x, y, c, col)
- 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.
- col = ImageColorAllocate(im, red, green, blue)
- 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(im, col)
- 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 PHP support has been enabled in PHP.
- im = ImageCreate(x_size, y_size)
- ImageCreate returns an image identifier representing a blank image of size
x_size by y_size. This function is only available if GD support has been
enabled in PHP.
- ImageDestroy(im)
- ImageDestroy frees any memory associated with image im. im is the image
identifier returned by the ImageCreate function. This
function is only available if GD support has been enabled in PHP.
- ImageFill(im, x, y, col)
- ImageFill performs a flood fill starting at coordinate x,y (top left is 0,0) with
colour col in image im. This function is only available if GD support has been
enabled in PHP.
- ImageFilledPolygon(im, points, num_points, col)
- 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(im, x1, x2, y1, y2, col)
- 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(im, x, y, border, col)
- 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(im, filename)
- ImageGif creates the GIF file in filename from the image im. The im argument is
the return from the ImageCreate function. This function is
only available if GD support has been enabled in PHP.
- ImageInterlace(im, interlace)
- 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.
- ImageLine(im, x1, y1, x2, y2, col)
- ImageLine draws a line from x1,y1 to x2,y2 (top left is 0,0) in image
im of colour col.
This function is only available if GD support has been enabled in PHP.
- ImagePolygon(im, points, num_points, col)
- 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(im, x1, x2, y1, y2, col)
- 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.
- ImageSetPixel(im, x, y, col)
- ImageSetPixel draws a pixel at x,y (top left is 0,0) in image
im of colour col.
This function is only available if GD support has been enabled in PHP.
- ImageString(im, size, x, y, s, col)
- 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(im, size, x, y, s, col)
- 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.
- Include filename
- 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.
- intval(variable)
- strval returns the long integer value of the variable. See also
the strval() and doubleval()
functions.
- IsSet(variable)
- The IsSet function returns 1 if the given variable is defined,
and 0 if it isn't.
- Max(array)
- 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.
- Min(array)
- 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.
- MkDir(dir,mode)
- MkDir creates a directory. The mode parameter must be
given in octal notation.
- MkTime(hour,min,sec,mon,day,year)
- 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.
- $result = msql(database,query)
- msql sends an mSQL query. Arguments are the database name and the query
string. ie. <?msql("MyDatabase"quot;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.
This function is only available if mSQL support has been enabled in PHP.
- msql_connect(hostname)
- 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_FieldFlags(result,i)
- msql_FieldFlags returns the field flags of the speficied 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_FieldLen(result,i)
- msql_FieldLen returns the length of the specified field.
This function is only available if mSQL support has been enabled in PHP.
- msql_FieldName(result,i)
- 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(result,i)
- 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(result)
- 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_NumFields(result)
- msql_NumFields returns the number of fields 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_NumRows(result)
- 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(string)
- 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]".
- msql_Result(result,i,field)
- 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:
<?
msql_connect("localhost");
$name = "bob";
$result = msql($database,"select * from table where firstname='$name'");
$num = msql_numrows($result);
echo "$num records found!<p>";
$i=0;
while($i<$num);
echo msql_result($result,$i,"fullname");
echo "<br>";
echo msql_result($result,$i,"address");
echo "<br>";
$i++;
endwhile;
>
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.
This function is only available if mSQL support has been enabled in PHP.
- OctDec(octal_number)
- OctDec converts an octal number to a decimal number. See also
DecOct().
- openDir(directory)
- openDir opens the speficied 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.
- PutEnv(string)
- 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()
- Rand returns a random number between 0 and RANDMAX. RANDMAX can be
determined with the getRandMax function. Normally
a specific range is chosen by simply using the modulus operator on the result.
- readDir()
- 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.
- reg_Match(expr,arg)
- 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.
- reg_replace(expr,replace,arg)
- 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").
- reg_Search(expr,arg)
- 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.
- Rename(old,new)
- Rename filename old to new. Similar to the Unix C
rename() function.
- rewind(fd)
- rewind() resets 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.
See also ftell() and fseek().
- rewindDir()
- rewindDir moves the current directory pointer back to the
beginning of the directory. Use the openDir
function to open a directory before calling this function.
- SetLogging(arg)
- SetLogging() either enables or disables the logging of access
statistics for a page. If arg is
non-zero, logging will be enabled, if zero, disabled.
- SetShowInfo(arg)
- SetShowInfo() either enables or disables the information footer
at the bottom of all pages loaded through PHP. If arg is
non-zero, the footers will be enabled, if zero, disabled.
- SetType(variable,type)
- SetType sets the type of a variable. The type argument
is one of, "integer", "double" or "string".
See also the GetType() function.
- Sleep(secs)
- Sleep will delay for secs seconds. Similar to the Unix C sleep()
function. See also the USleep() function.
- Sort(array)
- Sort is used to sort a PHP array in ascending order. 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.
- Srand(integer)
- Srand seeds the random number generator. This function takes
any integer as an argument. One choice is to use the date
function to give you the current number of seconds past the minute.
ie.
<?srand(date("s"))>
- strchr(string,arg)
- strchr and strstr are actually identical functions. They
can be used interchangebly 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".
- strlen(string)
- strlen returns the length of the string.
- strrchr(string,arg)
- strrchr is identical to strchr except for the
fact that it will start at the end of the string and search backwards for
a match.
- strstr(string,arg)
- strstr and strchr are actually identical functions. They
can be used interchangebly 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(string,arg)
- 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:
<?
$string = "This is an example string";
$tok = strtok($string," ");
while($tok);
echo "Word=$tok<br>";
$tok = strtok(" ");
endwhile;
>
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.
- strtolower(string)
- strtolower converts the string argument to all lower case characters.
- strtoupper(string)
- strtoupper converts the string argument to all upper case characters.
- strval(variable)
- strval returns the string value of the variable. See also
the intval() and doubleval()
functions.
- substr(string, start, length)
- 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.
- System(command_string)
- System is just like the C system() command in that it excutes
the given unix command and outputs the result. See also the
Exec function.
- TempNam(path, prefix)
- TempNam returns a unique filename located in the directory indicated
by path with filename prefix given by prefix. It is identical to the
Unix C tempnam() function.
- Time()
- Time simply returns the current local time in seconds
since Unix epoch. It is equivalent to calling
Date("U").
- Unlink(filename)
- Unlink deletes the given filename. Similar to the Unix C unlink() function.
- USleep(microsecs)
- Sleep will delay for the given number of microseconds. Similar to the Unix C usleep()
function. See also the Sleep() function.
Adding your own functions to PHP/FI
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
- 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.
For the Time() example we add:
%token TIME
Next, we add the actual function grammar. Look for a large block
preceded by func:. This block contains a list of
all the PHP/FI functions. You may add your function anywhere in this
list. The Time() entry looks like this:
| TIME '(' ')'
{
if(GetCurrentState(NULL) || inCase || inElseIf) UnixTime();
}
The fact that there is nothing between the '(' ')' means that the function
does not take any arguments. The actual name of the function to be called
internally in PHP in this example is UnixTime(). The condition
before the function call is essential. The GetCurrentState(NULL)
call returns the current state from the state machine. If we are in an
inactive state for some reason, the function should not be called. The
inCase and inElseIf checks specify that the function is
allowed to be called both in case and elseif blocks. This should be
true of any function you add.
- 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 dimensinal 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 simply 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",TIME },
This entry maps a string to the token you defined in parse.raw. 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.
- 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:
void UnixTime(void) {
char temp[32];
sprintf(temp,"%ld",(long)time(NULL));
Push(temp,LNUMBER);
}
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 epxression 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. 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.
The Crypt() Grammar in parse.raw:
%token CRYPT
.
.
.
| CRYPT '(' expr ',' expr ')'
{
if(GetCurrentState(NULL) || inCase || inElseIf) Crypt(1);
}
| CRYPT '(' expr ')'
{
if(GetCurrentState(NULL) || inCase || inElseIf) Crypt(0);
}
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.
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 },
The actual Crypt() function in crypt.c:
/*
* If mode is non-zero, a salt is expected.
* If mode is zero, a pseudo-random salt will be selected.
*/
void Crypt(int mode) {
#if HAVE_CRYPT
Stack *s;
char salt[8];
char *enc;
salt[0] = '\0';
if(mode) {
s = Pop();
if(!s) {
Error("Stack error in crypt");
return;
}
if(s->strval) strncpy(salt,s->strval,2);
}
s = Pop();
if(!s) {
Error("Stack error in crypt");
return;
}
if(!salt[0]) {
salt[0] = 'A' + (time(NULL) % 26);
salt[1] = 'a' + (time(NULL) % 26);
salt[2] = '\0';
}
enc = (char *)crypt(s->strval,salt);
#if DEBUG
Debug("Crypt returned [%s]\n",enc);
#endif
Push(enc,STRING);
#else
Error("No crypt support compiled into this version");
#endif
}
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):
/* Expression Stack */
typedef struct Stack {
short type;
unsigned char *strval;
long intval;
double douval;
VarTree *var;
struct Stack *next;
} Stack;
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 is 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.