XMLSERVICEDEBUG
Quick Page Table of Contents
Scanning…
XMLSERVICE/Toolkit debugging and service
Who is this page for?
Instructions designed for IBM i developer learning PHP and XMLSERVICE …
Debug technique: It’s as easy as 1–2−3–4−5–6−7–8−9 :)
- Run the test script that contains control “*debug” and script will “hang” while it waits on #2
$ctl .= " *debug";
- A MSGW inquiry message in DSPMSG QSYSOPR will be generated by the toolkit. Note the job information (number, name, user) provided in the MSGW.
- STRSRVJOB using that job information as parameters.
- STRDBG with the program and library you wish to debug.
- Answer the MSGW. Any answer will do—”G” is fine.
- The RPG program source will appear in debug mode in your terminal, ready to step through, allowing you to inspect variables, etc.
- When done inspecting and stepping, let the RPG program complete (using function keys indicated on screen).
- ENDDBG
- ENDSRVJOB
Job1 (threaded) Job 2 Job 3 (DB2 userid/password) Job 4 (optional XTOOLKIT job) (ctl=*debugcgi) (ctl=*debugproc) (ctl=*debug) browser -> Apache ->XMLCGI (Apache CGI child) -> QSQSRVR (XMLSERVICE *here) -> QSQSRVR (XMLSERVICE client) -> XTOOLKIT (XMLSERVICE ipc=/tmp/flinstone) $ctl .= " *debugcgi"; // Job 2 - debug XMLCGI to see REST/HTTP data passed by client (when using REST only) $ctl .= " *debugproc"; // Job 3 - debug XMLSERVICE "client" to see DB2 passed data (DB2 interface) $ctl .= " *debug"; // Job 4 - debug XMLSERVICE "server" to see XMLSERVICE calls (DB2 interface) // Note: when ctl='*here', both XMLSERVICE "client"/"server" // are in QSQSRVSR job (NO XTOOLKIT job) // remote: Attaching with LUW drivers changes QSQSRVR ... // CLIENT (Client Access drivers) <==> QZDAxxxx // CLIENT (DB2 Connect drivers) <==> QRWxxxx
Tips
This is a collection of debug tips and where you may find your problem data.
- Check the logs (click here) … — viewing PHP logs is often enough to solve a problem
- Check active XMLSERVICE job (click here) …
- WRKACTJOB —
5=work -> 10. Display job log -> F10=Display detailed messages
can be very revealing - WRKACTJOB —
5=work -> 11. Display call stack -> F5=Refresh
watch stack during stress runs
- WRKACTJOB —
- Check one level at a time (click here) … — run simple tests up web site food chain can be very revealing
- Download tests: 2012–05–18 - levels-1.4.zip — simple tests for each level
- Level 0 — PHP working (click here) …
- Level 1 — Apache/PHP working (click here) …
- Level 2 — db2 connection working (click here) …
- Level 3 - XMLSERVICE XML interface working (click here) …
- Level 4 — PHP New Toolkit working (click here) …
- Level 5 — PHP CW Toolkit working (optional) (click here) …
- Stop XMLSERVICE for debugger attach (click here) ..
- additional links common XMLSERVICE error information
- {XMLSERVICE FAQ} - have issues, try here
- {XMLSERVICE ERRORS} - errors, try here
- {XMLSERVICE Connections} - XMLSERVICE/Toolkit connections
- {XMLSERVICE Performance} - performance XMLSERVICE
- PASE debug secrets (for a PASE geek) …
- The following links are associated with my machine environment and may be helpful.
- Apache ab tool — Apache ab web site stress tests are performed from the 5250 command line (call qp2term) or ssh myibmi using PASE (see Apache ab link install instructions)
- You can run stress tests from 2-tier Linux/Windows using Apache ab tool, but i am using Apchae ab from PASE.
- Apache ab tool is not perfect, but if you use relatively “sane” number of browsers like -c 10 it will work.
- Apache ab test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
- Apache ab sample run — see sample run my machine
- GUI System Debugger — GUI debugger always available on IBM i
- Apache FastCGI — Apache FastCGI is used for PHP on IBM i, this link may be helpful.
- PHP via iASP — My machine setup using iASP Zend Server data.
- Many of the examples below reference /MYASP2/www/zend2 because i am running all my Zend Server data in an Apache ZEND2 configuration on port 80 using iASP /MYASP2
(http://myibmi/hello.php)
. - Your configuration is more likely Zend Server out-of-the-box-install running in /www/zendsvr on port 10088
(http://myibmi:10088/hello.php)
- Many of the examples below reference /MYASP2/www/zend2 because i am running all my Zend Server data in an Apache ZEND2 configuration on port 80 using iASP /MYASP2
- Apache ab tool — Apache ab web site stress tests are performed from the 5250 command line (call qp2term) or ssh myibmi using PASE (see Apache ab link install instructions)
Working with service provider?
Here are a few common things that can provide useful information if working with outside support people.
- 0) easy way 1.7.1 … just send provider XMLSERVLOG/LOG and XMLSERVLOG/DUMP in SAVF
- assuming you have a trace of the issue (see xmlservice logging instructions)
- 1) what do you see in error logs for simple tests ???
call qp2term > tail /usr/local/zendsvr/var/log/php.log > tail /myasp2/www/zend2/logs/error_log.Q112061800 > tail /myasp2/www/zend2/logs/access_log.Q112061800
- 2) Summarize configuration (below)???
My Example: SYSASP -- ZENDSVR library ... everything as installed SYSASP -- /usr/local/zendsvr ... everything as installed SYSASP -- /tmp ... many Zend "enterprise" components use /tmp MYASP2 -- /myasp2/www/zend2 ... ALL "user data" moved from /www/zendsvr (/conf, /logs, /htdocs) More ... /myasp2/www/zend2 -- NO symbolic links between SYSAPS and MYASP2 for true "independent"ASP. -- config files /myasp2/www/zend2/conf attach: fastcgi.conf attach: httpd.conf
- 3) Around time of simple test failure … do you see job logs?
wrkoutq
If jobs are still active (php-cgi, etc.) ... wrkactjob 5 ZEND2 QTMHHTTP BCI .0 PGM-QZSRHTTP SIGW ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi THDW 5 ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi TIMW 10. Display job log, if active, on job queue, or pending F10 -- full job log
- 4) Around time of simple test failure … do you see VLOGS???
STRSST 1. Start a service tool 5. Licensed Internal Code log 1. Select entries from the Licensed Internal Code (LIC) log Specify Licensed Internal Code Log Selection Values -- leave as is enter --- 0100A890 i5/OS PASE 4700 0013 06/15/12 09:03:43 7 <--- PASE 0100A891 LIC log interface 0401 0100 06/15/12 09:04:08 1 0100A892 Signals management 4600 0001 06/15/12 09:04:51 255 0100A893 Process management 1300 0001 06/18/12 21:02:06 1 maybe look for PASE, storage management, ASP, so on around "failure time" Note: you can also dump logs to spool ...
When you have no idea (dumping many processes)?
Some times you just have no idea what is going on, here is a handy macro to dump a lot of stacks.
STRSST/STRDST 1. Start a service tool 4. Display/Alter/Dump 1. Display/Alter storage ... or option for dump to printer ... 2. Licensed Internal Code (LIC) data 14. Advanced analysis Option Command 1 processinfo In this case dumping all process dealing with keyword "ZEND" appearing in job ... Specify Advanced Analysis Options Output device . . . . . . : Display Type options, press Enter. Command . . . . : PROCESSINFO Options . . . . . -NAMES ZEND Note: Information dumped printer/display is same as paseps macro.
Check active XMLSERVICE job …
If you are using private connections (InternalKey or $ipc=‘/tmp/packers’), the XMLSERVICE job is probably available for examination with wrkactjob.
Work with Active Jobs LP0264D 05/17/12 11:35:12 CPU %: .0 Elapsed time: 00:00:00 Active jobs: 313 Type options, press Enter. 2=Change 3=Hold 4=End 5=Work with 6=Release 7=Display message 8=Work with spooled files 13=Disconnect ... Current Opt Subsystem/Job User Type CPU % Function Status 5 XTOOLKIT DB2 BCH .0 PGM-XMLSERVICE SEMW
1) Use option 5=work -> 10. Display job log -> F10=Display detailed messages
to examine joblog on errors …
Display All Messages System: LP0264D Job . . : XTOOLKIT User . . : DB2 Number . . . : 435915 >> CALL PGM(XMLSERVICE/XMLSERVICE) PARM('/tmp/packers') Pointer not set for location referenced. Application error. MCH3601 unmonitored by ZZSRV at statement 0000000448, instruction X'0000'.
2) Use option 5=work -> 11. Display call stack -> F5=Refresh
to examine stack during stress tests …
Display Call Stack System: LP0264D Job: XTOOLKIT User: DB2 Number: 437582 Thread: 0000000C Type Program Statement Procedure 1 QCMD QSYS /01C8 XMLSERVICE XMLSERVICE _QRNP_PEP_XMLSERVICE XMLSERVICE XMLSERVICE 1133 XMLSERVICE XMLSERVICE XMLSERVICE 4607 RUNSERVER XMLSERVICE XMLSERVICE 2983 SIGSETTIMEOUT XMLSERVICE XMLSERVICE 2876 SIGTIMEROFF QP0SSRV1 QSYS 19 setitimer QP0SSRV2 QSYS 159 qp0sitimer__F12qp0sitimer_t >
Check the logs …
Check PHP log for messages …
On my IBM i machine ... EDTF STMF('/usr/local/zendsvr/var/log/php.log') -- or -- call qp2term (or ssh myibmi) > tail /usr/local/zendsvr/var/log/php.log ... stuff ... in /MYASP2/www/zend2/htdocs/hello.php on line 1
On my Linux machine ... $ tail /usr/local/zend/var/log/php.log [16-May-2012 16:30:12] PHP Warning: db2_close() expects parameter 1 to be resource ...
Check Apache logs for messages …
error logs for date in question ... EDTF STMF('/myasp2/www/zend2/logs/error_log.Q112051500') -- or -- call qp2term (or ssh myibmi) > tail /myasp2/www/zend2/logs/error_log.Q112051500 [Tue May 15 17:10:11 2012] [error] [client 9.5.158.38] CGI PROGRAM /QSYS.LIB/XMLSERVICE.LIB/XMLCGI.PGM RETURNED EXCEPTION ID CEE9901 [Tue May 15 17:10:11 2012] [error] [client 9.5.158.38] SEE JOBLOG FOR JOB 428979/QTMHHTTP /ZEND2
access logs for date in question ... EDTF STMF('/myasp2/www/zend2/logs/access_log.Q112051500') -- or -- call qp2term (or ssh myibmi) > tail /myasp2/www/zend2/logs/access_log.Q112051500 9.5.158.38 - - [15/May/2012:17:47:41 -0500] "GET /cgi-bin/xmlcgi.pgm?db2=LP0264D
Check PHP Toolkit logs for messages …
toolkit.ini logfile EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.log') -- or -- call qp2term (or ssh myibmi) > tail /usr/local/zendsvr/share/ToolkitAPI/toolkit.log 15 May 2012 22:53:35.752099 Running stateless; no IPC needed. Service library: ZENDSVR 15 May 2012 22:53:36.588466 i5Error: num=14 cat=9 msg="No more entries." desc="No more entries." location set in toolkit.ini ... EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.ini') [log] ; warnings and errors will be written to the logfile. logfile = "/usr/local/zendsvr/share/ToolkitApi/toolkit.log"
toolkit.ini debugLogFile EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/debug.log') -- or -- call qp2term (or ssh myibmi) > tail /usr/local/zendsvr/share/ToolkitAPI/debug.log <data type='1A' var='ds1' comment='DSCHARA'><![CDATA[E]]></data> <data type='1A' var='ds2' comment='DSCHARB'><![CDATA[F]]></data> location set in toolkit.ini ... EDTF STMF('/usr/local/zendsvr/share/ToolkitApi/toolkit.ini') ; debug turns PHP toolkit's debug mode on or off (true/false). Default log file: /usr/local/zendsvr/share/ToolkitApi/debug.log ; This log will grow large, so leave this false when you do not need to log everything. debug = true debugLogFile = "/usr/local/zendsvr/share/ToolkitApi/debug.log"
PHP and XMLSERVICE bad XML ... EDTF STMF('/tmp/bad.xml') -- or -- > tail /tmp/bad.xml start <?xml version="1.0" encoding="ISO-8859-1" ?><script><cmd><success><ܬCDATA�+++ success QSYS/DLTDTAARA DTAARA(XMLSERVICE/BETTYBOOP)||></success></cmd>
Check one level at a time …
Troubles on your PHP site or installation???
Often times if you take a deep breath, slow down and look at each level of web site components you can find your issue without reaching for the bat phone and calling Zend or IBM. The following set of tests walks up the PHP levels of components to give you confidence you are looking at the correct layer of your issue. Of course after you complete smaller PHP scripts (hello.php, etc.), you can likely use the same step up next level techniques on your sophisticated applications (WorldPeace.php).
Level 0 — PHP working
If you are running on the IBM i machine it is always best to make sure your Apache/PHP setup can do anything.
Note: Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
Test number #0
Install the following simple test in your Document root and see if “Hello World” appears.
/MYASP2/www/zend2/htdocs/hello.php <?php echo "Hello world"; ?>
Run the test …
call qp2term (or ssh myibmi) > export PATH=/usr/local/zendsvr/bin:$PATH > export LIBPATH=/usr/local/zendsvr/lib > cd /MYASP2/www/zend2/htdocs > php hello.php Hello world>
No, not working???
Level 1 — Apache/PHP working
If you are running on the IBM i machine it is always best to make sure your Apache/PHP setup can do anything.
Note: Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
Test number #1
Install the following simple test in your Document root and see if “Hello World” appears in your browser.
/MYASP2/www/zend2/htdocs/hello.php <?php echo "Hello world"; ?>
No, not working???
Ok, next run stress test …
call qp2term > cd /usr/local/Zend/apache2/bin > ab -t 25 -c 10 http://myibmi/hello.php -t 25 -- 25 seconds -c 10 -- 10 concurrent browsers (simulates ten browsers)
- this test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
- Apache ab sample run — see sample run my machine
wrkactjob refresh (F10) - if you do not see multiple php-cgi jobs getting CPU re-run tests with more load
call qp2term > cd /usr/local/Zend/apache2/bin > ab -t 25 -c 10 http://myibmi/hello.php &; ab -t 25 -c 10 http://myibmi/hello.php &; ab -t 25 -c 10 http://myibmi/hello.php &; -t 25 -- 25 seconds -c 10 -- 10 concurrent browsers (simulates ten browsers) Multiply by 3 Apache ab jobs running background -- 30 concurrent browsers (simulates thirty browsers)
- above using “&;” to fork/exec into background/batch many jobs(s) Apache ab to really hammer your web site
- ab tool is not perfect, so if you start too many of these forked jobs (‘&;’) the tool may core dump (die) — i usually can get 3 - 6 jobs working (30–60 browsers)
- if you still do not see a split of CPU between php-cgi jobs you may be missing HTTP PTFS see link Apache FastCGI
Level 2 — db2 connection working
At this level we want to check our DB2 connections.
Note:
- Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
- This same test can be run 2-tier from Linux/Windows to IBM i using DB2 Connect.
- Example: {Linux DB2 Connect} — DRDA based example below
- Example: {Linux ODBC} — ODBC you may substitute
Test number #2
Install the following simple test in your Document root and see if “success” appears in your browser.
/MYASP2/www/zend2/htdocs/connection2.inc <?php $database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux $cwdatabase = "localhost"; $user = "DB2"; $password = "XXXXXXXX"; $libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server) $i5persistentconnect = false; ?> /MYASP2/www/zend2/htdocs/xxtoolkit_connect.php <?php require_once('connection2.inc'); // flip between persistent and non-persistent connections for ($i=0;$i<500;$i++) { for ($i5persistentconnect=1;$i5persistentconnect>-1;$i5persistentconnect--) { if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password); else $conn = db2_connect($database,$user,$password); if (!$conn) echo "<br>Bad connect: $conn,$database,$user,perm=$i5persistentconnect"; else echo "<br>Good connect: $conn,$database,$user,perm=$i5persistentconnect"; if ($i5persistentconnect) $ok = true; else $ok = db2_close($conn); echo ",ok=$ok\n"; } }
run the test Apache …
Point your browser to php program ... http://myibmi/xxtoolkit_connect.php Good connect: Resource id #2,*LOCAL,DB2,perm=1,ok=1 Good connect: Resource id #3,*LOCAL,DB2,perm=0,ok=1 Good connect: Resource id #4,*LOCAL,DB2,perm=1,ok=1 :
run the test 2-tier … I choose to run from command line on my Linux machine, but Linux Apache would also work.
$ which php /usr/local/zend/bin/php $ php xxtoolkit_connect.php <br>Good connect: Resource id #5,LP0264D,DB2,perm=1,ok=1 <br>Good connect: Resource id #6,LP0264D,DB2,perm=0,ok=1 <br>Good connect: Resource id #7,LP0264D,DB2,perm=1,ok=1 :
No, not working???
Level 3 - XMLSERVICE XML interface working
At this level we want to check our PHP raw XML Toolkit built on top of ibm_db2 connections (Level 2).
Note:
- Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
- This same test can be run 2-tier from Linux/Windows to IBM i using DB2 Connect.
- RPG test *PGM ZENDSVR/ZZCALL is included with Zend Server installation, so test will run out-of-box
Test number #3
Install the following simple test in your Document root and see if “success” appears in your browser.
/MYASP2/www/zend2/htdocs/connection2.inc <?php $database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux $cwdatabase = "localhost"; $user = "DB2"; $password = "XXXXXXXX"; $libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server) $i5persistentconnect = false; ?> /MYASP2/www/zend2/htdocs/xxtoolkit_raw.php <?php require_once('connection2.inc'); if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password); else $conn = db2_connect($database,$user,$password); if (!$conn) echo "Bad connect: $conn,$database,$user,perm=$i5persistentconnect"; $stmt = db2_prepare($conn, "call XMLSERVICE.iPLUG4K(?,?,?,?)"); $ctl = "*sbmjob"; // *here for no additional private job $ipc='/tmp/packers'; // $ipc = ""; // *here no need ipc $clobIn = "<?xml version='1.0'?> <pgm name='ZZCALL' lib='$libxmlservice'> <parm io='both'> <data type='1A'>a</data> </parm> <parm io='both'> <data type='1A'>b</data> </parm> <parm io='both'> <data type='7p4'>11.1111</data> </parm> <parm io='both'> <data type='12p2'>222.22</data> </parm> <parm io='both'> <ds> <data type='1A'>x</data> <data type='1A'>y</data> <data type='7p4'>66.6666</data> <data type='12p2'>77777.77</data> </ds> </parm> <return> <data type='10i0'>0</data> </return> </pgm>"; $clobOut = ""; $ret=db2_bind_param($stmt, 1, "ipc", DB2_PARAM_IN); $ret=db2_bind_param($stmt, 2, "ctl", DB2_PARAM_IN); $ret=db2_bind_param($stmt, 3, "clobIn", DB2_PARAM_IN); $ret=db2_bind_param($stmt, 4, "clobOut", DB2_PARAM_OUT); $ret=db2_execute($stmt); // var_dump($clobOut); if (strpos($clobOut,"4444444444.44")>0) echo "success"; else echo "fail"; ?>
run the test Apache …
Point your browser to php program ... http://myibmi/xxtoolkit_raw.php success
run the test 2-tier … I choose to run from command line on my Linux machine, but Linux Apache would also work.
$ which php /usr/local/zend/bin/php $ php xxtoolkit_raw.php success
No, not working???
- Check PHP log for messages (click here) …
- Check Apache logs for messages (click here) …
- Check PHP toolkit logs for messages (click here) …
Ok, next run stress test …
call qp2term > cd /usr/local/Zend/apache2/bin > ab -t 25 -c 10 http://lp0264d/xxtoolkit_raw.php -t 25 -- 25 seconds -c 10 -- 10 concurrent browsers (simulates ten browsers)
- this test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
- Apache ab sample run — see sample run my machine
Level 4 — PHP New Toolkit working
At this level we want to check our PHP CW Toolkit built on top of raw XML Toolkit (Level 3).
Note:
- Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
- This same test can be run 2-tier from Linux/Windows to IBM i using DB2 Connect.
- RPG test *PGM ZENDSVR/ZZCALL is included with Zend Server installation, so test will run out-of-box
Test number #4
Install the following simple test in your Document root and see if “success” appears in your browser.
/MYASP2/www/zend2/htdocs/connection2.inc <?php $database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux $cwdatabase = "localhost"; $user = "DB2"; $password = "XXXXXXXX"; $libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server) $i5persistentconnect = false; ?> /MYASP2/www/zend2/htdocs/xxtoolkit_new.php <?php require_once('connection2.inc'); require_once("ToolkitService.php"); if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password); else $conn = db2_connect($database,$user,$password); if (!$conn) echo "Bad connect: $conn,$database,$user,perm=$i5persistentconnect"; try { $ToolkitServiceObj = ToolkitService::getInstance($conn); } catch (Exception $e) { die($e->getMessage()); } $param[] = $ToolkitServiceObj->AddParameterChar ('both', 1, 'INCHARA', 'var1', 'Y'); $param[] = $ToolkitServiceObj->AddParameterChar ('both', 1, 'INCHARB', 'var2', 'Z'); $param[] = $ToolkitServiceObj->AddParameterPackDec('both', 7,4,'INDEC1', 'var3', '001.0001'); $param[] = $ToolkitServiceObj->AddParameterPackDec('both', 12,2,'INDEC2', 'var4', '0000000003.04'); $ds[] = $ToolkitServiceObj->AddParameterChar ('both', 1, 'DSCHARA', 'ds1', 'A'); $ds[] = $ToolkitServiceObj->AddParameterChar ('both', 1, 'DSCHARB', 'ds2', 'B'); $ds[] = $ToolkitServiceObj->AddParameterPackDec('both', 7,4,'DSDEC1', 'ds3', '005.0007'); $ds[] = $ToolkitServiceObj->AddParameterPackDec('both', 12,2,'DSDEC1', 'ds4', '0000000006.08'); $param[] = $ToolkitServiceObj->AddDataStruct($ds); $clobOut = $ToolkitServiceObj->PgmCall('ZZCALL', $libxmlservice, $param, null, null); // var_dump($clobOut); $value = "what is ...".$clobOut["io_param"]["ds4"]; if (strpos($value,"4444444444.44")>-1) echo "success"; else echo "fail";
run the test Apache …
Point your browser to php program ... http://myibmi/xxtoolkit_new.php success
run the test 2-tier … I choose to run from command line on my Linux machine, but Linux Apache would also work.
$ which php /usr/local/zend/bin/php $ php xxtoolkit_new.php success
No, not working???
Ok, next run stress test …
call qp2term > cd /usr/local/Zend/apache2/bin > ab -t 25 -c 10 http://lp0264d/xxtoolkit_new.php -t 25 -- 25 seconds -c 10 -- 10 concurrent browsers (simulates ten browsers)
- this test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
- Apache ab sample run — see sample run my machine
Level 5 — PHP CW Toolkit working (optional)
At this level we want to check our PHP CW Toolkit built on top of new Toolkit (Level 4).
Note:
- Your machine may have document root at /www/zendsvr vs. /MYASP2/www/zend2 (out-of-box installed Zend Server).
- This same test can be run 2-tier from Linux/Windows to IBM i using DB2 Connect.
- RPG test *PGM ZENDSVR/ZZCALL is included with Zend Server installation, so test will run out-of-box
Test number #5
Install the following simple test in your Document root and see if “success” appears in your browser.
/MYASP2/www/zend2/htdocs/connection2.inc <?php $database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux $cwdatabase = "localhost"; $user = "DB2"; $password = "XXXXXXXX"; $libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server) $i5persistentconnect = false; ?> /MYASP2/www/zend2/htdocs/xxtoolkit_cw.php <?php require_once('connection2.inc'); require_once('CW/cw.php'); // new toolkit compatibility (Alan) /* connect */ if ($i5persistentconnect) $conn = i5_pconnect($cwdatabase,$user,$password); else $conn = i5_connect($cwdatabase,$user,$password); if (!$conn) echo "Bad connect: $conn,$cwdatabase,$user,perm=$i5persistentconnect"; if (!$conn) { $tab = i5_error(); die("fail Connect: ".$tab[2]." "."$tab[3], $tab[0]"); } /* prepare */ $description = array ( // single parms array ( "Name"=>"INCHARA","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"), array ( "Name"=>"INCHARB","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"), array ( "Name"=>"INDEC1","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"7.4"), array ( "Name"=>"INDEC2","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"12.2"), // structure parm array ( "DSName"=>"INDS1", "Count"=>1, "DSParm"=> array ( array ( "Name"=>"DSCHARA","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"), array ( "Name"=>"DSCHARB","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"), array ( "Name"=>"DSDEC1","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"7.4"), array ( "Name"=>"DSDEC2","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"12.2"), ) ) ); $pgm = i5_program_prepare("$libxmlservice/ZZCALL", $description); if (!$pgm) { $tab = i5_error(); die("fail Prepare: ".$tab[2]." "."$tab[3], $tab[0]"); } // *** parameter list allocation $list= array ( "DSCHARA"=>"x", "DSCHARB"=>"y", "DSDEC1"=>66.6666, "DSDEC2"=>77777.77, ); // *** parameter values passed to procedure $in = array ( "INCHARA"=>"a", "INCHARB"=>"b", "INDEC1"=>11.1111, "INDEC2"=>222.22, "INDS1"=>$list, ); // *** name of variables created for out parameters $out = array ( "INCHARA"=>"INCHARA", "INCHARB"=>"INCHARB", "INDEC1"=>"INDEC1", "INDEC2"=>"INDEC2", "INDS1"=>"INDS1", ); $rc=i5_program_call($pgm, $in, $out); if ($rc != false) { if ($INCHARA != 'C') die("fail C == $INCHARA\n"); if ($INCHARB != 'D') die("fail D == $INCHARB\n"); if ($INDEC1 != 321.1234) die("fail 321.1234 == $INDEC1\n"); if ($INDEC2 != 1234567890.12) die("fail 1234567890.12 = $INDEC2\n"); if ($INDS1["DSCHARA"] != 'E' || $INDS1["DSCHARB"] != 'F' || $INDS1["DSDEC1"] != 333.333 || $INDS1["DSDEC2"] != 4444444444.44) { var_dump($INDS1); die("fail DS not correct\n"); } } else { $tab = i5_error(); die("fail Call: ".$tab[2]." "."$tab[3], $tab[0]"); } // good echo "success"; ?>
run the test Apache …
Point your browser to php program ... http://myibmi/xxtoolkit_cw.php success
run the test 2-tier … I choose to run from command line on my Linux machine, but Linux Apache would also work.
$ which php /usr/local/zend/bin/php $ php xxtoolkit_cw.php success
No, not working???
- Check PHP log for messages (click here) …
- Check Apache logs for messages (click here) …
- Check PHP toolkit logs for messages (click here) …
Ok, next run stress test …
call qp2term > cd /usr/local/Zend/apache2/bin > ab -t 25 -c 10 http://lp0264d/xxtoolkit_cw.php -t 25 -- 25 seconds -c 10 -- 10 concurrent browsers (simulates ten browsers)
- this test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
- Apache ab sample run — see sample run my machine
Apache ab sample run
Apache ab tool — Apache ab web site stress tests are performed from the 5250 command line (call qp2term) or ssh myibmi using PASE (see Apache ab link install instructions)
- You can run stress tests from 2-tier Linux/Windows using Apache ab tool, but i am using Apchae ab from PASE.
- Apache ab tool is not perfect, but if you use relatively “sane” number of browsers like -c 10 it will work.
- Apache ab test is designed to drive CPU to 100% (a good thing), so don’t panic about CPU
Example run my machine …
> ab -t 25 -c 10 http://lp0264d/hello.php This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0 Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Copyright 2006 The Apache Software Foundation, http://www.apache.org/ Benchmarking lp0264d (be patient) Completed 5000 requests Completed 10000 requests Completed 15000 requests Completed 20000 requests Finished 20325 requests Server Software: Apache Server Hostname: lp0264d Server Port: 80 Document Path: /hello.php Document Length: 11 bytes Concurrency Level: 10 Time taken for tests: 25.5119 seconds Complete requests: 20325 Failed requests: 0 Write errors: 0 Total transferred: 3394275 bytes HTML transferred: 223575 bytes Requests per second: 812.83 [#/sec] (mean) <--- 800 hits/second Time per request: 12.303 [ms] (mean) Time per request: 1.230 [ms] (mean, across all concurrent requests) Transfer rate: 132.53 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 1.1 0 30 Processing: 2 11 7.2 10 322 Waiting: 2 10 7.2 10 322 Total: 2 11 7.3 11 322 Percentage of the requests served within a certain time (ms) 50% 11 66% 12 75% 14 80% 15 90% 17 95% 19 98% 21 99% 23 100% 322 (longest request) >
wrkactjob — during Apache ab test you can use refresh on wrkactjob scree to see the php-cgi jobs working
- you should expect to see multiple php-cgi jobs getting some CPU time as you refresh with F10
Work with Active Jobs LP0264D 05/16/12 13:37:25 CPU %: 100.0 Elapsed time: 00:00:00 Active jobs: 295 Type options, press Enter. 2=Change 3=Hold 4=End 5=Work with 6=Release 7=Display message 8=Work with spooled files 13=Disconnect ... Current Opt Subsystem/Job User Type CPU % Function Status ZEND2 QTMHHTTP BCI .0 PGM-zfcgi SELW ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi THDW ZEND2 QTMHHTTP BCI .0 PGM-php-cgi.bi THDW ZEND2 QTMHHTTP BCI 2.8 PGM-php-cgi.bi TIMA ZEND2 QTMHHTTP BCI 1.8 PGM-php-cgi.bi TIMA ZEND2 QTMHHTTP BCI 2.3 PGM-php-cgi.bi TIMA ZEND2 QTMHHTTP BCI 2.8 PGM-php-cgi.bi TIMA ZEND2 QTMHHTTP BCI 1.8 PGM-php-cgi.bi RUN ZEND2 QTMHHTTP BCI 1.4 PGM-php-cgi.bi TIMA
Stop XMLSERVICE for debugger attach
WRKACTJOB find XMLSERVICE private mode only
IF you are running a private connection (ipc=‘/tmp/packers’), you can simply use WRKACTJOB and locate the XMLSERVICE job and attach debugger. However the next qsysopr message option is also available.
XMLSERVICE QSYSOPR message stop anytime
At times it is useful to stop the XMLSERVICE job to connect a debugger to examine an issue, especially if you are running stateless in the QSQSRVR job.
I often find the simple trick below to be very useful.
The trick …
At this time the PHP wrappers have not implemented a stop for debugger interface (cough … Alan), but XMLSERVICE has control *debug ability already available. In the following example adding $ctl .= " *debug";
will stop XMLSERVICE job with a inquire message on qsysopr, simply attach your debugger to job # in msg, set a breakpoint in your module (or in XMLSERVICE module), and answer qsysopr message with any character to let XMLSERVICE continue to your breakpoint. That is it …
Hint: PHP wrappers are sending XML just like below, so if you have toolkit.ini debug turned on you can often simply cut/paste your XML in debug log into the variable $clobIn below.
Test #3 as example …
/MYASP2/www/zend2/htdocs/connection2.inc <?php $database = "*LOCAL"; // *LOCAL on IBM i ... LP0264D on Linux $cwdatabase = "localhost"; $user = "DB2"; $password = "XXXXXXXX"; $libxmlservice = "ZENDSVR"; // ZZCALL (Zend Server) $i5persistentconnect = false; ?> /MYASP2/www/zend2/htdocs/xxtoolkit_raw.php <?php require_once('connection2.inc'); if ($i5persistentconnect) $conn = db2_pconnect($database,$user,$password); else $conn = db2_connect($database,$user,$password); if (!$conn) echo "Bad connect: $conn,$database,$user,perm=$i5persistentconnect"; $stmt = db2_prepare($conn, "call XMLSERVICE.iPLUG4K(?,?,?,?)"); $ctl = "*sbmjob"; // *here for no additional private job $ctl .= " *debug"; // THIS WILL STOP XMLSERVICE JOB MSG TO QSYSOPR (server side) // $ctl .= " *debugproc"; // THIS WILL STOP XMLSERVICE/QSQSRVR JOB MSG TO QSYSOPR (client side) // if running *here either *debug/*debugproc will work $ipc='/tmp/packers'; // $ipc = ""; // *here no need ipc $clobIn = "<?xml version='1.0'?> <pgm name='ZZCALL' lib='$libxmlservice'> <parm io='both'> <data type='1A'>a</data> </parm> <parm io='both'> <data type='1A'>b</data> </parm> <parm io='both'> <data type='7p4'>11.1111</data> </parm> <parm io='both'> <data type='12p2'>222.22</data> </parm> <parm io='both'> <ds> <data type='1A'>x</data> <data type='1A'>y</data> <data type='7p4'>66.6666</data> <data type='12p2'>77777.77</data> </ds> </parm> <return> <data type='10i0'>0</data> </return> </pgm>"; $clobOut = ""; $ret=db2_bind_param($stmt, 1, "ipc", DB2_PARAM_IN); $ret=db2_bind_param($stmt, 2, "ctl", DB2_PARAM_IN); $ret=db2_bind_param($stmt, 3, "clobIn", DB2_PARAM_IN); $ret=db2_bind_param($stmt, 4, "clobOut", DB2_PARAM_OUT); $ret=db2_execute($stmt); // var_dump($clobOut); if (strpos($clobOut,"4444444444.44")>0) echo "success"; else echo "fail"; ?>
Hint: If $clobIn PHP XML single quote / double quote issues are driving you nuts try the following technique.
BTW — For the enterprising do-it-yourself PHP builder you can see how very easy it would be to make a custom call *PGM API with parameter substitution using str_replace() function similar to test_lib_replace() … something like function ZZCALL($INCHARA,$INCHARB,$INDEC1,$INDEC2,$INDS1)
$xml = <<<ENDPROC <?xml version='1.0'?> <script> <pgm name='ZZCALL' lib='xyzlibxmlservicexyz'> <parm io='both'> <data type='1A' var='INCHARA'>a</data> </parm> <parm io='both'> <data type='1A' var='INCHARB'>b</data> </parm> <parm io='both'> <data type='7p4' var='INDEC1'>11.1111</data> </parm> <parm io='both'> <data type='12p2' var='INDEC2'>222.22</data> </parm> <parm io='both'> <ds> <data type='1A' var='INDS1.DSCHARA'>x</data> <data type='1A' var='INDS1.DSCHARB'>y</data> <data type='7p4' var='INDS1.DSDEC1'>66.6666</data> <data type='12p2' var='INDS1.DSDEC2'>77777.77</data> </ds> </parm> <return> <data type='10i0'>0</data> </return> </pgm> </script> ENDPROC; $clobIn = test_lib_replace($xml); // xml common text replacement function test_lib_replace($xml) { global $libxmlservice, $iOPM; if (!$iOPM) { $was = array("xyzlibxmlservicexyz"); $now = array("$libxmlservice"); } else { $was = array("xyzlibxmlservicexyz","<pgm"); $now = array("$libxmlservice","<pgm mode='opm'"); } $out = str_replace($was,$now,$xml); return $out; }
XMLSERVICE can be stopped …
Debug technique: -------------- It's as easy as 1-2-3-4-5-6-7-8-9-10 :) 1. Add the following line to your PHP script before the program call to be debugged. $toolkitConn should be your toolkit connection object. $toolkitConn->setOptions(array('customControl'=>'*debug')). Run your script. The script will "hang" while it waits on #2 below... (move to green screen 5250 for steps 2-10) 2. A MSGW inquiry message in DSPMSG QSYSOPR will be generated by the toolkit. 3. Note the job information (number, name, user) provided in the MSGW. 4. STRSRVJOB using that job information as parameters. 5. STRDBG with the program and library you wish to debug. 6. Answer the MSGW. Any answer will do--"G" is fine. 7. The RPG program source will appear in debug mode in your terminal, ready to step through, allowing you to inspect variables, etc. 8. When done inspecting and stepping, let the RPG program complete (using function keys indicated on screen). 9. ENDDBG 10. ENDSRVJOB
Author(s)
Tony “Ranger” Cairns - IBM i PHP / PASE