KNOWLEDGE BASE
Log In    |    Knowledge Base    |    4D Home
Tech Note: Using External PHP Interpreters in 4D v12
PRODUCT: 4D | VERSION: 12 | PLATFORM: Mac & Win
Published On: November 12, 2010

4D v12 contains the ability to run PHP scripts within 4D by using an internal or external PHP interpreter. This Technical Note will focus on the external interpreter aspect, including the requirements that must be met. The Technical Note will also go into detail regarding how to setup an external PHP interpreter on Windows and Mac operating systems.

Download Complete Tech Note and Example: Windows | Mac

Commented by Pascal Foubert on November 20, 2010 at 6:00 AM
In addition to this technote, which is not very detailled, take in accout these infos :
Note that to add a new extension to php (a .so or .dll) you need to create your own php fastcgi interpreter.

The problem is that with your own php interpreter 4D won't manage it for you. It means you HAVE to start/stop/restart it when need.

A good way is to put the interpreter in your resources folder.

On Mac OSX I recommend to use spawn-fcgi (from lighttpd) and a bash script, then use LEP to start/stop your php interpreter on start and on close base method (or when you want)

The bash script can be like this
#!/bin/bash
# Shell Script to start / stop PHP FastCGI using spawn-fcgi binary file.

PROVIDES=php-fcgi
SPAWN_FCGI=spawn-fcgi
SERVER_IP=127.0.0.1
SERVER_PORT=8102
PHP_CGI=php-fcgi
GREP=/usr/bin/grep
KILLALL=/usr/bin/killall
PHP_FCGI_CHILDREN=5
PHP_FCGI_MAX_REQUESTS=500

### DO NOT CHANGE ####
cmd=$1

pcgi_start(){
export PHP_FCGI_CHILDREN
export PHP_FCGI_MAX_REQUESTS

echo "Starting $PROVIDES..."
$SPAWN_FCGI -a $SERVER_IP -p $SERVER_PORT $PHP_CGI
}

pcgi_stop(){
echo "Killing $PROVIDES..."
$KILLALL $PROVIDES
}

pcgi_restart(){
pcgi_stop
pcgi_start
}

pcgi_status(){
ps aux | grep $PROVIDES | grep -v grep > /dev/null
[ $? -eq 0 ] && echo "$PROVIDES running" || echo "$PROVIDES NOT running"

}

pcgi_help(){
echo "Usage: $0 {start|stop|restart|status}"
}

case ${cmd} in
[Ss][Tt][Aa][Rr][Tt]) pcgi_start;;
[Ss][Tt][Oo][Pp]) pcgi_stop;;
[Rr][Ee][Ss][Tt][Aa][Rr][Tt]) pcgi_restart;;
[Ss][Tt][Aa][Tt][Uu][Ss]) pcgi_status 0;;
*) pcgi_help ;;
esac

Note that we'll start 5 php-fcgi processes. Not one. And every processes will be restarted every 500 requests

So in your resources folder, put :
- php-fcgi (php interpreter)
- spawn-fcgi (from lighttpd)
- php_gest.sh (your bash script)
- php.ini (the php ini file in which you'll define a new extension_dir for example)

Then in 4D you could use a method which start/stop/restart/ask status
C_TEXT($1;$cmd)
C_TEXT($in)
C_POINTER($2;$out;$3;$err)

ASSERT(Count parameters>0;"3 Parameters are required")
ASSERT(Count parameters>1;"2 parameters are missing")
ASSERT(Count parameters>2;"1 parameters is missing")
ASSERT(Test path name(Get 4D folder(Current Resources folder)+"php_.sh")=Is a document;"Php starter is missing")
ASSERT(Test path name(Get 4D folder(Current Resources folder)+"php-fcgi")=Is a document;"Php-fcgi is missing")
ASSERT(Test path name(Get 4D folder(Current Resources folder)+"php.ini")=Is a document;"Php.ini is missing")

ASSERT($1#"";"Parameter value pbm")
$cmd:=$1
ASSERT((Not(Nil($2)));"Pointer invalid")
ASSERT((Not(Nil($3)));"Pointer invalid")
ASSERT((Type($2->)=Is Text);"Params 2 must be a pointer on a txt var")
ASSERT((Type($3->)=Is Text);"Params 3 must be a pointer on a txt var")
$out:=$2
$err:=$3
SET ENVIRONMENT VARIABLE("_4D_OPTION_CURRENT_DIRECTORY";Get 4D folder(Current Resources folder))

Case of
: ($cmd="start")
SET DATABASE PARAMETER(PHP Use external interpreter;1)
SET DATABASE PARAMETER(PHP Interpreter IP address;"127.0.0.1")
SET DATABASE PARAMETER(PHP Interpreter port;8102)

LAUNCH EXTERNAL PROCESS("php_.sh start";$in;$out->;$err->)

: ($cmd="stop")
LAUNCH EXTERNAL PROCESS("php_.sh stop";$in;$out->;$err->)

: ($cmd="status")
LAUNCH EXTERNAL PROCESS("php_.sh status";$in;$out->;$err->)

: ($cmd="restart")
LAUNCH EXTERNAL PROCESS("php_.sh restart";$in;$out->;$err->)

End case


Then on method base On Startup you can do a simple
C_TEXT($out;$error)
PHP_Gest ("start";->$out;->$error)

to stop
PHP_Gest ("stop";->$out;->$error)

to restart
PHP_Gest ("restart";->$out;->$error)

to get the status
PHP_Gest ("status";->$out;->$error)

Hope it will help