|
PHP
Basically PHP is text interpreter, such Perl. It takes a text as input and it produces text.
PHP is mainly used to build dynamic web pages. In the HTML file, PHP's instructions (similar to C)
are found between PHP's tags (<?PHP instructions ?>).
Using PHP's instructions we can produce whatever text we want. We can produce HTML of course,
but it is not an obligation. You can generate JavaScript, Java, ... anything that will be
executed on the client machine. In a Web environment you should produce a Web-compatible
code (I meam anything that can be interpreted by the client browser). But you can also
generate any kind of text that has nothing to do with Web.
A PHP file (I mean the file that contains PHP's instructions) is not a CGI. That is you
should not put it into the "cgi-bin" directory. You should put it in the "htdocs" directory
instead (or whatever directory you specified in your "httpd.conf").
A CGI executes itself within the OS. Depending on the method used to pass data to the CGI,
the latter will read it from the standard input (POST) or from the environment-variable
QUERY_STRING (GET). Then it will produce print text to the standard output (STDOUT).
A PHP file is just a simple text file, this is not a program. This file is parsed by the
PHP interpreter to produce whaterver text you want. Usually the PHP interpreter is binded into
the Web server (this could be done via dynamically loadable libraries for example).
The following show you how to install PHP4 as a dymamic module. This assumes that:
- Apache will be installed under /home/hpptd.
- MySql will be installed under /home/mysql.
- libmcrypt will be installed under /home/libmcrypt.
- PHP4 will be installed under /home/php4. PHP4 will be compiled with mcrypt support.
- The configuration file "php.ini" will be put under "/home/php4/config".
- The dynamically loadable modules will be put under "/home/php4/modules".
- You are using bash.
- You are running Linux.
su - root
./configure --prefix=/home/httpd --enable-module=so
notes:
- "--prefix=/home/httpd" install Apache under "/home/httpd".
- "--enable-module=so" for PHP (as a dynamically loadable module).
make
make install
OK, now we need to setup the correct path to Apache binaries. Edit your "/etc/profile"
and add the following line (before the "export" of course):
PATH=${PATH}:/home/httpd/bin
And the reload your environment (you can logout and login again for example).
Now type "httpd -l" and make sure that you see the following line:
"mod_so.c"
./configure --prefix=/home/mysql
make
make install
If you are on Linux and have installed shared libraries, make sure the location of these
shared libraries are listed in your /etc/ld.so.conf file. For example, if you have:
/home/mysql/lib/mysql/libmysqlclient.so
Make sure /etc/ld.so.conf contains:
/home/mysql/lib/mysql
Then run ldconfig.
OK, now we need to setup the correct path to MySql binaries. Edit your "/etc/profile"
and add the following line (before the "export" of course):
PATH=${PATH}:/home/mysql/bin
Then reload your environment.
Create the MySQL grant tables (necessary only if you haven't installed MySQL before): In the MySql install directory,
type:
"scripts/mysql_install_db".
To start the server, type:
safe_mysqld & (note that the right PATH should be loaded now)
There is nothing difficult, just type:
./configure --prefix=/home/libmcrypt --disable-posix-threads
make
make install
Then edit /etc/ld.so.conf and add the line:
/home/libmcrypt/lib
Then run ldconfig
This is very simple, just type:
./configure --with-mysql=/home/mysql --with-apxs --prefix=/home/php4 --with-mcrypt=/home/libmcrypt --with-config-file-path=/home/php4/config
make
make install
Add the following line to your "/etc/profile" (before the "export"):
PATH="${PATH}:/home/php4/bin"
Then add the following line to your "/etc/profile":
export PHPRC=/home/php4/lib/
This will tell PHP where to find its libraries.
Then reload your environment.
Copy the generic configuration file to the "/home/php4/config/" directory.
cp ./php.ini-dist /home/php4/config/php.ini
Edit the file "/home/php4/config/php.ini" and set the variable "extension_dir" to "/home/php4/modules". This will
tell PHP4 to search for dinamically loadable modules (.so) into the directory "/home/php4/modules".
And then unable Apache to load PHP. Uncomment the PHP4 related lines in your httpd.conf
file. This should look like something like:
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
Then restart your server (apachectl restart) and you should be able to serve up PHP
files now. Note that to start Apache, type "apachectl start", assuming that the correct
PATH is set to /home/http/bin.
Go to the directoty /home/httpd/htdocs and edit the file "ex.php":
<HTML>
<BODY>
<?PHP print "toto"; ?>
</BODY>
</HTML>
Then run Netscape (or any browser) and enter the URL:
http://localhost/ex.php
You should see "toto".
newfunc.h |
#ifndef PHP_NEWFUNCTION_H
#define PHP_NEWFUNCTION_H
PHP_FUNCTION(newfunction1);
#endif
|
newfunc.c |
#include <stdio.h>
#include "php.h"
#include "php_ini.h"
#include "newfunc.h"
function_entry newfunc_functions_entry[] =
{
PHP_FE(newfunction1, NULL)
{NULL, NULL, NULL}
};
zend_module_entry newfunc_module_entry =
{
"newfunc", /* name */
newfunc_functions_entry, /* function_entry */
NULL, /* initializator */
NULL, /* destructor */
NULL, /* startup */
NULL, /* shutdown */
NULL, /* info */
STANDARD_MODULE_PROPERTIES
};
DLEXPORT zend_module_entry *get_module(void) { return &newfunc_module_entry; }
PHP_FUNCTION(newfunction1)
{
pval *arg1, *arg2;
/************************************************************************/
/* Make sure that we have two arguments */
/************************************************************************/
if (ARG_COUNT(ht) != 2) { WRONG_PARAM_COUNT; }
/************************************************************************/
/* Get the two arguments from the arguments' list */
/************************************************************************/
if (getParameters(ht,2,&arg1,&arg2)==FAILURE) { WRONG_PARAM_COUNT; }
/************************************************************************/
/* Make sure we have 'long' values */
/************************************************************************/
convert_to_long(arg1);
convert_to_long(arg2);
/************************************************************************/
/* Calculate arg1 + arg2 */
/************************************************************************/
RETURN_LONG(arg1->value.lval + arg2->value.lval);
}
|
Note 1
If you search into the PHP4 header files, you can find the following peaces of code:
if the file: "main/php3_compat.h":
typedef zval pval;
This means that if you want to write portable code that can be used with PHP3, you should use "pval" instead of "zval".
typedef struct _zval_struct zval;
struct _zval_struct
{
zvalue_value value;
zend_uchar type;
zend_uchar is_ref;
zend_ushort refcount;
};
The value "type" could be:
IS_NULL 0
IS_LONG 1
IS_DOUBLE 2
IS_STRING 3
IS_ARRAY 4
IS_OBJECT 5
IS_BOOL 6
IS_RESOURCE 7
IS_CONSTANT 8
IS_CONSTANT_ARRAY 9
With zvalue_value:
typedef union _zvalue_value
{
long lval; <= long value
double dval; <= double value
struct
{
char *val;
int len;
} str;
HashTable *ht; <= hash table value
struct
{
zend_class_entry *ce;
HashTable *properties;
} obj;
} zvalue_value;
Note 2
the line
RETURN_LONG(arg1->value.lval + arg2->value.lval);
could have been replaced by:
return_value->value.lval = arg1->value.lval + arg2->value.lval;
return_value->type = IS_LONG;
But the first method is certainly better. Indeed, if the "zval" (or "pval") structure changes, then the macro "RETURN_LONG" will be updated and you won't have to change your code.
Note 3
If you look at the file "Zend/zend_operators.h", you find the function used to convert PHP's objects:
ZEND_API void convert_scalar_to_number(zval *op);
ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC);
ZEND_API void convert_to_long(zval *op);
ZEND_API void convert_to_double(zval *op);
ZEND_API void convert_to_long_base(zval *op, int base);
ZEND_API void convert_to_null(zval *op);
ZEND_API void convert_to_boolean(zval *op);
ZEND_API void convert_to_array(zval *op);
ZEND_API void convert_to_object(zval *op);
ZEND_API void multi_convert_to_long_ex(int argc, ...);
ZEND_API void multi_convert_to_double_ex(int argc, ...);
ZEND_API void multi_convert_to_string_ex(int argc, ...);
ZEND_API int add_char_to_string(zval *result, zval *op1, zval *op2);
ZEND_API int add_string_to_string(zval *result, zval *op1, zval *op2);
#define convert_to_string(op) _convert_to_string((op) ZEND_FILE_LINE_CC)
Makefile |
#########################################################
# Generic Makefile for PHP dinamically loadable modules #
#########################################################
CC = gcc
#########################################################
# Where to put PHP's dinamically loadable modules #
#########################################################
PHP_MODULE_PATH = /home/php4/modules
#########################################################
# Where to fing PHP's header files #
#########################################################
PHP_TOP = /home/php4/include/php
PHP_TSRM = ${PHP_TOP}/TSRM
PHP_ZEND = ${PHP_TOP}/Zend
PHP_EXT = ${PHP_TOP}/ext
PHP_MAIN = ${PHP_TOP}/main
PHP_REGEX = ${PHP_TOP}/regex
#########################################################
# Compiler's options #
#########################################################
CFLAGS = -I${PHP_TOP} \
-I${PHP_TSRM} \
-I${PHP_ZEND} \
-I${PHP_EXT} \
-I${PHP_MAIN} \
-I${PHP_REGEX} \
-DCOMPILE_DL
# -shared
# Produce a shared object which can then be linked with other objects to form an executable. Only a
# few systems support this option.
# -fPIC
# If supported for the target machine, emit position-independent code, suitable for dynamic linking,
# even if branches need large displacements.
CFLAGSSO = -shared -fPIC -ldl
newfunc.o: newfunc.c \
newfunc.h
${CC} ${CFLAGS} -c newfunc.c
newfunc.so: newfunc.o
${CC} ${CFLAGSSO} -o newfunc.so newfunc.o
all: newfunc.so
install: newfunc.so
cp newfunc.so ${PHP_MODULE_PATH}/
clean:
rm newfunc.o newfunc.so
|
ex.php |
<HTML>
<BODY>
<?PHP
print "<BR>Test for the dunamically loadable module <I>newfunc</i></BR>";
dl("newfunc.so");
$a=1;
$b=2;
print "<BR>a = $a";
print "<BR>b = $b";
$c = newfunction1($a,$b);
print "<BR>c = newfunction1(a,b) = $c";
?>
</BODY>
</HTML>
|
result |
test for the dunamically loadable module newfunc
a = 1
b = 2
c = newfunction1(a,b) = 3
|
The file "newfunc.c" is modified:
newfunc.c |
#include <stdio.h>
#include "php.h"
#include "php_ini.h"
#include "newfunc.h"
function_entry newfunc_functions_entry[] =
{
PHP_FE(newfunction1, NULL)
{NULL, NULL, NULL}
};
zend_module_entry newfunc_module_entry =
{
"newfunc", /* name */
newfunc_functions_entry, /* function_entry */
NULL, /* initializator */
NULL, /* destructor */
NULL, /* startup */
NULL, /* shutdown */
NULL, /* info */
STANDARD_MODULE_PROPERTIES
};
DLEXPORT zend_module_entry *get_module(void) { return &newfunc_module_entry; }
PHP_FUNCTION(newfunction1)
{
pval *arg1, *arg2;
long resultat;
/************************************************************************/
/* Make sure that we have two arguments */
/************************************************************************/
if (ARG_COUNT(ht) != 2) { WRONG_PARAM_COUNT; }
/************************************************************************/
/* Get the two arguments from the arguments' list */
/************************************************************************/
if (getParameters(ht,2,&arg1,&arg2)==FAILURE) { WRONG_PARAM_COUNT; }
/************************************************************************/
/* Make sure we have 'long' values */
/************************************************************************/
convert_to_long(arg1);
convert_to_long(arg2);
/************************************************************************/
/* Calculate arg1 + arg2 */
/************************************************************************/
resultat = arg1->value.lval + arg2->value.lval;
arg1->value.lval *= 10;
RETURN_LONG(resultat);
}
|
And the PHP script becomes:
ex.php |
<HTML>
<BODY>
<?PHP
print "<BR>Test for the dunamically loadable module <I>newfunc</i></BR>";
dl("newfunc.so");
$a=1;
$b=2;
print "<BR>a = $a";
print "<BR>b = $b";
$c = newfunction1($a,$b);
print "<BR>c = newfunction1(a,b) = $c";
print "<BR>a = $a";
?>
</BODY>
</HTML>
|
The result is:
result |
test for the dunamically loadable module newfunc
a = 1
b = 2
c = newfunction1(a,b) = 3
a = 1
|
As you can see, the value of "a" is 1 and not 10.
The following code does exactly the same thing that the previous one (this is just another way to write C code - but it is totally equivalent):
newfunc.c |
#include <stdio.h>
#include "php.h"
#include "php_ini.h"
#include "newfunc.h"
...
PHP_FUNCTION(newfunction1)
{
pval **arg1, **arg2;
long resultat;
/************************************************************************/
/* Make sure that we have two arguments */
/************************************************************************/
if (ARG_COUNT(ht) != 2) { WRONG_PARAM_COUNT; }
/************************************************************************/
/* Get the two arguments from the arguments' list */
/************************************************************************/
if (getParameters(ht,2,arg1,arg2)==FAILURE) { WRONG_PARAM_COUNT; }
/************************************************************************/
/* Make sure we have 'long' values */
/************************************************************************/
convert_to_long(*arg1);
convert_to_long(*arg2);
/************************************************************************/
/* Calculate arg1 + arg2 */
/************************************************************************/
resultat = (*arg1)->value.lval + (*arg2)->value.lval;
(*arg1)->value.lval *= 10;
RETURN_LONG(resultat);
}
|
OK, now lets play with strings. One thing you must know is that ALL string returned by a PHP function must have been allocated using emalloc(). PHP will free it (using "efree"), so if you did not use emalloc ... you are in big trouble.
There are two kinds of memory in this program. Memory which is returned
to the parser in a variable and memory which you need for temporary
storage in your internal function. When you assign a string to a
variable which is returned to the parser you need to make sure you first
allocate the memory with either emalloc or estrdup. This memory
should NEVER be freed by you, unless you later, in the same function
overwrite your original assignment (this kind of programming practice is
not good though).
For any temporary/permanent memory you need in your functions/library you
should use the three emalloc(), estrdup(), and efree() functions. They
behave EXACTLY like their counterpart functions. Anything you emalloc()
or estrdup() you have to efree() at some point or another, unless it's
supposed to stick around until the end of the program, otherwise there
will be a memory leak. The meaning of "the functions behave exactly like
their counterparts" is if you efree() something which was not
emalloc()'ed nor estrdup()'ed you might get a segmentation fault. So
please take care and free all of your wasted memory. One of the biggest
improvements in PHP 3.0 will hopefully be the memory management.
newfunc.c |
#include <stdio.h>
#include "php.h"
#include "php_ini.h"
#include "newfunc.h"
...
char *My_BIN2HEX (char*, const int, int*);
PHP_FUNCTION(newfunction1)
{
pval *string;
char *result;
int new_length;
/************************************************************************/
/* Make sure that we have two arguments */
/************************************************************************/
if (ZEND_NUM_ARGS() != 1) { WRONG_PARAM_COUNT; }
/* or "(ARG_COUNT() != 1) { WRONG_PARAM_COUNT; }" */
/************************************************************************/
/* Get the two arguments from the arguments' list */
/************************************************************************/
if (getParameters(ht,1,&string)==FAILURE) { WRONG_PARAM_COUNT; }
/************************************************************************/
/* Make sure we have a characters' string */
/************************************************************************/
convert_to_string(string);
/* or "convert_to_string_ex(&string);" */
result = My_BIN2HEX (string->value.str.val, string->value.str.len, &new_length);
if (result == NULL) { RETURN_FALSE; }
/* Look at the file "Zend/zend_API.h" to get the list of RETURN_XXX macros */
/* Here we don't duplicate the resulting string (third arg is 0) since we */
/* have allocated "result" using "emalloc". */
RETURN_STRINGL (result, new_length, 0);
}
char *My_BIN2HEX (char *src, const int length, int *new_length)
{
int i;
char *result, aux[3];
/************************************************************************/
/* Use "emalloc()" instead of "malloc()" */
/* Remember that under PHP, resulting strings MUST be allocated by */
/* "emalloc" --- Do NOT use statically allocated strings because PHP */
/* will free it. */
/************************************************************************/
result = (char*)emalloc(2*length*sizeof(char));
if (result == NULL) { return NULL; }
for (i=0; i<length; i++)
{
sprintf (aux, "%2X", (unsigned char)src[i]);
result[2*i] = aux[0];
result[2*i+1] = aux[1];
}
*new_length = 2*length*sizeof(char);
return result;
}
|
Now, lets look at this simple PHP script:
ex.php |
<HTML>
<BODY>
<?PHP
print "<BR>Test for the dunamically loadable module <I>newfunc</i></BR>";
dl("newfunc.so");
$a=1;
$b=2;
print "<BR>a = $a";
print "<BR>b = $b";
$c = newfunction1($a);
print "<BR>c = newfunction1(\"$a\") = $c";
$c = newfunction1("ABCDEFGH");
print "<BR>c = newfunction1(\"ABCDEFGH\") = $c";
?>
</BODY>
</HTML>
|
The result is:
result |
Test for the dunamically loadable module newfunc
a = 1
b = 2
c = newfunction1("1") = 31
c = newfunction1("ABCDEFGH") = 4142434445464748
|
|