Fast CGI

FastCGI origin

IBM i Apache includes an implementation of FastCGI support with DG1 IBM HTTP Server (ILE QZFAST.SRVPGM together with PASE zfcgi). In brief terms, FastCGI allows PASE CGI programs to stay up and running request-2-request to give PASE the same sort of high performance repeat use benefit we see in ILE CGI programs (activation groups). The trick is any FastCGI program must implement FastCGI message/payload techniques documented at fastcgi org link (fastcgi org). This page is a collection of multiple FastCGI tips. Most FastCGI tips for PHP will also work for other PASE FastCGI OS languages compiled/loaded on your IBM i machine (ie, Ruby, perl, Java, etc.).

  • - fastcgi.conf ‘tiny’ testing examples from fastcgi org (see FastCGI configuration this page)
    • Note: fastcgi config tests require additional IBM i PTFs (see this page)
      call qp2term
      cd /www/zendsvr/htdocs/Samples
      > unzip  <-- unzip on laptop if your 400 not have unzip (or Open Source Binaries Yips)
      > tar -xf fcgi-c-or-java-1.0.1.tar
      > cd fcgi
      > cat README.txt                      <-- test instructions 'tiny'
                                                - c fastcgi (libfcgi.a/ static/dynamic servers)
                                                - Java fastcgi (FCGI.jar TCP external servers)
      Hint: everything you need to make your 
            own PASE fastcgi web language 
            using java or c is in zip download

FastCGI flow

FastCGI operations belong to Fasctcgi architecture (below), to wit, only PHP children read http requests / fastcgi commands (unix socket), therefore any new fastcgi protocol would have to be added to fastcgi architecture to be supported by all fastcgi clients like php and ruby, and perl and … all fastcgi clients (picture below). Apache and PASE zfcgi manager start a command line like php, ruby, perl, etc., providing a fastcgi unix domain socket for fastcgi command protocol (/www/zendsvr/logs/fcgi-lhcifocf.sock). zfcgi monitors started “mother”, perhaps may restart a replacement on early/error termination.

browser <---http(80)---> apache (threaded)<-------PASE fcgi start/stop/unix socket------------> PHP "monitor/mother" (StartProcesses="1")
 request<---http(40659)-->apache thread 01<---------------------------------------------------> |<->PHP "child 01" (SetEnv="PHP_FCGI_CHILDREN=2")
browser <---http(80)---> apache (threaded)                                                      |
 request<---http(40658)-->apache thread 02<---------------------------------------------------> |<->PHP "child 02" (SetEnv="PHP_FCGI_CHILDREN=2")
            |                                             fastcgi start request socket--------> /www/zendsvr/logs/fcgi-lhcifocf.sock (unix socket)  
            |                                             wait/poll random PHP child chat       (unix socket "packets" are fastcgi protocol)
            |                                             based on "first grab" unix socket.    
            |                                             Actual work then occurs on apache
            |                                             and client agreed 'private socket'
            |                                             (40658, 40659, etc.).    
            Apache conversation only starts
            on port 80, then handles each
            request client on allocated
            "private socket" (40658, 40659)

Bulletin — Zend Server start 6+ may fail depending on Apache level

if you see ...
QHTTPSVR/QZSRHTTP: No matches for the wildcard '*.conf' in '/usr/local/zendsvr6/etc/sites.d/http/__default__/0', failing(use Include 

Add blank/dummy files for IBM i Apache to start ...
call qp2term
touch /usr/local/zendsvr6/etc/sites.d/globals-blank.conf
touch /usr/local/zendsvr6/etc/sites.d/vhost_blank.conf
touch /usr/local/zendsvr6/etc/sites.d/http/__default__/0/blank.conf

restart Zend Server 

CCSID issues

Have CCSID issues??

Change Zend default CCSID=819 to CCSID=1208 in /www/zendsvr/conf/fastcgi.conf, because 1208 is passed directly through PASE into DB2 to avoid unwanted conversions.

... SetEnv="CCSID=819" SetEnv="LANG=C" ...
... SetEnv="CCSID=1208" SetEnv="LANG=C" ...

; Static PHP servers for default user
Server type="application/x-httpd-php" CommandLine="/usr/local/ZendSvr/bin/php-cgi.bin" StartProcesses="1" SetEnv="QIBM_SRVRMODE_SBS=ZENDSVR" SetEnv="LIBPATH=/usr/local/ZendSvr/lib" SetEnv="PHPRC=/usr/local/ZendSvr/etc/" SetEnv="PHP_FCGI_CHILDREN=10" SetEnv="PHP_FCGI_MAX_REQUESTS=0" ConnectionTimeout="5" RequestTimeout="20" SetEnv="CCSID=1208" SetEnv="LANG=C" SetEnv="INSTALLATION_UID=20111108100706281116" SetEnv="LDR_CNTRL=MAXDATA=0x40000000"

Apache: /www/zendsvr/conf/httpd.conf ← (ILE Apache side)

   DefaultFsCCSID 37 
   CGIJobCCSID 37 
   - This often fixes majority of web script issue


There are many aspects of web security (just Google), but a few fundamentals help IBM i.

Secure your web site against easy hacks (mandatory)

Please remember to secure your web site write access after making changes or creating new Apache instances. Multiple machines have been hacked because they missed these simple steps.

... no write access to this web site, by anyone ...
call qp2term 
> chmod -R 0555 /www/zend3               <--- *RX Owner, *RX Group , *RX to *PUBLIC (r-x)
> chmod -R 0755 /www/zend3/logs          <--- *RWX Owner -- access/error logs need write access 
> chown -R QTMHHTTP /www/zend3           <--- QTMHHTTP owns all objects

Note: -R is recursive walk through all directories/files starting with /path, 
      which is zend3 in the example above (/www/zend3) 

Personal note: As a programmer, my instinct is allow write access owner of files/programs/data (me), but ‘trust myself’ thinking spills into web security, ultimately leads to geek vs. hacker, perhaps best avoided allowing nobody write access to web site (chmod -R 0555 /www, except for /logs).

ServerUserID and FastCGIServerID (2013–03–14)

  • Yes — PTFs FastCGIServerID available similar behaviour to Apache ServerUserID (FastCGI configuration section for full ZS example).
    • httpd.conf
      # enable FastCGI
      LoadModule zend_enabler_module /QSYS.LIB/QHTTPSVR.LIB/QZFAST.SRVPGM
      # enable ILE CGI swap profile
      ServerUserID ADCU
      # enable FastCGI swap profile (PTF required, see FastCGI PTFs)
      FastCGIServerID ADCU
  • No — FastCGI match for Apache UserID NOT available (IBM understands this issue).

QTMHHTTP or QTMHHTP1 — Glass half full, glass half empty …

RPG CGI coders are familiar with “switch profile” to default QTMHHTP1 (ServerUserID QTMHHTTP or QTMHHTP1), which works well because we do not embed RPG inside html documents. However, QTMHHTTP default for both .php and .html can be handy as many applications embed php in html documents (below), so even with FastCGIServerID, you have a decision to make … see FastCGI .html, .phtml, and .php (html with embedded php) for more information.

<body class="page_bg">
Hello, today is <?php echo date('l, F jS, Y'); ?>.

Example: Zend Server using FastCGIServerID ADCU

If you chose to alter Zend Server to use FastCGIServerID, be prepared for a long day of grant authorization settings as most everyone has different site security expectations … but for demonstration/education, example below is fastest way i could find to get everything working with ZS FastCGIServerID, perhaps serve as template for your FastCGIServerID efforts (ADCU *USER profile — no sign on 5250).

  • 0) Apache web server
    • quick fix … shut down all Apache servers including *ADMIN
        endtcpsvr server(*HTTP) httpsvr(*ADMIN)
        endtcpsvr server(*HTTP) instance(ZENDSVR)
        endtcpsvr server(*HTTP) instance(ZEND2)
        ... and so on
  • 1) IFS /tmp
    • quick fix … stop Zend Server and remove everything
      •  call qp2term
        > cd /tmp
        > pwd
        /tmp             <--- make SURE in /tmp or whole system may get deleted
        > rm -R *
  • 2) IFS /usr/local/zendsvr
    • quick fix … stop Zend Server and change *PUBLIC *RX (a few *RWX)
      •  call qp2term 
        > cd /usr/local
        > pwd
        /usr/local       <--- make SURE in /usr/local or whole system may get *PUBLIC change
        > chmod -R 0755 zendsvr  <--- *RWX Owner, *RX Group , *RX to *PUBLIC (r-x)
                                 <--- owner qsecofr via zend install (not QTMHHTTP anyway) 
        > cd zendsvr
        > pwd
        /usr/local/zendsvr       <--- make SURE in /usr/local/zendsvr
        > chmod -R 0777 tmp
        > chmod -R 0777 var
  • 3) library ZENDSVR
    • should already be ok … *PUBLIC *RX or *RWX (r-x or rwx)
      •  call qp2term
        > ls -l /qsys.lib/zendsvr.lib
        drwx---r-x    2 117      0             16384 Feb 21 15:24 AURA.FILE
        -rwx---r-x    1 117      0             61440 Feb 21 15:24 BUGREPORT.PGM
        -rwx---r-x    1 117      0            102400 Feb 21 15:24 CLRMONTBLS.PGM
  • 4) active XMLSERVICE jobs
    • quick fix … kill all XMLSERVICE jobs and remove ipcs data
        a) wrkactjob
        ... before ipcs command stop all Apache servers including *ADMIN ...
        b) call qp2term
        > ipcs | grep -i qtm | awk '{print "ipcrm -" tolower($1) " "$2}' | sh 
          note: grep -i qtm means find QTMHHTTP, you may also want other
                xmlservice active profiles (minimum QTMHHTTP)
  • 5) you web site applications (your day just got longer)
    • quick fix … *PUBLIC *RX
      •  call qp2term
        > chmod -R 0555 /myasp2/www/zend2          <--- *RWX Owner, *RX Group , *RX to *PUBLIC (r-x)
        > chmod -R 0777 /myasp2/www/zend2/logs     <--- *RWX Owner, *RWX Group , *RWX to *PUBLIC (rwx)
        > chown -R QTMHHTTP /myasp2/www/zend2      <--- QTMHHTTP owns all objects
        > chmod -R 0555 /www/zendsvr               <--- *RWX Owner, *RX Group , *RX to *PUBLIC (r-x)
        > chmod -R 0777 /www/zendsvr/logs          <--- *RWX Owner, *RWX Group , *RWX to *PUBLIC (rwx)
        > chown -R QTMHHTTP /www/zendsvr           <--- QTMHHTTP owns all objects
        Ops ... my PmWiki needs web write access so pages alter and uploads occur ... 
        *Option 1) i trust web site applications/users (QTMHHTTP owns all objects) ...
        > chmod -R 0777 /myasp2/www/zend2/htdocs/wiki/wiki.d   <--- *RWX Owner, *RWX Group , *RWX to *PUBLIC (rwx)
        > chmod -R 0777 /myasp2/www/zend2/htdocs/wiki/uploads  <--- *RWX Owner, *RWX Group , *RWX to *PUBLIC (rwx)
        *Option 2) only trust applications running ADCU write access web site applications/users ...
        > chmod -R 0755 /myasp2/www/zend2/htdocs/wiki/wiki.d   <--- *RWX Owner, *RX Group , *RX to *PUBLIC (r-x)
        > chown -R ADCU /myasp2/www/zend2/htdocs/wiki/wiki.d   <--- ADCU owns all objects
        > chmod -R 0755 /myasp2/www/zend2/htdocs/wiki/uploads  <--- *RWX Owner, *RX Group , *RX to *PUBLIC (r-x)
        > chown -R ADCU /myasp2/www/zend2/htdocs/wiki/uploads  <--- ADCU owns all objects
        *Note: This application really should not store data in web document root,
               REALLY should be moved into a separate directory outside doc root 
               to avoid uploading executable script into upload directory 
               (we are putting too much trust in PmWiki edit password control,
               but this was for yips demo easy to upload examples.)
  • 6) other libraries XMLSERVICE, XMLSERVTST, MYLIB, etc.
    • PHP application specific … *PUBLIC *RX or *RWX (r-x or rwx)
  • 7) Apache web server
    • start Apache everything again
      • a) make your authorization change httpd.conf (editor, edtf, etc.)
        > e httpd.conf
        # enable FastCGI swap profile (swap PTF)
        FastCGIServerID ADCU
        b) restart all Apaches
        strtcpsvr server(*HTTP) httpsvr(*ADMIN)   <--- start *ADMIN 1st, if using web GUI change FastCGIServerID 
        -- after FastCGIServerID added restart --
        strtcpsvr server(*HTTP) instance(ZENDSVR)
        strtcpsvr server(*HTTP) instance(ZEND2)
        ... and so on
        c) use wrkactjob to see if working ...
        call qp2term
        > system wrkactjob | grep -i zend
           ZEND2        QTMHHTTP    945836   QTMHHTTP    BCI    2  25        .1                  0     .0  PGM-QZSRHTTP    DEQW          3
           ZEND2        QTMHHTTP    945837   QTMHHTTP    BCI    2  25        .0                  0     .0  PGM-zfcgi       SELW          1
           ZEND2        QTMHHTTP    945838   ADCU        BCI    2  25       2.5                  0     .0  THDW          1
           ZEND2        QTMHHTTP    945839   ADCU        BCI    2  25        .0                  0     .0  THDW          1
           ZEND2        QTMHHTTP    945840   ADCU        BCI    2  25        .0                  0     .0  TIMW          1
           ZEND2        QTMHHTTP    945841   ADCU        BCI    2  25        .0                  0     .0  TIMW          1
           ZEND2        QTMHHTTP    945842   ADCU        BCI    2  25        .0                  0     .0  TIMW          1
           ZEND2        QTMHHTTP    945859   ADCU        BCI    2  25        .1                  0     .0  PGM-tiny        TIMW          1
           ZEND2        QTMHHTTP    945860   ADCU        BCI    2  25        .1                  0     .0  PGM-tiny        TIMW          1

Security more …

Five steps to incorporate SSL technology (optional)

Here is a nice link explaining five easy steps to SSL-enable your HTTP server.

A few more from Alan

iProDeveloper by Kevin Schroeder:

FastCGI configuration

Any Apache instance can add PASE CGI (FastCGI), and they will run along side your ILE CGIs just fine. You will find the directives in your httpd.conf file, also known web GUI folks as Apache instance.

httpd.conf (Apache instance): FastCGI start is fairly simple (using PASE editor, web GUI, EDTF, etc.), in example below i will use FastCGI to route HTTP request of 3 different suffixes to PASE FastCGI servers (.php, .java, .c).

  • .php — static server typical default PHP setting Zend Server
  • .java (PTF) — external java server (java -DFCGI_PORT=8081 TinyFCGI)
  • .c (PTF) — dynamic server
httpd.conf (Apache instance):

> cd /myasp2/www/zend2/conf/
> e httpd.conf
# enable FastCGI
LoadModule zend_enabler_module /QSYS.LIB/QHTTPSVR.LIB/QZFAST.SRVPGM

# enable ILE CGI swap profile
# ServerUserID ADCU

# enable FastCGI swap profile (swap PTF)
# FastCGIServerID ADCU

# protect FastCGI against bad CCSID (dspsysval qccsid 65535)
DefaultFsCCSID 37

# fastcgi zend static http://i/any.php (zend server default)
AddType application/x-httpd-php .php
AddHandler fastcgi-script .php

# fastcgi java external http://i/ (external PTF)
AddType application/x-httpd-java .java
AddHandler fastcgi-script .java

# fastcgi c dynamic http://i/any.c (dynamic PTF)
AddType application/x-httpd-c .c
AddHandler fastcgi-script .c

fastcgi.conf (Apache instance adding FastCGI):

fastcgi.conf (Apache instance adding FastCGI):

; Static PHP servers for default user
Server type="application/x-httpd-php" CommandLine="/usr/local/ZendSvr/bin/php-cgi.bin" StartProcesses="1" SetEnv="QIBM_SRVRMODE_SBS=ZENDSVR" SetEnv="LIBPATH=/usr/local/ZendSvr/lib" SetEnv="PHPRC=/usr/local/ZendSvr/etc/" SetEnv="PHP_FCGI_CHILDREN=10" SetEnv="PHP_FCGI_MAX_REQUESTS=0" ConnectionTimeout="30" RequestTimeout="60" SetEnv="CCSID=819" SetEnv="LANG=C" SetEnv="INSTALLATION_UID=20111108100706281116" SetEnv="LDR_CNTRL=MAXDATA=0x40000000" SetEnv="DEMO_YIPS=secret"

; ExternalServer ...
;, lp0264d:8081
;   localhost:8081,
; Start following tcp external server anytime before/after Apache ...
;   /www/zendsvr/htdocs/Samples/fcgi/external/tests/*
;   java -DFCGI_PORT=8081 TinyFCGI
ExternalServer type="application/x-httpd-java" Binding="" ConnectionTimeout="300" RequestTimeout="300"

; Dynamic PHP servers for tiny
;   httpd.conf: FastCGIServerID ADCU  (optional)
; Assumes unix domain socket test available ...
;   /www/zendsvr/htdocs/Samples/fcgi/server/tests/*
DynamicServer type="application/x-httpd-c" MinProcesses=5 MaxProcesses=100 CommandLine="/www/zendsvr/htdocs/Samples/fcgi/server/tests/tiny" ConnectionTimeout="30" RequestTimeout="60"
MinDynamicServers 5 
MaxDynamicServers 100 

; Where to place socket files
IpcDir /myasp2/www/zend2/logs
IpcPublic *RWX

FastCGI .html, .phtml, and .php (html with embedded php)

If you are not familiar with embedded php in html using FastCGI, you will need an .htaccess file in any directory attempting force PHP to process .html files as .php (see below). For htaccess html as php serving, remove httpd.conf AddCharset UTF-8 (#AddCharset UTF-8 .htm .html .xml) .

> pwd

> ls -al
total 80
drwxrwx---    2 qtmhhttp 0              8192 Jun 26 17:52 .
drwxrwxrwx    9 qtmhhttp 0              8192 Jun 26 16:52 ..
-rwxrwx---    1 qtmhhttp 0                53 Jun 26 17:51 .htaccess
-rwxrwx---    1 qtmhhttp 0               111 Jun 26 16:55 today.html
-rwxrwx---    1 qtmhhttp 0                54 Jun 26 16:59 another.php

> cat today.html 
<body class="page_bg">
Hello, today is <?php echo date('l, F jS, Y'); ?>.

> cat .htaccess 
AddType application/x-httpd-php .html
AddHandler fastcgi-script .html

Alternatively, you may add .htaccess directives above to your main httpd.conf, but all .html have to be processed by FastCGI php-cgi children, which is of course a waste of CPU time for plain .html files, therefore many people simply change .html+php to .phtml and use httpd.conf.


AddType application/x-httpd-php .php
AddHandler fastcgi-script .php
AddType application/x-httpd-php .phtml
AddHandler fastcgi-script .phtml

httpd.conf and fastcgi.conf CCSID common settings

/www/zendsvr/conf/httpd.conf (web admin GUI port 2001 - ZENDSVR):
DefaultFsCCSID 37 or 5035
CGIJobCCSID 37 or 5035
   37 - normal non-DBCS
 5035 - Japan

edit configuration /www/zendsvr/conf/fastcgi.conf (editor):
LANG=C (or SetEnv="LANG=C" individual server)
CCSID=819 or 1208 (or SetEnv="CCSID=819 individual server)
  1208 - utf-8 for DBCS (Japan)
  819 - normal for non-DBCS
  LANG=C - normal
Only if using ServerId or switch profile (need PTF above) 
IpcPublic *RWX          -- set *PUBLIC access value
IpcGroup profile *RWX   -- set *GROUP profile access value
IpcOwner profile *RWX   -- set *OWNER profile access value

Summary of my machine (i use a iASP)

Check out my machine configuration {Zend Server on iASP}, shows relationship between httpd.conf (Apache) and fastcgi.conf (PHP) configurations files.

Why fastcgi.conf StartProcesses = 1 or StartProcesses = n ??

StartProcesses = 1 * PHP_FCGI_CHILDREN = 16 … 16 total worker jobs

  • 1 PHP manager with all 16 children

StartProcesses = 2 * PHP_FCGI_CHILDREN = 8 … 16 total worker jobs

  • 2 PHP managers each with 8 children
The children do all the real work of course.

StartProcesses comes down to manager job(s) ... 
... 2 managers each with 8 children? 
... or 1 manager with 16 children?
... both work, i use 2 or more mangers (dime a dozen)

When a manager dies (rare-2-never), she takes her children out with her,
but the whole thing will like restart on the fly anyway (just my preference).
 4      ZENDSVR      QTMHHTTP    BCI      .0   THDW <--manager
        ZENDSVR      QTMHHTTP    BCI      .0   TIMW <--child 1
        ZENDSVR      QTMHHTTP    BCI      .0   TIMW <--child n

Did anyone try DBCS (CCSID 5035)

Japanese 5035 appears to work.

end current running jobs:

change the system CCSID value:

edit configuration:
/www/zendsvr/conf/fastcgi.conf (editor): 
SetEnv="CCSID=1208" SetEnv="LANG=C"

/www/zendsvr/conf/httpd.conf (web admin GUI port 2001 - ZENDSVR):
DefaultFsCCSID 5035

restart jobs:

Note: If using ODBC will likely have to start/stop prestart jobs as well.


PHP Zend Server tunning

Following these simple suggestions, you can optimize your PHP on IBM i environment.

  • Get the latest IBM PTFs for Java (PASE), HTTP, DB2
    • Many “performance / intermittent” issues ranging from FastCGI to DB2 have been solved by simply updating a machine to the latest PTF levels from IBM. Specific PTFs below are known issues, but lagging behind IBM PTFs has not been a good idea in most cases for this new PHP world on IBM i.
  • Allocate IBM i resource correctly
A full power processor fits many production environments,
while partials like 0.25 - 0.75 usually not.
  • Make sure you have a valid Zend license - Valid licenses enable optimizing some internal options.
    • Note: We have seen up to 48X slow down benchmarks without valid license.
Click on Administration tab
Check Update License section
  • Use dynamic FastCGI - Optimized method of accessing the Web
    • Note: unfortunately we have seen instances where dynamic fastcgi did not work correctly, and you will need to use the static settings shipped with Zend Server. We believe that it is an odd combination individual PTFs that disappears with PTF upgrades.
DynamicServer type="application/x-httpd-php" MinProcesses=5 MaxProcesses=100 ... 
(See FastCGI Dynamic PTFS below)
  • Turn off all Zend Server code tracing, monitor, debug features great tools when developing code, but adds overhead.
Click on Server Setup tab
Click on Components tab
  • Turn off checking for changed PHP include files (production only) - Use this when you code is in a state of flux, otherwise, turn it off.

Other Apache performance?

Often times you can find easy major performance improvements to your site by using fast caching built into IBM i Apache for selected non-PHP files. There is a whole section of documentation covering how to do this in the FRCA link below.


These PTFs may fix your issue, start here.

PASE loader fix (possible PHP crash)
PTF MF52700 (v5r4m5)
PTF MF52710 (v6r1m0)
PTF MF52838 (v6r1m1)
PTF MF53041 (v5r4m0)

FastCGI socket fix (fix hangs and slow downs):
v5r4m0 PTF MF51560
v5r4m5 PTF MF51562
v6r1m0 PTF MF51559
v6r1m1 PTF MF51561
v7r1m0 PTF MF51572

FASTCGI - socket fix (fix hang remote side closes - Windows IE Explorer)
5.4 - MF53779
5.4.5 - MF53780
6.1.0 - MF53775
6.1.1 - MF53781
7.1 - MF53782

FastCGI socket auth (fastcgi.conf "switch profile" setting -- less common):
Release	57**DG1 PTF       57**SS1 PASE PTF
i 5.4   SI41577, SI41688  SI41324
i 6.1   SI41253, SI41704  SI41326
i 7.1   SI41367, SI41706  SI41325
IpcPublic *RWX          -- set *PUBLIC access value
IpcGroup profile *RWX   -- set *GROUP profile access value
IpcOwner profile *RWX   -- set *OWNER profile access value
Note: Development machines often use profile switching/authorization
to restrict "web" activities, but this may restrict FastCGI PHP from
access to it's socket. You will likely need to set IpcPublic *RWX,
or do auth math on group profiles to allow multiple profiles to work.

FastCGI enable Dynamic FastCGI setting (performance):
V5R4: SI43218  V5R4: SI43221
V6R1: SI43243  V6R1: SI43224
V7R1: SI43244  V7R1: SI43222

Example dynamic FastCGI for Zend Server (PHP):
; Dynamic PHP servers for default user (all one line)
DynamicServer type="application/x-httpd-php" MinProcesses=5 MaxProcesses=100 CommandLine="/usr/local/ZendSvr/bin/php-cgi.bin" SetEnv="LIBPATH=/usr/local/ZendSvr/lib" SetEnv="PHPRC=/usr/local/ZendSvr/etc/" SetEnv="PHP_FCGI_CHILDREN=1" SetEnv="PHP_FCGI_MAX_REQUESTS=0" ConnectionTimeout="60" RequestTimeout="60" SetEnv="INSTALLATION_UID=20110323113634153552" SetEnv="LDR_CNTRL=MAXDATA=0x40000000"
; Where to place socket files
IpcDir /www/zendsvr/logs
;Minimum and Maximum of dynamic servers
MinDynamicServers 5
MaxDynamicServers 100

Allow fastcgi.conf to specify multiple directories shared libraries
SI43793 (5.4)
SI43795 (6.1)
SI43798 (7.1)

PTF#s DB2 (or CLOBs fail):
SI39831/SI39917 - V7R1 
SI39829 - V6R1 
SI39610  V5R4
Note: There are many other DB2 fixes, 
      best to simply get the latest cumulative

Dump virtual hosts or modules:
V5R4: SI43745  (Note:  -M/-D DUMP_MODULES is not support on V5R4(Apache 2.0.63))
V6R1: SI43746  SI43837
V7R1: SI43799  SI43800

FastCGI external server (java -DFCGI_PORT=8081 TinyFCGI) and security 
# enable FastCGI swap profile (swap PTF)
# FastCGIServerID ADCU

5722DG1 V5R4M0 SI49489
5761DG1 V6R1M0 SI48749
5770DG1 V7R1M0 SI49021

5722SS1 V5R4M0 SI49419
5761SS1 V6R1M0 SI49420
5770SS1 V7R1M0 SI49422

https SSL slow down PTFs 
V7R1: SI51051
V6R1: SI51050

-- PHP on a IASP
    7.1 - MF56867
    6.1m0 - MF56960
    6.1m1 - MF56961 

Self help FastCGI bad CCSID looping or PHP 65535 DB2 junk??

Likely you have a bad fastcgi configuration.

Which Apache file is FastCGI???
I. Apache:  /www/zendsvr/conf/httpd.conf <-- (ILE Apache side)
DefaultFsCCSID 37   ... or 280 (Italian) ... or so on ...
CGIJobCCSID 37      ... or 280 (Italian) ... or so on ...
  It is a very good idea to set these, so DB2 works with PHP (and other PASE things).
  Mandatory setting if you are trying to run on a QCCSID 65535 machine
  as shipped default from IBM (dspsysval qccsid).
  At times these settings alone may not be sufficient for PHP,
  and you will need the following PASE specific FastCGI setting.  

II. FastCGI: /www/zendsvr/conf/fastcgi.conf <-- THIS file (PASE side)
 1) Bad fastcgi.conf CCSID setting for PASE side FastCGI.
 Good (ASCII):
  Try a PASE CCSID 819 typical or 1208 (DBCS).
  DynamicServer type= ... CCSID=819  (Good for PASE)
  StaticServer type=  ... CCSID=819  (Good for PASE)
 Bad (EBCDIC):
  Do not use ILE settings for PASE.
  DynamicServer type= ... CCSID=37  (bad ILE setting PASE)
  StaticServer type=  ... CCSID=37  (bad ILE setting PASE)
    Setting EBCDIC CCSID will cause unknown issues like FastCGI looping
    because PASE side of FastCGI will have no idea what you are doing,
    so check the PASE locales carefully before setting (above link).

 2) Bad fastcgi.conf LANG setting (ie. English not installed on the machine.)
  Try default LANG=C, which works nearly anywhere (UNIX default).
  DynamicServer type= ... LANG=C (Good default language PASE)
  StaticServer type=  ... LANG=C (Good default language PASE)
  when secondary language not installed (missing)
  DynamicServer type= ... LANG=en_US (bad if secondary language not installed)
  StaticServer type=  ... LANG=en_US (bad if secondary language not installed)
    PASE locales are included with separately installed language groups, 
    not in BASE IBM i OS. FastCGI will likely loop attempting to recover 
    until you install any missing language, so make sure your secondary
    languages is actually installed on the machine before starting.

Happens 99 times out of 100 when not working (CCSID 65535) ….

You cannot run IBM i PHP and interact with IBM i DB2, PGM, SRVPGM (xmlservice), when your IBM i machine is default ship setting of 65535. Change the default ship Zend Server setting and you will likely be up and running.

I run 65535 xmlservice on my V6R1 machine (among other machines) ...
 Coded character set
   identifier . . . . . :   65535      1-65535

Change these files and restart everything (web, db2, xmlservice, tec.) ...

I. Apache:  /www/zendsvr/conf/httpd.conf <-- (ILE Apache side)
   DefaultFsCCSID 37   ... or 280 (Italian) ... or so on ...
   CGIJobCCSID 37      ... or 280 (Italian) ... or so on ...
   - This often fixes majority of web script issue

II. FastCGI: /www/zendsvr/conf/fastcgi.conf <-- THIS file (PASE side)
    CCSID=819 and LANG=C, 
    which works nearly anywhere (UNIX default).
    - This file must be ASCII 819, so careful with editor or will not work (EDTF especially).
    - CCSID=1208 can be a problem for PHP extensions, so most configurations use CCSID=819 and 
      take specific script action to encode/decode 1208 data (see xmlservice hex/before/after)

III. User profile -- DB2 connections 
    - This fixes most DB2 CCSID client/server problems both 1-tier and 2-tier

-- or (skip I. - III.)---

IV. change system ccsid for everything on the machine
    - some legacy applications may not work, should work but ..., so check things out 

Note 65535 - means HEX (or binary), which also means no conversion and 65535 is essentially doomsday for most any application trying to work between PASE and DB2 (most any client and DB2).

client (ASCII 819) + server (EBCDIC 65535) = junk-you-can't-read-or-use

Now the rest of the story … 65535 problem is common, so IBM i DB2 folks force a reasonable job CCSID for SOME remote connections, but NOT all connections (PASE and others), therefore observationally you may see some applications work (client access products) and others will not (PHP). However, the work around (work with) your machine is simple, just follow one of the steps above to set a valid CCSID (personally i like change user profile description, but i also set Apache httpd.conf).

command line PHP Db2 junk (call qp2term, qshell (qsh))??

Many people have trouble with “junk” being returned when using “qshell” (QSH). Usually what you see as junk characters is actually EBCDIC or ASCII being returned across stdout evoked script (stdout terminal window and/or green screen), but under the wrong terminal emulation expectation (ASCII when EBCDIC expected or visa versa). The general rule that will “cure” most of these issues is:

  • call qp2term (PASE sh) - most PASE utilities run correctly under ASCII shell environment (PASE php-cli)
  • qsh (qshell) - most ILE or “native” interfaces run correctly under EBCDIC shell environment
    • QSH can cross-load script from PASE, but the conversions going on under the covers can get script in trouble, which mostly solved with script having a shebang !#/QOpenSys/usr/bin/sh at the top (whew):

HOWEVER default CCSID 65535 machines beware …

when using call qp2term, ssh myi, etc., i had to change parent shell job(s) ccsid to 37 before running command line php/pear worked with ibm_db2 SQL/XMLSERVICE (php-cli, pear, etc.).

  • CHGJOB JOB(836270/ADC/QPADEV0004) CCSID(37)
  • CHGJOB JOB(836268/ADC/QPADEV0004) CCSID(37)
Example: Jobs I had to chgjob (37) ...
        QPADEV0004   ADC         BCI      .0  PGM-sshd         SELW
        QPADEV0004   ADC         BCI      .0  PGM-bsh          THDW   <-- this one
        QPADEV0004   ADC         BCI      .0  PGM-tcsh         TIMW   <-- this one

        QPADEV0004   ADC         INT      .1  PGM-QP2TERM      DEQW
        QPADEV0004   ADC         BCI      .1  PGM-sh           TIMW   <-- this one
... all shells from call qp2term or ssh connections to 65535 machine.

Then php command line db2 tests work ...
call qp2term -- after pops up use another screen to chgjob (37) to  PGM-sh
export PATH=/usr/local/zendsvr/bin:$PATH
export LIBPATH=/usr/local/zendsvr/lib
php-cli mytest.php
-- or --
php mytest.php

PASE php-cgi out of memory (SetEnv=“LDR_CNTRL=MAXDATA=0×80000000″)

You can force most any 32-bit PASE program to leave more heap space (including php-cgi), just specify environment variable up to LDR_CNTRL=MAXDATA=0×80000000 (8 * 256MB). However, please be aware while you are increasing the heap, you are also limiting the number of 256MB segments available for shared memory (not commonly used by PHP programs anyway).

In FastCGI php-cgi just add directive to fastcgi.config.

Server type="application/x-httpd-php" ... normal stuff ... SetEnv="LDR_CNTRL=MAXDATA=0x80000000"

Graphically memory of PASE 32 bit LDR_CNTRL=MAXDATA=0×80000000. Variations of LDR_CNTRL allow you to rearrange even reserved segments and shared libraries, but these uses of LDR_CNTRL are infrequently deployed (except for the most gruesome memory hog Java programs MAXDATA=0xD0000000@DSA).

>export LDR_CNTRL=MAXDATA=0x80000000
>php -v
memory of PASE program PHP
00000000 - 0FFFFFFF - PASE kernel heap (mostly read or no access to user programs)
10000000 - 1FFFFFFF - PASE main program text/code (php)
20000000 - 2FFFFFFF - PASE stack (programs usually share stack/heap in this one segment 256MB)
30000000 - 3FFFFFFF ------
40000000 - 4FFFFFFF      |
50000000 - 5FFFFFFF      |
60000000 - 6FFFFFFF      |--- PASE heap (LDR_CNTRL=MAXDATA=0x80000000)
70000000 - 7FFFFFFF      |    used for new/delete/malloc/free allocations PHP to run scripts
80000000 - 8FFFFFFF      |
90000000 - 9FFFFFFF      |    *Note: no more segments avail for shared memory
A0000000 - AFFFFFFF ------
B0000000 - BFFFFFFF - reserved
C0000000 - CFFFFFFF - reserved
D0000000 - DFFFFFFF - machine wide shared library text/code (libc.a, etc.)
E0000000 - EFFFFFFF - shared memory
F0000000 - FFFFFFFF - machine wide shared library data

Self help FastCGI/PHP looper (100% CPU) or waiter (0% CPU)??

Take a quick wrkactjob look at active PHP job(s) stacks and see where you are, very often API name you see in stack will be exactly problem PHP API.

  • script acting slow — wrkactjob see what you are calling …
  • script eating CPU — wrkactjob see what you are calling …
  wrkactjob (5=Work with)
  5      ZENDSVR      QTMHHTTP    BCI     4.3   TIMA

  11. Display call stack, if active
  P    php-cgi.bin                      0000008C  __start
  P    php-cgi.bin                      000008F4  main
  P    php-cgi.bin                      000001A4  fcgi_accept_request
  P    unix                             00000008  <syscall32>:naccept
  *Note: Example stack above is completely normal (fastcgi waiting for work) 


Tony “Ranger” Cairns - IBM i PHP / PASE