├── .travis.yml
├── tests
├── ADDONE.RPGLE
├── bootstrap.php
├── ToolkitApiTest
│ ├── test-issue-44.php
│ ├── HttpSuppTest.php
│ ├── Int8ParamTest.php
│ ├── Int16ParamTest.php
│ ├── UInt8ParamTest.php
│ ├── UInt16ParamTest.php
│ ├── ProgramParameterTest.php
│ └── ToolkitTest.php
├── config
│ └── db.config.php.dist
└── functional
│ └── ToolkitTest.php
├── .gitignore
├── samples
├── omit.php
├── classic
│ ├── display-library-list
│ │ └── example.php
│ ├── program-call-two-params
│ │ └── example.php
│ ├── service-program-call
│ │ └── example.php
│ └── program-call-data-structure-params
│ │ └── example.php
├── data-structure.php
├── local-transport.php
├── display-library-list.php
├── simple-parameters.php
├── connect_pdo_odbc.php
├── data-structure-array-with-counter.php
├── README.md
├── ssh-transport.php
├── call-procedure.php
├── data-types.md
└── options.php
├── ToolkitApi
├── ToolkitServiceSet.php
├── CW
│ ├── cwclasses.php
│ ├── I5Error.php
│ ├── ToolkitServiceCw.php
│ └── DataDescriptionPcml.php
├── iToolkitService.php
├── Int8Param.php
├── UInt8Param.php
├── Int16Param.php
├── UInt16Param.php
├── TmpUserSpace.php
├── ToolkitService.php
├── ObjectLists.php
├── DateTimeApi.php
├── LocalSupp.php
├── SystemValues.php
├── autoload.php
├── PdoSupp.php
├── ListFromApi.php
├── Odbcsupp.php
├── toolkit.ini.zs5
├── SshSupp.php
├── toolkit.ini.zs6
├── toolkit.ini
├── SpooledFiles.php
├── Db2supp.php
├── JobLogs.php
├── httpsupp.php
├── DataArea.php
├── DataQueue.php
└── UserSpace.php
├── phpunit.xml.dist
├── phpunit.xml
├── README.md
├── LICENSE.txt
└── composer.json
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | before_script: composer install
4 |
5 | script: phpunit --configuration phpunit.xml --testsuite ToolkitTests
6 |
--------------------------------------------------------------------------------
/tests/ADDONE.RPGLE:
--------------------------------------------------------------------------------
1 | /FREE
2 | Dcl-Pi ADDONE;
3 | MyParm1 Int(10);
4 | End-Pi;
5 | MyParm1 += 1;
6 | Return;
7 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | AddParameterChar('omit', 10, 'Param to allow omitting', 'OMITPARAM', '');
11 |
12 |
--------------------------------------------------------------------------------
/ToolkitApi/ToolkitServiceSet.php:
--------------------------------------------------------------------------------
1 |
13 |
14 | ./tests/ToolkitApiTest
15 |
16 |
17 | ./tests/functional
18 |
19 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 | ./tests/ToolkitApiTest
15 |
16 |
17 | ./tests/functional
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/ToolkitApiTest/HttpSuppTest.php:
--------------------------------------------------------------------------------
1 | setIpc($ipc);
15 |
16 | $this->assertEquals($ipc, $httpsupp->getIpc());
17 | }
18 |
19 | public function testIsIpcSet(): void
20 | {
21 | $ipc = 'test';
22 |
23 | $httpsupp = new httpsupp();
24 | $httpsupp->setIpc($ipc);
25 |
26 | $this->assertEquals($ipc, $httpsupp->getIpc());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/config/db.config.php.dist:
--------------------------------------------------------------------------------
1 | [
4 | 'odbc' => [
5 | 'dsn' => 'DSN=*LOCAL;',
6 | 'username' => 'MYUSER',
7 | 'password' => 'MYPASS',
8 | 'platform' => 'IbmDb2',
9 | 'platform_options' => [
10 | 'quote_identifiers' => true,
11 | ],
12 | ],
13 | ],
14 | 'toolkit' => [
15 | 'system' => [
16 | 'XMLServiceLib' => 'QXMLSERV',
17 | 'HelperLib' => 'QXMLSERV',
18 | 'debug' => false,
19 | 'trace' => false,
20 | 'sbmjob_params' => 'QSYS/QSRVJOB/XTOOLKIT',
21 | 'stateless' => true,
22 | ],
23 | ],
24 | ];
--------------------------------------------------------------------------------
/ToolkitApi/Int8Param.php:
--------------------------------------------------------------------------------
1 | assertTrue($parameter instanceof ProgramParameter);
18 |
19 | $parameter = new Int8Param('in', 'comment 2', 'var2', 10);
20 | $this->assertTrue($parameter instanceof ProgramParameter);
21 |
22 | $parameter = new Int8Param('out', 'comment3', 'var3', 3);
23 | $this->assertTrue($parameter instanceof ProgramParameter);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/ToolkitApiTest/Int16ParamTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($parameter instanceof ProgramParameter);
18 |
19 | $parameter = new Int16Param('in', 'comment 2', 'var2', 10);
20 | $this->assertTrue($parameter instanceof ProgramParameter);
21 |
22 | $parameter = new Int16Param('out', 'comment3', 'var3', 3);
23 | $this->assertTrue($parameter instanceof ProgramParameter);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/ToolkitApiTest/UInt8ParamTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($parameter instanceof ProgramParameter);
18 |
19 | $parameter = new UInt8Param('in', 'comment 2', 'var2', 10);
20 | $this->assertTrue($parameter instanceof ProgramParameter);
21 |
22 | $parameter = new UInt8Param('out', 'comment3', 'var3', 3);
23 | $this->assertTrue($parameter instanceof ProgramParameter);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/ToolkitApiTest/UInt16ParamTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($parameter instanceof ProgramParameter);
18 |
19 | $parameter = new UInt16Param('in', 'comment 2', 'var2', 10);
20 | $this->assertTrue($parameter instanceof ProgramParameter);
21 |
22 | $parameter = new UInt16Param('out', 'comment3', 'var3', 3);
23 | $this->assertTrue($parameter instanceof ProgramParameter);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ToolkitApi/TmpUserSpace.php:
--------------------------------------------------------------------------------
1 | CreateUserSpace($this->generate_name(), $UsLib, $DftUsSize)) {
19 | throw new \Exception($this->getError());
20 | } else {
21 | $this->TMPUSName = sprintf("%-10s%-10s", $this->getUSName(), $UsLib);
22 | }
23 |
24 | return $this;
25 | }
26 |
27 | /**
28 | * @todo do not delete
29 | */
30 | public function __destruct()
31 | {
32 | // $this->DeleteUserSpace();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/samples/classic/display-library-list/example.php:
--------------------------------------------------------------------------------
1 | getMessage(), "\n";
9 | exit();
10 | }
11 |
12 | $obj->setToolkitServiceParams(array('InternalKey' => "/tmp/$user",
13 | 'debug' => true,
14 | 'plug' => "iPLUG32K"));
15 | $cmd = "addlible ZENDSVR";
16 | $obj->CLCommand($cmd);
17 | echo "
";
18 | $rows = $obj->CLInteractiveCommand("DSPLIBL");
19 | /*$rows = $obj->CLInteractiveCommand("WRKSYSVAL OUTPUT(*PRINT)");*/
20 | if (!$rows) {
21 | echo $obj->getLastError();
22 | } else {
23 | var_dump($rows);
24 | }
25 |
26 | echo "";
27 |
28 | /* Do not use the disconnect() function for "state full" connection */
29 | $obj->disconnect();
30 |
--------------------------------------------------------------------------------
/samples/data-structure.php:
--------------------------------------------------------------------------------
1 | // Data structure is easy to add. It's just another parameter.
2 |
3 | $param = []; // initialize parameter array
4 |
5 | // add parameters as desired
6 | $param[] = $tk->AddParameterChar('in', 10,'Name', 'PTNAME', 'Fred');
7 | $param[] = $tk->AddParameterChar('in', 25,'Address', 'PTADDR', '123 Toolkit Drive');
8 |
9 | // DATA STRUCTURE
10 | // Define the data structure as an array of basic parameter types or other data structures
11 | $ds = [];
12 | $ds[] = $tk->AddParameterChar('in', 21,'Part', 'PTPRT', 'A123');
13 | $ds[] = $tk->AddParameterChar('in', 3,'Vendor', 'PTVEN', '825');
14 | $ds[] = $tk->AddParameterChar('out', 20,'Description', 'PTDES', $out);
15 | $ds[] = $tk->AddParameterZoned('out', 9, 2, 'Price', 'PTPRC', $out);
16 |
17 | // Add the data structure as just another element in your main parameter array.
18 | $param[] = $tk->AddDataStruct($ds, 'myds');
19 |
20 | // Add additional regular parameters as needed
21 | $param[] = $tk->AddParameterZoned('in', 5, 2, 'Discount', 'PTDISC', '0.24');
22 |
--------------------------------------------------------------------------------
/samples/local-transport.php:
--------------------------------------------------------------------------------
1 | CLInteractiveCommand("DSPLIBL"); // just one type of command to run
16 | var_dump($res);
17 | } catch (Exception $e) {
18 | echo $e->getMessage(), "\n";
19 | }
20 |
--------------------------------------------------------------------------------
/samples/display-library-list.php:
--------------------------------------------------------------------------------
1 | getMessage(), "\n";
14 | exit();
15 | }
16 |
17 | $conn->setOptions(array('stateless' => true));
18 |
19 | echo "";
20 | $rows = $conn->CLInteractiveCommand("DSPLIBL");
21 | if (!$rows) {
22 | echo $conn->getLastError();
23 | } else {
24 | print_r($rows);
25 | }
26 |
27 | echo "";
28 | ?>
29 |
30 | Output will look like:
31 | Array
32 | (
33 | [0] => 5770SS1 V7R4M0 190621 Library List 7/02/21 15:10:47 Page 1
34 | [1] => ASP
35 | [2] => Library Type Device Text Description
36 | [3] => QSYS SYS System Library
37 | [4] => QSYS2 SYS System Library for CPI's
38 | [5] => QHLPSYS SYS
39 | [6] => QUSRSYS SYS System Library for Users
40 | [7] => QGPL USR General Purpose Library
41 | [8] => QTEMP USR
42 | [9] => * * * * * E N D O F L I S T I N G * * * * *
43 | )
44 |
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PHP Toolkit for IBM i
2 | =====================
3 |
4 | [](https://travis-ci.org/zendtech/IbmiToolkit)
5 |
6 | For production systems please do not use the master branch. Instead use the latest
7 | [stable release](https://github.com/zendtech/IbmiToolkit/releases/latest).
8 |
9 | Introduction
10 | ------------
11 |
12 | The PHP Toolkit for IBM i (Toolkit) is a PHP-based front end to [XMLSERVICE](http://www.youngiprofessionals.com/wiki/XMLSERVICE) that helps programmers call RPG and CL programs along with other native resources from within PHP.
13 |
14 | The Toolkit is open source and has been developed with help from Alan Seiden and the community.
15 |
16 | Discussion of the Toolkit takes place in GitHub Discussions:
17 | https://github.com/zendtech/IbmiToolkit/discussions
18 |
19 | Current Main Features:
20 |
21 | - Ability to call RPG, CL, and COBOL
22 | - Run interactive commands such as ‘wrkactjob’
23 | - Transport-neutral, supporting DB2, ODBC, and HTTP, and others as needed
24 | - Compatibility wrapper to execute Easycom syntax
25 | - Support of all RPG parameter types, including data structures, packed decimal, and output parameters
26 |
27 | XMLSERVICE and the IBM i Toolkit are already shipped with Zend Server and Seiden CommunityPlus+ PHP. But being
28 | open source they can also be downloaded, installed, and upgraded separately.
29 |
30 | For examples, please visit:
31 | https://github.com/zendtech/IbmiToolkit/tree/master/samples
32 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2005-2014, Zend Technologies USA, Inc.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice, this
11 | list of conditions and the following disclaimer in the documentation and/or
12 | other materials provided with the distribution.
13 |
14 | * Neither the name of the {organization} nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/ToolkitApi/ToolkitService.php:
--------------------------------------------------------------------------------
1 | =7.1",
20 | "ext-mbstring": "*",
21 | "ext-pcre": "*",
22 | "ext-pdo": "*",
23 | "ext-simplexml": "*"
24 | },
25 | "suggest": {
26 | "ext-ibm_db2": "For the Db2 transport",
27 | "ext-odbc": "For the ODBC transport",
28 | "ext-pdo_ibm": "For the PDO Db2 transport",
29 | "ext-pdo_odbc": "For the PDO ODBC transport",
30 | "ext-pcntl": "For the local transport",
31 | "ext-ssh2": "For the SSH transport"
32 | },
33 | "autoload": {
34 | "classmap": ["ToolkitApi/"],
35 | "psr-4": {
36 | "ToolkitApi\\":"ToolkitApi"
37 | }
38 | },
39 | "autoload-dev": {
40 | "psr-4": {
41 | "ToolkitApi\\":"ToolkitApi",
42 | "ToolkitApiTest\\":"tests/ToolkitApiTest",
43 | "ToolkitFunctionalTest\\": "tests/functional"
44 | }
45 | },
46 | "require-dev": {
47 | "phpunit/phpunit": "^11.0",
48 | "symfony/process": "^4.3"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/samples/classic/program-call-two-params/example.php:
--------------------------------------------------------------------------------
1 | getMessage(), "\n";
24 | exit();
25 | }
26 |
27 | $ToolkitServiceObj->setToolkitServiceParams(array('InternalKey' => "/tmp/$user"));
28 | $code = $_POST ['code'];
29 | $desc = ' ';
30 |
31 | $param[] = $ToolkitServiceObj->AddParameterChar('both', 10, 'CODE', 'CODE', $code);
32 | $param[] = $ToolkitServiceObj->AddParameterChar('both', 10, 'DESC', 'DESC', $desc);
33 | $result = $ToolkitServiceObj->PgmCall("COMMONPGM", "ZENDSVR6", $param, null, null);
34 | if ($result) {
35 | showTable($result['io_param']);
36 | } else {
37 | echo "Execution failed.";
38 | }
39 |
40 | /* Do not use the disconnect() function for "state full" connection */
41 | $ToolkitServiceObj->disconnect();
42 |
--------------------------------------------------------------------------------
/samples/classic/service-program-call/example.php:
--------------------------------------------------------------------------------
1 | getMessage(), "\n";
10 | exit();
11 | }
12 | $ToolkitServiceObj->setToolkitServiceParams(array('InternalKey' => "/tmp/$user"));
13 | $SysValueName = "QCCSID";
14 | $Err = ' ';
15 | $SysValue = ' ';
16 |
17 | $param[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'ErrorCode', 'errcode', $Err);
18 | $param[] = $ToolkitServiceObj->AddParameterChar('both', 10, 'SysValName', 'sysvalname', $SysValueName);
19 | $param[] = $ToolkitServiceObj->AddParameterChar('both', 1024, 'SysValue', 'sysvalue', $SysValue);
20 | $OutputParams = $ToolkitServiceObj->PgmCall('ZSXMLSRV', "ZENDSVR6", $param, NULL, array('func' => 'RTVSYSVAL'));
21 | if (isset($OutputParams['io_param']['sysvalname'])) {
22 | echo " System value " . $SysValueName . " = " . $OutputParams['io_param']['sysvalue'];
23 | } else
24 | echo " Operation failed. System value $SysValueName did not retrieve.";
25 | /*change parameter value and execute again PgmCall()*/
26 | ProgramParameter::UpdateParameterValues($param, array("sysvalname" => "QLANGID"));
27 | $OutputParams = $ToolkitServiceObj->PgmCall('ZSXMLSRV', "ZENDSVR6", $param, NULL, array('func' => 'RTVSYSVAL'));
28 | if (isset($OutputParams['io_param']['sysvalname'])) {
29 | echo " System value " . $SysValueName . " = " . $OutputParams['io_param']['sysvalue'];
30 | } else {
31 | echo " Operation failed. System value $SysValueName did not retrieve.";
32 | }
33 |
34 | $ToolkitServiceObj->disconnect();
35 |
--------------------------------------------------------------------------------
/samples/simple-parameters.php:
--------------------------------------------------------------------------------
1 | setOptions(array('stateless'=>true));
14 |
15 | // Define several input/output params
16 | // (To see all available data types, see: samples/data-types.md)
17 | $params = []; // start with empty array
18 | $params[] = $conn->AddParameterChar('in', 1,'Division', 'DIV', 'A');
19 | $params[] = $conn->AddParameterChar('in', 6,'Product', 'PROD', '123456');
20 | $params[] = $conn->AddParameterPackDec('both', 7, 2, 'Quantity', 'QTY', '4.53');
21 | $params[] = $conn->AddParameterZoned('out', 5, 2, 'Price', 'PRICE', '0');
22 |
23 | // Call program.
24 | // In this example, assume your program is MYLIB/MYPGM.
25 | $result = $conn->PgmCall('MYPGM', 'MYLIB', $params);
26 |
27 | if (!$result) {
28 | echo 'Error calling program. Code: ' . $conn->getErrorCode() . ' Msg: ' . $conn->getErrorMsg();
29 | } else {
30 | echo 'Called program successfully.
';
31 | // Parameter values that are I/O type "out" or "both" will be available in $result['io_param'].
32 | echo 'Input/output params: QTY: ' . $result['io_param']['QTY'] . ' PRICE: ' . $result['io_param']['PRICE'] . '
';
33 | }
34 |
35 | /*
36 | The above will output something like:
37 |
38 | Called program successfully.
39 |
40 | Input/output params: QTY: 4.53 PRICE: 0.00
41 |
42 | */
43 |
--------------------------------------------------------------------------------
/samples/connect_pdo_odbc.php:
--------------------------------------------------------------------------------
1 | $persistence,
30 | PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING,
31 | ));
32 | } catch (PDOException $e) {
33 | die ('PDO connection failed: ' . $e->getMessage());
34 | }
35 |
36 | // use your existing database connection when creating toolkit object
37 | $tkobj = ToolkitService::getInstance($dbconn, $namingMode, '', $dbConnectionType);
38 |
39 | // simplest is stateless mode, but could set InternalKey to a directory name instead for a stateful connection.
40 | $tkobj->setOptions(array('stateless' => true));
41 |
42 | // (Example command to test toolkit)
43 | // run DSPLIBL and return screen as an array
44 | $result = $tkobj->ClInteractiveCommand('DSPLIBL');
45 | print_r($result);
46 |
--------------------------------------------------------------------------------
/samples/data-structure-array-with-counter.php:
--------------------------------------------------------------------------------
1 | AddParameterChar('in', 21,'Part', 'PTPRT', 'A123');
17 | $ds[] = $conn->AddParameterChar('in', 3,'Vendor', 'PTVEN', '825');
18 | $ds[] = $conn->AddParameterChar('out', 20,'Description', 'PTDES', $out);
19 | $ds[] = $conn->AddParameterZoned('out', 9, 2, 'Price', 'PTPRC', $out);
20 |
21 | // Multi-occurrence data structure with maximum dimension set to 10000 but whose final output count will be determined by MYCOUNTER. Name the counter whatever you wish.
22 | $param[] = $conn->AddDataStruct($ds, 'MULTDS')
23 | ->setParamDimension(10000) // if your RPG array has max of 10000 records
24 | ->setParamLabelCounted('MYCOUNTER'); // create your own counter name
25 |
26 | // COUNTVAR is a counter field. Value is set by RPG/COBOL program. Value will control the number of MULTDS fields that return (see data structure MULTDS below)
27 | // Counter variable doesn't have to match the counted() and counter() labels.
28 | $param[] = $conn->AddParameterZoned('both', 5, 0, 'how many MULTDS array elements actually return', 'COUNTVAR', 6)
29 | ->setParamLabelCounter('MYCOUNTER'); // match the counter name you defined on setParamLabelCounted()
30 |
31 | // The count identifier you specified ties them together.
32 |
33 | // Now when you call your RPG program, the output will be very efficient, because you'll receive only the number of records that the RPG program specified in the counter variable.
34 |
35 | ?>
36 |
--------------------------------------------------------------------------------
/samples/README.md:
--------------------------------------------------------------------------------
1 | # PHP Toolkit sample scripts
2 |
3 | - [`call-procedure.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/call-procedure.php):
4 | Complete example of calling an RPG procedure (service program)
5 | - [`connect_pdo_odbc.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/connect_pdo_odbc.php):
6 | How to connect to the toolkit using PDO_ODBC
7 | - [`data-structure-array-with-counter.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/data-structure-array-with-counter.php):
8 | Efficient way to receive an array of data back
9 | - [`data-types.md`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/data-types.md):
10 | Reference guide to XMLSERVICE data types and equivalent PHP Toolkit functions
11 | - [`display-library-list.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/display-library-list.php):
12 | Get results back from an "interactive/5250" CL command.
13 | - [`local-transport.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/local-transport.php):
14 | Uses xmlservice-cli to make a program call without needing a database connection.
15 | - [`omit.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/omit.php):
16 | When an RPG program makes a parameter optional by specifying `OPTION(*OMIT)`, this snippet shows how to to specify on the PHP side that the parameter will not be passed.
17 | - [`options.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/options.php):
18 | Connection options, both basic and advanced. Recommended reading.
19 | - [`ssh-transport.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/ssh-transport.php):
20 | Uses the SSH transport for connecting to the toolkit. Ideal for running the toolkit on a PC or other system and connecting to a remote IBM i.
21 | - [`simple-parameters.php`](https://github.com/zendtech/IbmiToolkit/blob/master/samples/simple-parameters.php):
22 | Example with ordinary parameters only; no data structures, arrays, or procedure return values.
23 | - [`classic` folder](https://github.com/zendtech/IbmiToolkit/tree/master/samples/classic):
24 | Contains the original Zend Server examples from 2011. For historical purposes only.
25 |
--------------------------------------------------------------------------------
/ToolkitApi/ObjectLists.php:
--------------------------------------------------------------------------------
1 | ToolkitSrvObj = $ToolkitSrvObj;
23 | return $this;
24 | } else {
25 | return false;
26 | }
27 | }
28 |
29 | /**
30 | * @param string $object = *ALL, *name, *generic name
31 | * @param string $library = *ALL, *name, *generic name
32 | * @param string $objecttype = *ALL, *type
33 | * @return array|bool
34 | * @throws \Exception
35 | */
36 | public function getObjectList($object = '*ALL', $library = '*LIBL', $objecttype = '*ALL')
37 | {
38 | $ObjName = $object;
39 | $ObjLib = $library;
40 | $ObjType = $objecttype;
41 |
42 | $this->TmpUserSpace = new TmpUserSpace($this->ToolkitSrvObj);
43 |
44 | $UsFullName = $this->TmpUserSpace->getUSFullName();
45 |
46 | $params[] = $this->ToolkitSrvObj->AddParameterChar('in', 20, "User Space Name", 'userspacename', $UsFullName);
47 | $params[] = $this->ToolkitSrvObj->AddParameterChar('in', 10, "Object name", 'objectname', $ObjName);
48 | $params[] = $this->ToolkitSrvObj->AddParameterChar('in', 10, "Object library", 'objectlib', $ObjLib);
49 | $params[] = $this->ToolkitSrvObj->AddParameterChar('in', 10, "Object Type", 'objecttype', $ObjType);
50 | $this->ToolkitSrvObj->PgmCall(ZSTOOLKITPGM, $this->ToolkitSrvObj->getOption('HelperLib'), $params, NULL, array('func' => 'OBJLST'));
51 |
52 | $ObjList = $this->TmpUserSpace->ReadUserSpace(1, $this->TmpUserSpace->RetrieveUserSpaceSize());
53 | $this->TmpUserSpace->DeleteUserSpace();
54 |
55 | unset($this->TmpUserSpace);
56 |
57 | if (trim($ObjList)!='') {
58 | return (str_split($ObjList, $this->OBJLLISTREC_SIZE));
59 | } else {
60 | return false;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/ToolkitApi/CW/I5Error.php:
--------------------------------------------------------------------------------
1 | setI5Error(0, 0, '', '');
36 | }
37 |
38 | /**
39 | * __toString will make it easy to output an error via echo or print
40 | *
41 | * @return string
42 | */
43 | public function __toString()
44 | {
45 | $err = $this->getI5Error();
46 | return "i5Error: num={$err['num']} cat={$err['cat']} msg=\"{$err['msg']}\" desc=\"{$err['desc']}\"";
47 | }
48 |
49 | /**
50 | * Set error information for last action.
51 | *
52 | * @param int $errNum Error number (according to old toolkit). Zero/false if no error
53 | * @param string $errCat Category of error
54 | * @param string $errMsg Error message (often a CPF code but sometimes just a message)
55 | * @param string $errDesc Longer description of error
56 | * @return void
57 | */
58 | public function setI5Error($errNum, $errCat = I5_CAT_PHP, $errMsg = '', $errDesc = '')
59 | {
60 | // the array (eventually returned by i5_error()
61 | // likes to have both numeric and alphanumeric keys.
62 | $i5ErrorArray = array(0=>$errNum, 1=>$errCat, 2=>$errMsg, 3=>$errDesc,
63 | 'num'=>$errNum, 'cat'=>$errCat, 'msg'=>$errMsg, 'desc'=>$errDesc);
64 |
65 | self::$_i5Error = $i5ErrorArray;
66 | }
67 |
68 | /**
69 | * Return i5 error array for most recent action.
70 | *
71 | * @return array Error array for most recent action.
72 | */
73 | public function getI5Error()
74 | {
75 | return self::$_i5Error;
76 | }
77 | }
--------------------------------------------------------------------------------
/ToolkitApi/DateTimeApi.php:
--------------------------------------------------------------------------------
1 | ToolkitSrvObj = $ToolkitSrvObj ;
20 | }
21 | }
22 |
23 | /**
24 | * from 8-character *DTS format to 17-character full date and time
25 | *
26 | * @param $dtsDateTime
27 | * @return bool
28 | */
29 | public function dtsToYymmdd($dtsDateTime)
30 | {
31 | $inputFormat = "*DTS"; // special system format, returned by some APIs.
32 | $outputFormat = "*YYMD"; // 17 chars long
33 | $outputVarname = 'datetimeOut';
34 |
35 | $apiPgm = 'QWCCVTDT';
36 | $apiLib = 'QSYS';
37 |
38 | $paramXml = "
39 | $inputFormat
40 |
41 |
42 | $dtsDateTime
43 |
44 |
45 | $outputFormat
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | \n" .
54 | Toolkit::getErrorDataStructXml(5); // param number 5
55 |
56 | // pass param xml directly in.
57 | $retPgmArr = $this->ToolkitSrvObj->PgmCall($apiPgm, $apiLib, $paramXml);
58 | if ($this->ToolkitSrvObj->getErrorCode()) {
59 | return false;
60 | }
61 |
62 | $retArr = $retPgmArr['io_param'][$outputVarname];
63 |
64 | return $retArr;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/functional/ToolkitTest.php:
--------------------------------------------------------------------------------
1 | connectionOptions = $config['db']['odbc'];
29 | $this->toolkitOptions = $config['toolkit'];
30 | }
31 |
32 | /**
33 | * @throws \Exception
34 | */
35 | public function testCanPassPdoOdbcObjectToToolkit(): void
36 | {
37 | $pdo = new \PDO(
38 | 'odbc:' . $this->connectionOptions['dsn'],
39 | $this->connectionOptions['username'],
40 | $this->connectionOptions['password'],
41 | [
42 | 'platform' => $this->connectionOptions['platform'],
43 | 'platform_options' => [
44 | 'quote_identifiers' => $this->connectionOptions['platform_options']['quote_identifiers'],
45 | ]
46 | ]
47 | );
48 |
49 | $toolkit = new Toolkit($pdo, null, null, 'pdo');
50 | $toolkit->setOptions($this->toolkitOptions);
51 |
52 | $this->assertInstanceOf(Toolkit::class, $toolkit);
53 | }
54 |
55 | /**
56 | * @throws \Exception
57 | */
58 | public function testCanPassOdbcResourceToToolkit(): void
59 | {
60 | $connection = odbc_connect($this->connectionOptions['dsn'], $this->connectionOptions['username'], $this->connectionOptions['password']);
61 |
62 | if (!$connection) {
63 | throw new \Exception('Connection failed');
64 | }
65 | $toolkit = new Toolkit($connection, null, null, 'odbc');
66 | $toolkit->setOptions($this->toolkitOptions);
67 |
68 | $this->assertInstanceOf(Toolkit::class, $toolkit);
69 | }
70 |
71 | /**
72 | * @throws \Exception
73 | */
74 | public function testCanPassOdbcConnectionParametersToToolkit(): void
75 | {
76 | $toolkit = new Toolkit(
77 | $this->connectionOptions['dsn'],
78 | $this->connectionOptions['username'],
79 | $this->connectionOptions['password'],
80 | 'odbc'
81 | );
82 | $toolkit->setOptions($this->toolkitOptions);
83 |
84 | $this->assertInstanceOf(Toolkit::class, $toolkit);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/samples/classic/program-call-data-structure-params/example.php:
--------------------------------------------------------------------------------
1 | getMessage(), "\n";
21 | exit();
22 | }
23 | $ToolkitServiceObj->setToolkitServiceParams(array('InternalKey' => "/tmp/$user"));
24 |
25 | $IOParam['var1'] = array("in" => "Y", "out" => "");
26 | $param[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'INCHARA', 'var1', $IOParam['var1']['in']);
27 | $IOParam['var2'] = array("in" => "Z", "out" => "");
28 | $param[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'INCHARB', 'var2', $IOParam['var2']['in']);
29 | $IOParam['var3'] = array("in" => "001.0001", "out" => "");
30 | $param[] = $ToolkitServiceObj->AddParameterPackDec('both', 7, 4, 'INDEC1', 'var3', '001.0001');
31 | $IOParam['var4'] = array("in" => "0000000003.04", "out" => "");
32 | $param[] = $ToolkitServiceObj->AddParameterPackDec('both', 12, 2, 'INDEC2', 'var4', '0000000003.04');
33 | $IOParam['ds1'] = array("in" => "A", "out" => "");
34 | $ds[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'DSCHARA', 'ds1', 'A');
35 | $IOParam['ds2'] = array("in" => "B", "out" => "");
36 | $ds[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'DSCHARB', 'ds2', 'B');
37 | $IOParam['ds3'] = array("in" => "005.0007", "out" => "");
38 | $ds[] = $ToolkitServiceObj->AddParameterPackDec('both', 7, 4, 'DSDEC1', 'ds3', '005.0007');
39 | $IOParam['ds4'] = array("in" => "0000000006.08", "out" => "");
40 | $ds[] = $ToolkitServiceObj->AddParameterPackDec('both', 12, 2, 'DSDEC1', 'ds4', '0000000006.08');
41 | //$param[] = array('ds'=>$ds);
42 | $param[] = $ToolkitServiceObj->AddDataStruct($ds);
43 | $result = $ToolkitServiceObj->PgmCall('ZZCALL', "ZENDSVR6", $param, null, null);
44 | if ($result) {
45 | /*update parameters array by return values */
46 | foreach ($IOParam as $key => &$element) {
47 | $element['out'] = $result['io_param'][$key];
48 | }
49 | echo "
";
50 | showTableWithHeader(array("Parameter name", "Input value", "Output value"), $IOParam);
51 | } else {
52 | echo "Execution failed.";
53 | }
54 |
55 | /* Do not use the disconnect() function for "state full" connection */
56 | $ToolkitServiceObj->disconnect();
57 |
--------------------------------------------------------------------------------
/samples/ssh-transport.php:
--------------------------------------------------------------------------------
1 | "EADDEA1EB936B3C6F7D7E5A380B6BB607E71259D",
27 | // By default, the password like other transports is used by default, but you can use another method like so:
28 | "sshMethod" => "agent",
29 | // The password is ignored if not using password authentication.
30 | // No additional parameters are used for the agent.
31 | // This is ideal because you don't need to embed credentials.
32 | // Your development environment likely has a working agent too!
33 | // Want to use SSH keys? Try something like...
34 | /*
35 | "sshMethod" => "keyfile",
36 | "sshPublicKeyFile" => "/home/calvin/.ssh/id_rsa.pub",
37 | "sshPrivateKeyFile" => "/home/calvin/.ssh/id_rsa",
38 | // (optional)
39 | "sshPassphrase" => "dubnobasswithmyheadman"
40 | */
41 | // Override the port number
42 | "sshPort" => 22,
43 | );
44 | $tkobj = ToolkitService::getInstance("hostname", "username", '', "ssh", $options);
45 | $res = $tkobj->CLInteractiveCommand("DSPLIBL");
46 | var_dump($res);
47 | // Setting it up yourself:
48 | $sshConn = ssh2_connect(hostname, 2222); // for example, custom port
49 | ssh2_auth_agent($sshConn, "username"); // simple example
50 | $tkobj = ToolkitService::getInstance($sshConn, "", "", "ssh");
51 | var_dump($res);
52 | } catch (Exception $e) {
53 | echo $e->getMessage(), "\n";
54 | }
55 |
--------------------------------------------------------------------------------
/ToolkitApi/LocalSupp.php:
--------------------------------------------------------------------------------
1 | array("pipe", "r"), // stdin
25 | 1 => array("pipe", "w"), // stdout
26 | 2 => array("pipe", "w"), // stderr
27 | );
28 | $proc = proc_open($this->getXmlserviceCliPath(), $descriptorspec, $pipes);
29 | if (!is_resource($proc)) {
30 | $this->setErrorCode("LOCAL_EXEC");
31 | $this->setErrorMsg("error executing command on local system");
32 | return false;
33 | }
34 | stream_set_blocking($pipes[0], true); // XXX
35 | $written = fwrite($pipes[0], $xmlIn);
36 | fclose($pipes[0]); // close stdin so the process starts to read
37 | $xmlOut = stream_get_contents($pipes[1]);
38 | fclose($pipes[1]);
39 | // XXX: Do something with stderr
40 | fclose($pipes[2]);
41 | proc_close($proc);
42 | return $xmlOut;
43 | }
44 |
45 | /**
46 | * @return string
47 | */
48 | public function getErrorCode()
49 | {
50 | return $this->last_errorcode;
51 | }
52 |
53 | /**
54 | * @return string
55 | */
56 | public function getErrorMsg()
57 | {
58 | return $this->last_errormsg;
59 | }
60 |
61 | /**
62 | * @param $errorCode
63 | */
64 | protected function setErrorCode($errorCode)
65 | {
66 | $this->last_errorcode = $errorCode;
67 | }
68 |
69 | /**
70 | * @param $errorMsg
71 | */
72 | protected function setErrorMsg($errorMsg)
73 | {
74 | $this->last_errormsg = $errorMsg;
75 | }
76 |
77 | /**
78 | * @param string $path
79 | */
80 | public function setXmlserviceCliPath($path)
81 | {
82 | $this->xmlserviceCliPath = $path;
83 | }
84 |
85 | /**
86 | * @return null
87 | */
88 | public function getXmlserviceCliPath()
89 | {
90 | return $this->xmlserviceCliPath;
91 | }
92 |
93 | private function checkCompat()
94 | {
95 | if (!extension_loaded("pcntl")) {
96 | $this->setErrorCode("PCNTL_NOT_LOADED");
97 | $this->setErrorMsg("the process control extension isn't loaded");
98 | return false;
99 | }
100 | return true;
101 | }
102 |
103 | /**
104 | * None of these options matter for a local transport.
105 | *
106 | * @param $server
107 | * @param $user
108 | * @param $password
109 | * @param $options
110 | * @return LocalSupp|bool
111 | */
112 | public function connect($server, $user, $password, $options)
113 | {
114 | if (!$this->checkCompat()) {
115 | return false;
116 | }
117 | // stateless, we don't have to do anything
118 | return $this;
119 | }
120 |
121 | public function disconnect()
122 | {
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/samples/call-procedure.php:
--------------------------------------------------------------------------------
1 | getCode();
13 | $msg = $e->getMessage();
14 |
15 | switch ($code) {
16 | case 8001:
17 | // "Authorization failure on distributed database connection attempt"
18 | // Usually means a wrong DB2 user or password
19 | echo 'Could not connect due to wrong user or password.';
20 | break;
21 | case 42705:
22 | echo 'Database not found. Try WRKRDBDIRE to check.';
23 | break;
24 | default:
25 | echo 'Could not connect. Error: ' . $code . ' ' . $msg;
26 | break;
27 | } //(switch)
28 | die; // couldn't connect...handle this however you wish
29 | } //(try/catch)
30 |
31 | // set stateless mode for easy testing (no 'InternalKey' needed).
32 | // (setOptions() introduced in v1.4.0)
33 | $conn->setOptions(array('stateless'=>true));
34 |
35 | /* If you wish to test this script but you don't have a real service program,
36 | * use parseOnly and parseDebugLevel as shown below.
37 | * No program will be called and you'll get your original values back.
38 | * Simply uncomment the next line to try this great testing feature of the toolkit.
39 | */
40 | //$conn->setOptions(array('parseOnly'=>true, 'parseDebugLevel'=>1));
41 |
42 | // define several input/output params
43 | $params = []; // start with empty array
44 | $params[] = $conn->AddParameterChar('in', 1,'Division', 'DIV', 'A');
45 | $params[] = $conn->AddParameterChar('in', 6,'Product', 'PROD', '123456');
46 | $params[] = $conn->AddParameterPackDec('both', 7, 2, 'Quantity', 'QTY', '4.53');
47 | $params[] = $conn->AddParameterZoned('out', 5, 2, 'Price', 'PRICE', '0');
48 |
49 | // define a procedure return param. Can be any type, even a data structure
50 | $retParam = $conn->AddParameterInt32('out', '4-byte int', 'MYRESULT', '13579');
51 |
52 | /* Call service program procedure.
53 | * Procedure name is optional and specified in parameter 5, an array containing associative index 'func'.
54 | * Make sure your procedure name is 100% correct. It is case-sensitive.
55 | * If you get an error, look for your procedure name in the output from this command (replacing LIBNAME/PGMNAME with your library and program names):
56 | * DSPSRVPGM SRVPGM(LIBNAME/PGMNAME) DETAIL(*PROCEXP)
57 | * In this example, assume your program is MYLIB/MYPGM and has a procedure/function 'myproc'
58 | */
59 | $result = $conn->PgmCall('MYPGM', 'MYLIB', $params, $retParam, array('func'=>'myproc'));
60 |
61 | if (!$result) {
62 | echo 'Error calling program. Code: ' . $conn->getErrorCode() . ' Msg: ' . $conn->getErrorMsg();
63 | }
64 |
65 | echo 'Called program successfully.
';
66 | echo 'Input/output params: QTY: ' . $result['io_param']['QTY'] . ' PRICE: ' . $result['io_param']['PRICE'] . '
';
67 | echo 'Procedure return param MYRESULT: ' . $result['retvals']['MYRESULT'];
68 |
69 | /*
70 | The above will output something like:
71 |
72 | Called program successfully.
73 |
74 | Input/output params: QTY: 4.53 PRICE: 0.00
75 | Procedure return param MYRESULT: 13579
76 |
77 | */
78 |
--------------------------------------------------------------------------------
/ToolkitApi/SystemValues.php:
--------------------------------------------------------------------------------
1 | ToolkitSrvObj = $ToolkitSrvObj;
20 | return $this;
21 | } else {
22 | return false;
23 | }
24 | }
25 |
26 | /**
27 | *
28 | * @todo Deprecate setConnection in future.
29 | *
30 | * @param $dbname
31 | * @param $user
32 | * @param $pass
33 | */
34 | public function setConnection ($dbname , $user, $pass)
35 | {
36 | if (!$this->ToolkitSrvObj instanceof Toolkit) {
37 | $this->ToolkitSrvObj = new Toolkit($dbname, $user, $pass);
38 | }
39 | }
40 |
41 | /**
42 | * @return array|bool
43 | */
44 | public function systemValuesList()
45 | {
46 | if (!$this->ToolkitSrvObj instanceof Toolkit) {
47 | return false;
48 | }
49 |
50 | $tmparray = $this->ToolkitSrvObj->CLInteractiveCommand ('WRKSYSVAL OUTPUT(*PRINT)');
51 |
52 | if (isset($tmparray)) {
53 | $i = 4;
54 | while (isset($tmparray [$i + 1])) {
55 | $tmparr = trim($tmparray [++$i]);
56 | if (substr($tmparr, 0, 1) == 'Q') {
57 | $len = strlen ($tmparr);
58 | $sysvals [] = array('Name' => substr ($tmparr, 0, 10),
59 | 'CurrentValue' => substr ($tmparr, 15, 32),
60 | 'ShippedValue' => substr ($tmparr, 47, 32),
61 | 'Description' => substr ($tmparr, 79, ($len - 79)));
62 | }
63 | }
64 | return $sysvals;
65 | } else {
66 | return false;
67 | }
68 | }
69 |
70 | /**
71 | * @todo QWCRSVAL to work with 2 tiers while retaining good performance
72 | *
73 | * @param $sysValueName
74 | */
75 | public function getSystemValue($sysValueName)
76 | {
77 | if (!$this->ToolkitSrvObj instanceof Toolkit) {
78 | return false;
79 | }
80 |
81 | $Err = ' ';
82 | $SysValue = ' ';
83 | $params [] = $this->ToolkitSrvObj->AddParameterChar('both', 1, "ErrorCode", 'errorcode', $Err);
84 | $params [] = $this->ToolkitSrvObj->AddParameterChar('both', 10, "SysValName", 'sysvalname', $sysValueName);
85 | $params [] = $this->ToolkitSrvObj->AddParameterChar('both', 1024, "SysValue", 'sysval', $SysValue);
86 | $retArr = $this->ToolkitSrvObj->PgmCall(ZSTOOLKITPGM, $this->ToolkitSrvObj->getOption('HelperLib'), $params, NULL, array('func' => 'RTVSYSVAL'));
87 |
88 | if ($retArr !== false && isset($retArr['io_param'])) {
89 | $sysval = $retArr['io_param'];
90 | if (isset($sysval['sysvalname'])) {
91 | return $sysval['sysval'];
92 | } else {
93 | $this->setError($sysval['errorcode']);
94 | }
95 | }
96 | }
97 |
98 | /**
99 | * @return mixed
100 | */
101 | public function getError() {
102 | return $this->ErrMessage;
103 | }
104 |
105 | /**
106 | * @param $errCode
107 | */
108 | private function setError($errCode)
109 | {
110 | if ($errCode == '') /*clear error message*/ {
111 | $this->ErrMessage = '';
112 | return;
113 | }
114 |
115 | if ($errCode == '1') {
116 | $this->ErrMessage = 'System value data is not available.';
117 | } else {
118 | if ($errCode == '2') {
119 | $this->ErrMessage = 'System value can not be retrieved. ';
120 | }
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/ToolkitApi/autoload.php:
--------------------------------------------------------------------------------
1 | __DIR__ . DIRECTORY_SEPARATOR . 'Toolkit.php',
8 | 'ToolkitApi\ToolkitInterface' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitInterface.php',
9 | 'ToolkitApi\db2supp' => __DIR__ . DIRECTORY_SEPARATOR . 'Db2supp.php',
10 | 'ToolkitApi\httpsupp' => __DIR__ . DIRECTORY_SEPARATOR . 'httpsupp.php',
11 | 'ToolkitApi\SshSupp' => __DIR__ . DIRECTORY_SEPARATOR . 'SshSupp.php',
12 | 'ToolkitApi\LocalSupp' => __DIR__ . DIRECTORY_SEPARATOR . 'LocalSupp.php',
13 | 'ToolkitApi\DateTimeApi' => __DIR__ . DIRECTORY_SEPARATOR . 'DateTimeApi.php',
14 | 'ToolkitApi\ListFromApi' => __DIR__ . DIRECTORY_SEPARATOR . 'ListFromApi.php',
15 | 'ToolkitApi\UserSpace' => __DIR__ . DIRECTORY_SEPARATOR . 'UserSpace.php',
16 | 'ToolkitApi\TmpUserSpace' => __DIR__ . DIRECTORY_SEPARATOR . 'TmpUserSpace.php',
17 | 'ToolkitApi\DataQueue' => __DIR__ . DIRECTORY_SEPARATOR . 'DataQueue.php',
18 | 'ToolkitApi\SpooledFiles' => __DIR__ . DIRECTORY_SEPARATOR . 'SpooledFiles.php',
19 | 'ToolkitApi\JobLogs' => __DIR__ . DIRECTORY_SEPARATOR . 'JobLogs.php',
20 | 'ToolkitApi\ObjectLists' => __DIR__ . DIRECTORY_SEPARATOR . 'ObjectLists.php',
21 | 'ToolkitApi\SystemValues' => __DIR__ . DIRECTORY_SEPARATOR . 'SystemValues.php',
22 | 'ToolkitApi\DataArea' => __DIR__ . DIRECTORY_SEPARATOR . 'DataArea.php',
23 | 'ToolkitApi\odbcsupp' => __DIR__ . DIRECTORY_SEPARATOR . 'Odbcsupp.php',
24 | 'ToolkitApi\PdoSupp' => __DIR__ . DIRECTORY_SEPARATOR . 'PdoSupp.php',
25 | 'ToolkitApi\ToolkitPcml' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitPCML.php',
26 | 'ToolkitApi\ProgramParameter' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
27 | 'ToolkitApi\DataStructure' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
28 | 'ToolkitApi\CharParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
29 | 'ToolkitApi\ZonedParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
30 | 'ToolkitApi\PackedDecParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
31 | 'ToolkitApi\Int32Param' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
32 | 'ToolkitApi\SizeParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
33 | 'ToolkitApi\SizePackParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
34 | 'ToolkitApi\Int64Param' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
35 | 'ToolkitApi\UInt32Param' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
36 | 'ToolkitApi\UInt64Param' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
37 | 'ToolkitApi\FloatParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
38 | 'ToolkitApi\RealParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
39 | 'ToolkitApi\HoleParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
40 | 'ToolkitApi\BinParam' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceParameter.php',
41 | 'ToolkitApi\XMLWrapper' => __DIR__ . DIRECTORY_SEPARATOR . 'ToolkitServiceXML.php',
42 | 'ToolkitApi\CW\ToolkitServiceCw' => __DIR__ . DIRECTORY_SEPARATOR . 'CW' . DIRECTORY_SEPARATOR . 'ToolkitServiceCw.php',
43 | 'ToolkitApi\CW\I5Error' => __DIR__ . DIRECTORY_SEPARATOR . 'CW' . DIRECTORY_SEPARATOR . 'I5Error.php',
44 | 'ToolkitApi\CW\DataDescription' => __DIR__ . DIRECTORY_SEPARATOR . 'CW' . DIRECTORY_SEPARATOR . 'DataDescription.php',
45 | 'ToolkitApi\CW\DataDescriptionPcml' => __DIR__ . DIRECTORY_SEPARATOR . 'CW' . DIRECTORY_SEPARATOR . 'DataDescriptionPcml.php',
46 | 'ToolkitApi\Int8Param' => __DIR__ . DIRECTORY_SEPARATOR . 'Int8Param.php',
47 | 'ToolkitApi\UInt8Param' => __DIR__ . DIRECTORY_SEPARATOR . 'UInt8Param.php',
48 | 'ToolkitApi\Int16Param' => __DIR__ . DIRECTORY_SEPARATOR . 'Int16Param.php',
49 | 'ToolkitApi\UInt16Param' => __DIR__ . DIRECTORY_SEPARATOR . 'UInt16Param.php',
50 | );
51 |
52 | if (array_key_exists($class, $classmap)) {
53 | $file = $classmap[$class];
54 | if (file_exists($file)) {
55 | require_once $file;
56 | }
57 | }
58 |
59 | return;
60 | });
61 |
--------------------------------------------------------------------------------
/tests/ToolkitApiTest/ProgramParameterTest.php:
--------------------------------------------------------------------------------
1 | size = 20;
31 | $this->type = sprintf('%dB', $this->size);
32 | $this->io = 'both';
33 | $this->comment = 'p1';
34 | $this->var = 'test';
35 | $this->data = 'off';
36 | $this->varying = 0;
37 | $this->dim = '';
38 | $this->by = false;
39 | $this->programParameter = new ProgramParameter(
40 | $this->type,
41 | $this->io,
42 | $this->comment,
43 | $this->var,
44 | $this->data,
45 | $this->varying,
46 | $this->dim,
47 | $this->by
48 | );
49 | }
50 |
51 | public function testCanGetParameterProperties(): void
52 | {
53 | $data1 = $this->programParameter->getParamProperities();
54 | $data2 = array(
55 | 'type' => $this->type,
56 | 'io' => $this->io,
57 | 'comment' => $this->comment,
58 | 'var' => $this->var,
59 | 'data' => $this->data,
60 | 'varying' => $this->varying,
61 | 'dim' => $this->dim,
62 | 'by' => $this->by,
63 | 'array' => false,
64 | 'setlen' => null,
65 | 'len' => null,
66 | 'dou' => '',
67 | 'enddo' => '',
68 | 'ccsidBefore' => '',
69 | 'ccsidAfter' => '',
70 | 'useHex' => false,
71 | );
72 |
73 | $this->assertEquals($data1, $data2);
74 | }
75 |
76 | public function testGetParameterPropertiesFacadeMethodReturnsSameAsRealMethod(): void
77 | {
78 | $data1 = $this->programParameter->getParamProperities();
79 | $data2 = $this->programParameter->getParamProperties();
80 |
81 | $this->assertEquals($data1, $data2);
82 | }
83 |
84 |
85 | }
86 |
87 | /*class DataStructureTest extends \PHPUnit_Framework_TestCase
88 | {
89 |
90 | }
91 |
92 | class CharParamTest extends \PHPUnit_Framework_TestCase
93 | {
94 |
95 | }
96 |
97 | class ZonedParamTest extends \PHPUnit_Framework_TestCase
98 | {
99 |
100 | }
101 |
102 | class PackedDecParamTest extends \PHPUnit_Framework_TestCase
103 | {
104 |
105 | }
106 |
107 | class Int32ParamTest extends \PHPUnit_Framework_TestCase
108 | {
109 |
110 | }
111 |
112 | class SizeParamTest extends \PHPUnit_Framework_TestCase
113 | {
114 |
115 | }
116 |
117 | class SizePackParamTest extends \PHPUnit_Framework_TestCase
118 | {
119 |
120 | }
121 |
122 | class Int64ParamTest extends \PHPUnit_Framework_TestCase
123 | {
124 |
125 | }
126 |
127 | class UInt32ParamTest extends \PHPUnit_Framework_TestCase
128 | {
129 |
130 | }
131 |
132 | class UInt64ParamTest extends \PHPUnit_Framework_TestCase
133 | {
134 |
135 | }
136 |
137 | class FloatParamTest extends \PHPUnit_Framework_TestCase
138 | {
139 |
140 | }
141 |
142 | class RealParamTest extends \PHPUnit_Framework_TestCase
143 | {
144 |
145 | }
146 |
147 | class HoleParamTest extends \PHPUnit_Framework_TestCase
148 | {
149 | public function testCanCreateInstance()
150 | {
151 |
152 | }
153 | }*/
154 |
155 | /**
156 | * Class BinParamTest
157 | * @package ToolkitApiTest
158 | */
159 | final class BinParamTest extends TestCase
160 | {
161 | /**
162 | * @var BinParam $binParam
163 | */
164 | protected $binParam;
165 |
166 | /**
167 | * @var ProgramParameter $programParameter
168 | */
169 | protected $programParameter;
170 |
171 | protected function setUp(): void
172 | {
173 | $size = 20;
174 | $this->binParam = new BinParam('both', $size, 'UncodeSample', 'p1', 'test');
175 | $type = sprintf('%dB', $size);
176 | $this->programParameter = new ProgramParameter($type, 'both', 'p1', 'test', 'off', 0, '', false);
177 | }
178 |
179 | public function testCanConvertBinaryToString(): void
180 | {
181 | $hex = '74657374';
182 | $data1 = $this->binParam->bin2str($hex);
183 | $data2 = $this->programParameter->bin2str($hex);
184 |
185 | $this->assertEquals($data1, $data2);
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/ToolkitApi/PdoSupp.php:
--------------------------------------------------------------------------------
1 | setError();
39 | return false;
40 | }
41 |
42 | $conn = new PDO($database, $user, $password, $options);
43 |
44 | if (!$conn instanceof PDO) {
45 | $this->setError();
46 | return false;
47 | }
48 |
49 | return $conn;
50 | }
51 |
52 | /**
53 | * PdoSupp constructor.
54 | * @param PDO $pdo
55 | */
56 | public function __construct(PDO $pdo)
57 | {
58 | $this->pdo = $pdo;
59 | }
60 |
61 | /**
62 | * @param PDO $conn
63 | */
64 | public function disconnect($conn)
65 | {
66 | if ($conn instanceof PDO) {
67 | $conn = null;
68 | }
69 | }
70 |
71 | /**
72 | * @param PDO|null $conn
73 | */
74 | protected function setError($conn = null)
75 | {
76 | if ($conn) {
77 | $this->setErrorCode($conn->errorCode());
78 | $this->setErrorMsg(implode('|', $conn->errorInfo()));
79 | } else {
80 | $this->setErrorCode($this->pdo->errorCode());
81 | $this->setErrorMsg(implode('|', $this->pdo->errorInfo()));
82 | }
83 | }
84 |
85 | /**
86 | * @param string $errorCode
87 | */
88 | protected function setErrorCode($errorCode)
89 | {
90 | $this->last_errorcode = $errorCode;
91 | }
92 |
93 | /**
94 | * @return string
95 | */
96 | public function getErrorCode()
97 | {
98 | return $this->last_errorcode;
99 | }
100 |
101 | /**
102 | * @param string $errorMsg
103 | */
104 | protected function setErrorMsg($errorMsg)
105 | {
106 | $this->last_errormsg = $errorMsg;
107 | }
108 |
109 | /**
110 | * @return string
111 | */
112 | public function getErrorMsg()
113 | {
114 | return $this->last_errormsg;
115 | }
116 |
117 | /**
118 | * this function used for special stored procedure call only
119 | *
120 | * @param PDO $conn
121 | * @param string $stmt
122 | * @param array $bindArray
123 | * @return string
124 | */
125 | public function execXMLStoredProcedure($conn, $stmt, $bindArray)
126 | {
127 | $statement = $conn->prepare($stmt);
128 |
129 | if (!$statement) {
130 | $this->setError($conn);
131 | return false;
132 | }
133 |
134 | $result = $statement->execute(array(
135 | $bindArray['internalKey'],
136 | $bindArray['controlKey'],
137 | $bindArray['inputXml']
138 | ));
139 |
140 | if (!$result) {
141 | $this->setError($conn);
142 | return "PDO error code: " . $this->pdo->errorCode() . ' msg: ' . $this->pdo->errorInfo();
143 | }
144 |
145 | $outputXml = '';
146 |
147 | if (!$bindArray['disconnect']) { // a disconnect request won't return data
148 | // Loop through rows, concatenating XML into a final XML string.
149 | foreach ($statement->fetchAll() as $row) {
150 | // for each row, get XML string from first and only array element,
151 | // no matter whether assoc or numeric key
152 | $xmlChunk = reset($row);
153 | if ($xmlChunk) {
154 | // Remove any "garbage" from after ending tag (there used to be an ODBC clob issue)
155 | if (strstr($xmlChunk , "")) {
156 | $pos = strpos($xmlChunk, "");
157 | $pos += strlen("");
158 | $outputXml .= substr($xmlChunk, 0, $pos);
159 | break;
160 | } else {
161 | $outputXml .= $xmlChunk;
162 | }
163 | }
164 | }
165 | }
166 |
167 | return $outputXml;
168 | }
169 |
170 | /**
171 | * @param PDO $conn
172 | * @param string $stmt
173 | * @return array
174 | */
175 | public function executeQuery($conn, $stmt)
176 | {
177 | $txt = array();
178 | $statement = $conn->prepare($stmt);
179 | $result = $statement->execute();
180 |
181 | if (!$result) {
182 | $this->setError($conn);
183 | return $txt;
184 | }
185 | foreach ($statement->fetchAll() as $row) {
186 | $txt[] = $row;
187 | }
188 |
189 | return $txt;
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/ToolkitApi/ListFromApi.php:
--------------------------------------------------------------------------------
1 | ..... that we'll wrap in a receiver variable. At this time it must be an XML string.
12 |
13 | // listinfo: totalRecords, firstRecordNumber, requestHandle. if firstRec... < totalRecords then can continue.
14 | // return I5_ERR_BEOF when went past last record. get CPF GUI0006 when used invalid record#.
15 |
16 | /**
17 | * @param $requestHandle
18 | * @param $totalRecords
19 | * @param $receiverDs
20 | * @param $lengthOfReceiverVariable
21 | * @param ToolkitInterface $ToolkitSrvObj
22 | */
23 | public function __construct($requestHandle, $totalRecords, $receiverDs, $lengthOfReceiverVariable, ?ToolkitInterface $ToolkitSrvObj = null)
24 | {
25 | if ($ToolkitSrvObj instanceof Toolkit) {
26 | $this->ToolkitSrvObj = $ToolkitSrvObj;
27 | }
28 |
29 | $this->_requestHandle = $requestHandle;
30 | $this->_receiverSize = $lengthOfReceiverVariable;
31 | $this->_totalRecords = $totalRecords;
32 | $this->_nextRecordToRequest = 1; // will request record #1 when someone asks
33 | $this->_receiverDs = $receiverDs; // will request record #1 when someone asks
34 | }
35 |
36 | /**
37 | * @return ToolkitInterface
38 | */
39 | public function getConn()
40 | {
41 | return $this->ToolkitSrvObj;
42 | }
43 |
44 | /**
45 | * Call QGYGTLE (get list entry) API using handle and "next record to request."
46 | *
47 | * Note: if get timing problems where no records are returned:
48 | * Embed the call to the QGYGTLE API in a do-loop that loops until a record is returned.
49 | *
50 | * @return bool Return false when run out of records (get GUI0006 error code).
51 | */
52 | public function getNextEntry()
53 | {
54 | $apiPgm = 'QGYGTLE';
55 | $apiLib = 'QSYS';
56 |
57 | $receiverDs = $this->_receiverDs;
58 | $requestHandle = $this->_requestHandle;
59 | $lengthOfReceiverVariable = $this->_receiverSize;
60 | $nextRecordToRequest = $this->_nextRecordToRequest++; // assign to me, then increment for next time
61 |
62 | $outputVarname = 'receiver';
63 |
64 | $lenLabel= 'size' . $outputVarname;
65 |
66 | $paramXml = "
67 |
68 | $receiverDs
69 |
70 |
71 |
72 | $lengthOfReceiverVariable
73 |
74 |
75 | $requestHandle
76 | \n" . $this->ToolkitSrvObj->getListInfoApiXml(4) . "\n" .
77 | "
78 | 1
79 |
80 |
81 | $nextRecordToRequest
82 | \n" .
83 | Toolkit::getErrorDataStructXmlWithCode(7); // param number 7
84 |
85 | // was getErrorDataStructXml
86 | // pass param xml directly in.
87 | $retPgmArr = $this->ToolkitSrvObj->PgmCall($apiPgm, $apiLib, $paramXml);
88 |
89 | if ($this->ToolkitSrvObj->getErrorCode()) {
90 | return false;
91 | }
92 |
93 | /* Even when no error reported by XMLSERVICE (->error),
94 | * we may get a GUI0006 in DS error structure exeption code, since we
95 | * supplied a full error data structure above (getErrorDataStructXmlWithCode).
96 | */
97 | $apiErrCode = $retPgmArr['io_param']['errorDs']['exceptId'];
98 |
99 | if ($apiErrCode != '0000000') {
100 | // Note: caller can check for GUI0006 and GUI0001 (expected when go past last record) vs. any other error (not expected)
101 | $this->ToolkitSrvObj->setErrorCode($apiErrCode);
102 | return false;
103 | }
104 |
105 | $retArr = $retPgmArr['io_param'][$outputVarname];
106 |
107 | return $retArr;
108 | }
109 |
110 | /**
111 | * close the list
112 | *
113 | * @return bool
114 | */
115 | public function close()
116 | {
117 | // call QGYCLST, the "close list" api.
118 | $apiPgm = 'QGYCLST';
119 | $apiLib = 'QSYS';
120 |
121 | $requestHandle = $this->_requestHandle;
122 |
123 | $paramXml = "
124 | $requestHandle
125 | \n" . Toolkit::getErrorDataStructXml(2); // param number 2
126 |
127 | // pass param xml directly in.
128 | $this->ToolkitSrvObj->PgmCall($apiPgm, $apiLib, $paramXml);
129 |
130 | // GUI0006 means end of list
131 | if ($this->ToolkitSrvObj->getErrorCode()) {
132 | return false;
133 | } else {
134 | return true;
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/samples/data-types.md:
--------------------------------------------------------------------------------
1 | # Data Types for XMLSERVICE and PHP Toolkit #
2 |
3 | This reference, begun by Tony Cairns while at IBM, used to be housed at `http://www.youngiprofessionals.com/wiki/index.php/XMLService/DataTypes`, but that site is no longer available, so we have made it available here, and added to it.
4 |
5 | ## Data Type Equivalents for C / RPG / XMLSERVICE XML / SQL ##
6 |
7 | ```
8 | C types RPG types XMLSERVICE types SQL types
9 | =============== ============================ ================================================ =========
10 | char D mychar 32a CHAR(32)
11 | varchar2 D myvchar2 32a varying VARCHAR(32)
12 | varchar4 D myvchar4 32a varying(4)
13 | packed D mydec 12p 2 DECIMAL(12,2)
14 | zoned D myzone 12s 2 NUMERIC(12,2)
15 | float D myfloat 4f FLOAT
16 | real/double D myreal 8f DOUBLE
17 | binary D mybin (any) F1F2F3 BINARY
18 | hole (no out) D myhole (any)
19 | boolean D mybool 1n CHAR(4)
20 | time D mytime T timfmt(*iso) 09.45.29 TIME
21 | timestamp D mystamp Z 2011-12-29-12.45.29.000000 TIMESTAMP
22 | date D mydate D datfmt(*iso) 2009-05-11 DATE
23 | int8/byte D myint8 3i 0 TINYINT (unsupported DB2)
24 | int16/short D myint16 5i 0 (4b 0) SMALLINT
25 | int32/int D myint32 10i 0 (9b 0) INTEGER
26 | int64/longlong D myint64 20i 0 BIGINT
27 | uint8/ubyte D myuint8 3u 0
28 | uint16/ushort D myuint16 5u 0
29 | uint32/uint D myuint32 10u 0
30 | uint64/ulonglong D myuint64 20u 0
31 | [indicator] D myind 1a
32 |
33 | ```
34 | * Notes on the two sizes of VARCHAR:
35 | * varchar2: accommodates a string of 1-65535 bytes.
36 | * varchar4: use if string may be larger than 65535 bytes.
37 | * More information about varchar data types:
38 | * https://www.ibm.com/docs/en/i/7.5?topic=keywords-varcharlength-2-4 [https://www.ibm.com/docs/en/i/7.5?topic=keywords-varcharlength-2-4]
39 | * https://www.ibm.com/docs/en/i/7.5?topic=type-variable-length-character-graphic-ucs-2-formats [https://www.ibm.com/docs/en/i/7.5?topic=type-variable-length-character-graphic-ucs-2-formats]
40 | * Note on TIMFMT and DATFMT: see your own RPG source code for the format required by the parameter.
41 | * We assume a default of *ISO if not specified.
42 | * Example: https://github.com/IBM/xmlservice/blob/84de343df1dc513d5774f5c1f470ada6701f6488/src/zzvlad.rpgle#L6
43 | * Reference for date formats: https://www.ibm.com/docs/en/i/7.1?topic=80-datfmt-date-format-keyword-display-files
44 |
45 |
46 | ## PHP Toolkit Functions That Implement the XMLSERVICE Data Types Shown Above ###
47 |
48 | ```
49 | toolkit method/class type i/o comment varName value
50 | ======================= ===== ====== ======= ======== =====
51 | $tk->AddParameterChar ( "both",32, "char", "mychar", "");
52 | $tk->AddParameterChar ( "both",32, "varchar2", "myvchar2", "", "on");
53 | $tk->AddParameterChar ( "both",32, "varchar4", "myvchar4", "", 4);
54 | $tk->AddParameterZoned ( "both",12,2,"packed", "mydec", 0.0);
55 | $tk->AddParameterPackDec( "both",12,2,"zoned", "myzone", 0.0);
56 | $tk->AddParameterFloat ( "both", "float", "myfloat", 0.0);
57 | $tk->AddParameterReal ( "both", "real", "myreal", 0.0);
58 | $tk->AddParameterBin ( "both", 9, "binary", "mybin", bin2hex(0xF1F2F3)); // to binary pack("H*", $hex)
59 | $tk->AddParameterHole ( 40, "hole" ); // no output (zero input)
60 | $tk->AddParameterChar ( "both", 4, "boolean", "mybool", "1");
61 | $tk->AddParameterChar ( "both", 8, "time", "mytime", "09.45.29");
62 | $tk->AddParameterChar ( "both", 26, "timestamp", "mystamp", "2011-12-29-12.45.29.000000");
63 | $tk->AddParameterChar ( "both", 10, "date", "mydate", "2009-05-11");
64 | new ProgramParameter ("3i0","both", "byte", "myint8", 0); // work around missing $tk->AddParameterInt8
65 | new ProgramParameter ("5i0","both", "short", "myint16", 0); // work around missing $tk->AddParameterInt16
66 | $tk->AddParameterInt32 ( "both", "int", "myint32", 0);
67 | $tk->AddParameterInt64 ( "both", "longlong", "myint64", 0);
68 | new ProgramParameter ("3u0","both", "ubyte", "myuint8", 0); // work around missing $tk->AddParameterUInt8
69 | new ProgramParameter ("5u0","both", "ushort", "myuint16", 0); // work around missing $tk->AddParameterUInt16
70 | $tk->AddParameterUInt32 ( "both", "uint", "myuint32", 0);
71 | $tk->AddParameterUInt64 ( "both", "ulonglong", "myuint64", 0);
72 | $tk->AddParameterChar ( "out", 1, "ind '0'/'1'" "myind", ""); // indicator type is boolean 1-byte character
73 | $tk->AddDataStruct ([array of parameters], "myds" );
74 |
75 | ```
76 |
--------------------------------------------------------------------------------
/samples/options.php:
--------------------------------------------------------------------------------
1 | true | false
7 |
8 | // 'stateless' is the most important option. Although false is the default value, true is much better for most users.
9 | // 'stateless' => true is usually the better choice. XMLSERVICE will run in an existing database job without creating additional jobs.
10 | // 'stateless' => false (default) results in a stateful connection where XMLSERVICE launches a separate job that stays running until ended.
11 | // When using stateless => false, remember to choose an InternalKey.
12 | // Example of 'stateless' => true, which is best for most uses.
13 | $conn->setOptions(array('stateless' => true)); // specify true unless you have a good reason not to.
14 |
15 | // # 'InternalKey' => $artibitraryDirectory
16 |
17 | // 'InternalKey', combined with turning on stateful mode, will cause a stateful toolkit job to be identified uniquely by the system.
18 | // The value of InternalKey should be an empty directory, typically under /tmp.
19 | // Any toolkit script specifying this InternalKey value and stateful mode can access the same XMLSERVICE job later as needed.
20 | // The stateful technique is useful for accessing QTEMP and *LDA resources in this unique job.
21 | // The job will remain running until ended *IMMED or timed out using a timeout option (see below)
22 | // Note: omitting InternalKey in stateful mode would cause a default key of '/tmp/Toolkit' to be used, which would mean everyone is sharing a single XMLSERVICE job.
23 | $conn->setOptions(array('stateless' => false,
24 | 'InternalKey' => "/tmp/alan2"
25 | ));
26 |
27 | // # 'idleTimeout' => $idleTimeoutSeconds
28 |
29 | // 'idleTimeout' will cause a stateful toolkit job to end after the specified number of seconds of inactivity.
30 | // This option will tell XMLSERVICE to use timeout setting *idle(3600/kill). For advanced timeout options, see: http://yips.idevcloud.com/wiki/index.php/XMLService/XMLSERVICETIMEOUT
31 |
32 | // In the example below, the XMLSERVICE job will end after 3600 seconds (one hour) of not being used.
33 | $conn->setOptions(array('stateless' => false,
34 | 'InternalKey' => "/tmp/alan2",
35 | 'idleTimeout' => 3600
36 | ));
37 |
38 | // # 'customControl' => $customControlKeys
39 |
40 | // 'customControl' is useful when you need to send control keys supported by XMLSERVICE but that aren't directly exposed by the PHP Toolkit.
41 | // Helpful for the less popular control keys that you might still need from time to time.
42 | // To send multiple keys, include a space between each.
43 |
44 | // Example #1: *java when calling an RPG program that includes java.
45 |
46 | $conn->setOptions(array('stateless' => true,
47 | 'customControl'=>'*java'
48 | ));
49 |
50 | // Example #2: *call. Useful for setting a timeout on a hanging or looping RPG program. This example for stateless mode.
51 | $conn->setOptions(array('stateless' => true,
52 | 'customControl'=> '*call(15/kill/server)', // return control to PHP after waiting 15 seconds. CPF is available in error code as well.
53 | ));
54 |
55 | // Example #3: *call and *sbmjob. Useful for setting a timeout on a hanging or looping RPG program. This example for stateful (IPC) mode.
56 | $conn->setOptions(array('stateless' => false, // explicitly be stateful when using this timeout option
57 | 'internalKey' => '/tmp/tkitjob2', // arbitrary directory name under /tmp to represent unique job
58 | 'customControl'=> '*call(15/kill/server) *sbmjob', // return control to PHP after waiting 15 seconds. CPF is available in error code as well.
59 | ));
60 |
61 |
62 | // # 'debug' => true or false
63 | // # 'debugLogFile' => path of log file
64 | // For both, defaults are set in toolkit.ini under the [system] group.
65 |
66 | // The debug log, when enabled, logs all XML sent/received, as well as connection information, and timing of each request.
67 | // It is invaluable for troubleshooting performance and program calls.
68 | // Make sure the PHP user (probably QTMHHTTP if running from the web) has *RW access to the file,
69 | // and, if the file doesn't yet exist, *RWX access to the parent directory so PHP can create the file.
70 | // The file can get large, so we recommend setting debug => false when logging is not needed.
71 |
72 | $conn->setOptions(array('debug' => true,
73 | 'debugLogFile'=>'/my/path/tkit_debug.log'
74 | ));
75 |
76 |
77 | // sbmjobCommand is an advanced keyword. Use it when you need to set your own job name or other parameters for a stateful toolkit job.
78 | // # 'sbmjobCommand' => full sbmjob command for full control of stateful toolkit job parameters (advanced)
79 |
80 | // Set these three values according to your needs (sample values given here)
81 | $internalKey = '/tmp/mykey123'; // unique identifier for job
82 | $jobName = 'MYTOOLKIT3';
83 | $jobQueue = 'QSYS/QSYSNOMAX';
84 |
85 | // specify stateful mode and the internal key (IPC) we established earlier.
86 | $conn->setOptions(['stateless' => false,
87 | 'internalKey' => $internalKey,
88 | ]);
89 |
90 | // Set up values needed in the sbmjob command
91 | $ipc = trim($conn->getInternalKey());
92 | $serviceLibrary = trim($conn->getOption('XMLServiceLib'));
93 | $jobNameParam = "JOB($jobName)";
94 | $jobqParam = "JOBQ($jobQueue)";
95 |
96 | // Fully customize where and how XMLSERVICE runs by building the SBMJOB command and set it up in the toolkit
97 | $sbmjobCommand = "SBMJOB CMD(CALL PGM({$serviceLibrary}/XMLSERVICE) PARM('$ipc')) {$jobNameParam} {$jobqParam}";
98 | $conn->setOptions(['sbmjobCommand' => $sbmjobCommand,
99 | 'sbmjobParams' => '', // empty because set these values in sbmjobCommand
100 | 'customControl' => '*sbmjob', // required when setting sbmjobCommand
101 | ]);
102 |
103 | ?>
104 |
--------------------------------------------------------------------------------
/ToolkitApi/Odbcsupp.php:
--------------------------------------------------------------------------------
1 | =') && $conn instanceof \Odbc\Connection)) {
42 | return $conn;
43 | }
44 | }
45 |
46 | $this->setError();
47 | return false;
48 | }
49 |
50 | /**
51 | * @param resource $conn
52 | */
53 | public function disconnect($conn)
54 | {
55 | if ((version_compare(PHP_VERSION, '8.4.0', '<') && is_resource($conn)) ||
56 | (version_compare(PHP_VERSION, '8.4.0', '>=') && $conn instanceof \Odbc\Connection)) {
57 | odbc_close($conn);
58 | }
59 | }
60 |
61 | /**
62 | * set error code and message based on last odbc connection/prepare/execute error.
63 | *
64 | * @todo: consider using GET DIAGNOSTICS for even more message text:
65 | * http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Frzala%2Frzalafinder.htm
66 | *
67 | * @param resource|null $conn
68 | */
69 | protected function setError($conn = null)
70 | {
71 | // is conn resource provided, or do we get last error?
72 | if ($conn) {
73 | $this->setErrorCode(odbc_error($conn));
74 | $this->setErrorMsg(odbc_errormsg($conn));
75 | } else {
76 | $this->setErrorCode(odbc_error());
77 | $this->setErrorMsg(odbc_errormsg());
78 | }
79 | }
80 |
81 | /**
82 | * @param string $errorCode
83 | */
84 | protected function setErrorCode($errorCode)
85 | {
86 | $this->last_errorcode = $errorCode;
87 | }
88 |
89 | /**
90 | * @return string
91 | */
92 | public function getErrorCode()
93 | {
94 | return $this->last_errorcode;
95 | }
96 |
97 | /**
98 | * @param string $errorMsg
99 | */
100 | protected function setErrorMsg($errorMsg)
101 | {
102 | $this->last_errormsg = $errorMsg;
103 | }
104 |
105 | /**
106 | * @return string
107 | */
108 | public function getErrorMsg()
109 | {
110 | return $this->last_errormsg;
111 | }
112 |
113 | /**
114 | * this function used for special stored procedure call only
115 | *
116 | * @param resource $conn
117 | * @param string $stmt
118 | * @param array $bindArray
119 | * @return string
120 | */
121 | public function execXMLStoredProcedure($conn, $stmt, $bindArray)
122 | {
123 | $crsr = odbc_prepare($conn, $stmt);
124 |
125 | if (!$crsr) {
126 | $this->setError($conn);
127 | return false;
128 | }
129 |
130 | // extension problem: sends warning message into the php_log or stdout
131 | // about number of result sets. (switch on return code of SQLExecute()
132 | // SQL_SUCCESS_WITH_INFO
133 | if (!@odbc_execute($crsr , array($bindArray['internalKey'], $bindArray['controlKey'], $bindArray['inputXml']))) {
134 | $this->setError($conn);
135 | return "ODBC error code: " . $this->getErrorCode() . ' msg: ' . $this->getErrorMsg();
136 | }
137 |
138 | // disconnect operation cause crush in fetch, nothing appears as sql script.
139 | $row='';
140 | $outputXML = '';
141 | if (!$bindArray['disconnect']) {
142 | while (odbc_fetch_row($crsr)) {
143 | $tmp = odbc_result($crsr, 1);
144 |
145 | if ($tmp) {
146 | // because of ODBC problem blob transferring should execute some "clean" on returned data
147 | if (strstr($tmp , "")) {
148 | $pos = strpos($tmp, "");
149 | $pos += strlen(""); // @todo why append this value?
150 | $row .= substr($tmp, 0, $pos);
151 | break;
152 | } else {
153 | $row .= $tmp;
154 | }
155 | }
156 | }
157 | $outputXML = $row;
158 | }
159 |
160 | return $outputXML;
161 | }
162 |
163 | /**
164 | * @param resource $conn
165 | * @param string $stmt
166 | * @return array
167 | */
168 | public function executeQuery($conn, $stmt)
169 | {
170 | $txt = array();
171 | $crsr = odbc_exec($conn, $stmt);
172 |
173 | if ((version_compare(PHP_VERSION, '8.4.0', '<') && is_resource($crsr)) ||
174 | (version_compare(PHP_VERSION, '8.4.0', '>=') && $crsr instanceof \Odbc\Result)) {
175 | while (odbc_fetch_row($crsr)) {
176 | $row = odbc_result($crsr, 1);
177 |
178 | if (!$row) {
179 | break;
180 | }
181 |
182 | $txt[]= $row;
183 | }
184 | } else {
185 | $this->setError($conn);
186 | }
187 |
188 | return $txt;
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/ToolkitApi/toolkit.ini.zs5:
--------------------------------------------------------------------------------
1 | ; toolkit.ini for Zend/PHP Toolkit and Compatibility Wrapper (CW)
2 | ; with default values appropriate for Zend Server 5
3 |
4 | [system]
5 | ; set library where XTOOLKIT lives, most likely XMLSERVICE (testing) or ZENDSVR (production)
6 | XMLServiceLib = "ZENDSVR" ; production Zend Server 5.x
7 | ;XMLServiceLib = "ZENDSVR6" ; production Zend Server 6.x/7.x
8 | ;XMLServiceLib = "XMLSERVICE" ; for testing new XMLSERVICE packages
9 |
10 | ; Location of ZSXMLSRV "helper" service program. Overrides ToolkitServiceSet's ZSTOOLKITLIB constant
11 | HelperLib = "ZENDSVR" ; library of ZS "helper" service program. ZENDSVR or ZENDSVR6
12 |
13 | ; debug sets PHP toolkit's debug mode on or off (true/false).
14 | ; Default log file: /usr/local/zendsvr(6/7)/var/log/tkit_debug.log
15 | ; This log will grow large, so leave this false when you do not need to log everything.
16 | debug = false
17 | debugLogFile = "/usr/local/zendsvr/var/log/tkit_debug.log"
18 |
19 | ; Enable internal, low-level XMLSERVICE trace into table XMLSERVLOG/LOG
20 | ; (New in PHP tkit 1.3.1, requiring XMLSERVICE 1.7.1)
21 | ; default is false
22 | trace = false
23 |
24 | ; encoding (ISO-8859-1 is default. For some languages, such as Japanese, UTF-8 seems better.)
25 | encoding = "ISO-8859-1"
26 | ;encoding = "UTF-8"
27 |
28 | ; Advanced CCSID options. Use all three options together.
29 | ; Details under the heading "CCSID user override - xmlservice options (hex/before/after)":
30 | ; http://www.youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICECCSID
31 | ;ccsidBefore = "819/37"
32 | ;ccsidAfter = "37/819"
33 | ;useHex = true
34 |
35 | ; paseCcsid controls CCSID for type of functions such as WRKACTJOB ('system' command in PASE)
36 | ; Default is 819. Another practical value is 1208 (UTF-8).
37 | ;paseCcsid = 819
38 |
39 | ; Optionally provide submit options here
40 | ; Format: JOBDLIB/JOBD/JOBNAME. If not specified, will be ZENDSVR6/ZSVR_JOBD/XTOOLKIT
41 | ;sbmjob_params = "ZENDSVR/ZSVR_JOBD/XTOOLKIT"
42 | ; Or specify another sbmjob combination, such as QSYS/QSRVJOB/XTOOLKIT,
43 | ; if ZENDSVR library isn't present on the system or LPAR.
44 | ;sbmjob_params = "QSYS/QSRVJOB/XTOOLKIT"
45 |
46 | ; If you plan to connect to v5r4 IBM i systems from this toolkit installation, set v5r4=true.
47 | ; The toolkit will then optimize program calls for v5r4 (important when calling non-ILE programs on v5r4).
48 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('v5r4'=>true));
49 | ; The default is false.
50 | v5r4 = false
51 |
52 | ; Data Structure integrity
53 | ; Whether to retain the tree-like hierarchy of data structures (dataStructureIntegrity = true)
54 | ; or to ignore DSes, flattening out all data elements to a single level (dataStructureIntegrity = false)
55 | ; Starting in Zend Server 6, the default here is true.
56 | ; For backward compatibility with pre-1.4.0 behavior, change one or both to false.
57 | dataStructureIntegrity = false
58 | ; Array Integrity
59 | ; Allow true array parameters with better functionality.
60 | ; For backward compatibility with pre-1.4.0, set to false.
61 | arrayIntegrity = false
62 |
63 | ; CW only: stateless mode is default for i5_connect (though automatically overridden if private conns are used)
64 | stateless = true
65 |
66 | [transport]
67 | ; transport type allows configuration of transport from this INI.
68 | ;transportType = "ibm_db2" ; ibm_db2 is default. Other choices: "odbc", "http"
69 | ; for http transport only
70 | ;httpTransportUrl = "http://example.com/cgi-bin/xmlcgi.pgm"
71 | ; default plug size, which is the expected output size. 4K, 32K, 512K (default), 65K, 512K, 1M, 5M, 10M, 15M
72 | ; can also change in code with $conn->setOptions(array('plugSize' => '4K')); or desired size
73 | ;plugSize = "512K"
74 |
75 |
76 | [log]
77 | ; Both CW and regular toolkit: warnings and errors will be written to the logfile (CW and regular toolkit).
78 | logfile = "/usr/local/zendsvr/var/log/toolkit.log"
79 |
80 | ; CW only: If logCwConnect = true then CW connection events will be written to the logfile.
81 | ; This log will grow large, so set logCwConnects=false in production.
82 | ; Certain warnings and errors will be written regardless.
83 | logCwConnect = false
84 |
85 |
86 | ; CW only: map hosts from ip/host to database names
87 | [hosts]
88 | ; map ip/host names to database names (WRKDBRDIRE)
89 | ; because old toolkit used ip/host name; Zend's toolkit uses database name.
90 | ; Two common keys are set by default. In CW, specify 'localhost' as host name if running on local IBM i.
91 | localhost = "*LOCAL"
92 | 127.0.0.1 = "*LOCAL"
93 |
94 | ; examples of other mappings
95 | ;1.2.3.4 = DB1
96 | ;myhost = MAINDB
97 | ;example.com = LPARDB
98 |
99 |
100 |
101 | [testing]
102 | ; parse_only means do not run your program. Only parse the XML and return debug info. Useful for testing dim/dou/counters
103 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('parseOnly'=>true));
104 | ; The default is false.
105 | ;parse_only = false
106 | ; parse_debug_level determines the amount of parsing detail to be logged in debug log (1-9: 1=none, 9=all)
107 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('parseDebugLevel'=>1)); // any number 1-9
108 | ; The default is null.
109 | ;parse_debug_level = 1
110 |
111 | [cw]
112 | ; if want to close db connection on i5_close();
113 | fullDbClose = false
114 |
115 | ; CW Demo configuration (may be deprecated in a future release)
116 | [demo]
117 | demo_library=CWDEMO
118 |
119 | ; For CW demo script, optional settings: initlibl, ccsid, jobname, idle_timeout, transport_type
120 | ; These affect the demo script only.
121 | ; May be helpful to specify QGPL if not ordinarily present because it's required in liblist to enable spool file access (Qshell's catsplf command used by the CW).
122 | ;initlibl = "QGPL"
123 | ;ccsid = 37
124 | ;jobname = PHPJOBX
125 | ;idle_timeout = 30
126 | ;transport_type = "odbc" ; ibm_db2 is default. Other choice is "odbc"
127 |
128 | ; for demo, use a persistent connection (true or false)
129 | persistent = true
130 |
131 | ; for demo, whether to use a private connection (true or false)
132 | private = false
133 |
134 | ; for demo script, if specified private above, this is the conn# to use.
135 | ; A value of 0 means the toolkit should generate the number.
136 | ; Recommendation: use 0 the first time to allow the toolkit to generate a number,
137 | ; then edit the INI file to specify the generated number, then run demo again.
138 | ; Private connections are slow the first time, then fast afterard.
139 | private_num = 0
--------------------------------------------------------------------------------
/ToolkitApi/SshSupp.php:
--------------------------------------------------------------------------------
1 | conn, $this->getXmlserviceCliPath());
28 | if (!$ssh_stdio) {
29 | $this->setErrorCode("SSH2_EXEC");
30 | $this->setErrorMsg("error executing command over SSH");
31 | return false;
32 | }
33 | /* XXX */
34 | stream_set_blocking($ssh_stdio, true);
35 | $written = fwrite($ssh_stdio, $xmlIn);
36 | if ($written === false) {
37 | $this->setErrorCode("SSH2_FWRITE");
38 | $this->setErrorMsg("error writing to stdin");
39 | return false;
40 | }
41 | fflush($ssh_stdio);
42 | ssh2_send_eof($ssh_stdio);
43 | $xmlOut = stream_get_contents($ssh_stdio);
44 | return $xmlOut;
45 | }
46 |
47 | /**
48 | * @return string
49 | */
50 | public function getErrorCode()
51 | {
52 | return $this->last_errorcode;
53 | }
54 |
55 | /**
56 | * @return string
57 | */
58 | public function getErrorMsg()
59 | {
60 | return $this->last_errormsg;
61 | }
62 |
63 | /**
64 | * @param $errorCode
65 | */
66 | protected function setErrorCode($errorCode)
67 | {
68 | $this->last_errorcode = $errorCode;
69 | }
70 |
71 | /**
72 | * @param $errorMsg
73 | */
74 | protected function setErrorMsg($errorMsg)
75 | {
76 | $this->last_errormsg = $errorMsg;
77 | }
78 |
79 | /**
80 | * @param string $path
81 | */
82 | public function setXmlserviceCliPath($path)
83 | {
84 | $this->xmlserviceCliPath = $path;
85 | }
86 |
87 | /**
88 | * @return null
89 | */
90 | public function getXmlserviceCliPath()
91 | {
92 | return $this->xmlserviceCliPath;
93 | }
94 |
95 | private function checkCompat()
96 | {
97 | // Only post-1.2 versions of ssh2 have ssh2_send_eof
98 | if (!extension_loaded("ssh2")) {
99 | $this->setErrorCode("SSH2_NOT_LOADED");
100 | $this->setErrorMsg("the ssh2 extension isn't loaded");
101 | return false;
102 | }
103 | if (!function_exists("ssh2_send_eof")) {
104 | $this->setErrorCode("SSH2_NO_SEND_EOF");
105 | $this->setErrorMsg("the ssh2 extension is too old to support ssh2_send_eof, use 1.3 or newer");
106 | return false;
107 | }
108 | return true;
109 | }
110 |
111 | /**
112 | * @param resource $conn
113 | * @return SshSupp|bool
114 | */
115 | public function connectWithExistingConnection($conn)
116 | {
117 | if (!$this->checkCompat()) {
118 | return false;
119 | }
120 | if (!$conn || !is_resource($conn)) {
121 | $this->setErrorCode("SSH2_NOT_RESOURCE");
122 | $this->setErrorMsg("connection isn't a valid resource");
123 | return false;
124 | }
125 | $this->conn = $conn;
126 | return $this;
127 | }
128 |
129 | /**
130 | * @param string $server
131 | * @param $user
132 | * @param $password
133 | * @param array $options
134 | * @return SshSupp|bool
135 | */
136 | public function connect($server, $user, $password, $options = array())
137 | {
138 | if (!$this->checkCompat()) {
139 | return false;
140 | }
141 | // XXX: Set advanced methods here
142 | $port = array_key_exists("sshPort", $options) ? $options["sshPort"] : 22;
143 | $conn = ssh2_connect($server, $port);
144 | if (!$conn) {
145 | $this->setErrorCode("SSH2_CONNECT");
146 | $this->setErrorMsg("error connecting to SSH");
147 | return false;
148 | }
149 | // XXX: should probably be doing better than SHA1 here, but ssh2
150 | $remoteFP = ssh2_fingerprint($conn, SSH2_FINGERPRINT_SHA1 | SSH2_FINGERPRINT_HEX);
151 | $trustedFP = array_key_exists("sshFingerprint", $options) ? $options["sshFingerprint"] : false;
152 | if ($trustedFP !== false && $trustedFP !== $remoteFP) {
153 | $this->setErrorCode("SSH2_FINGERPRINT");
154 | $this->setErrorMsg("the fingerprint ($remoteFP) differs from the set fingerprint");
155 | ssh2_disconnect($conn);
156 | return false;
157 | }
158 | $authMethod = array_key_exists("sshMethod", $options) ? $options["sshMethod"] : "password";
159 | switch ($authMethod) {
160 | case "keyfile":
161 | $pub = $options["sshPublicKeyFile"];
162 | $priv = $options["sshPrivateKeyFile"];
163 | $passphrase = $options["sshPrivateKeyPassphrase"];
164 | if (!ssh2_auth_pubkey_file($conn, $user, $pub, $priv, $passphrase)) {
165 | $this->setErrorCode("SSH2_AUTH_KEYFILE");
166 | $this->setErrorMsg("error performing keyfile auth over SSH");
167 | ssh2_disconnect($conn);
168 | return false;
169 | }
170 | break;
171 | case "agent":
172 | if (!ssh2_auth_agent($conn, $user)) {
173 | $this->setErrorCode("SSH2_AUTH_AGENT");
174 | $this->setErrorMsg("error performing agent auth over SSH");
175 | ssh2_disconnect($conn);
176 | return false;
177 | }
178 | break;
179 | case "password":
180 | if (!ssh2_auth_password($conn, $user, $password)) {
181 | $this->setErrorCode("SSH2_AUTH_PASSWORD");
182 | $this->setErrorMsg("error performing password auth over SSH");
183 | ssh2_disconnect($conn);
184 | return false;
185 | }
186 | break;
187 | }
188 |
189 | $this->conn = $conn;
190 |
191 | return $this;
192 | }
193 |
194 | public function disconnect()
195 | {
196 | if (is_resource($this->conn)) {
197 | ssh2_disconnect($this->conn);
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/ToolkitApi/toolkit.ini.zs6:
--------------------------------------------------------------------------------
1 | ; toolkit.ini for Zend/PHP Toolkit and Compatibility Wrapper (CW)
2 | ; with default values appropriate for Zend Server 6/7
3 | ;comment
4 | [system]
5 | ; set library where XTOOLKIT lives, most likely XMLSERVICE (testing) or ZENDSVR (production)
6 | ;XMLServiceLib = "ZENDSVR" ; production Zend Server 5.x
7 | XMLServiceLib = "ZENDSVR6" ; production Zend Server 6.x/7.x
8 | ;XMLServiceLib = "XMLSERVICE" ; for testing new XMLSERVICE packages
9 |
10 | ; Location of ZSXMLSRV "helper" service program. Overrides ToolkitServiceSet's ZSTOOLKITLIB constant
11 | HelperLib = "ZENDSVR6" ; library of ZS "helper" service program. ZENDSVR or ZENDSVR6
12 |
13 | ; debug sets PHP toolkit's debug mode on or off (true/false).
14 | ; Default log file: /usr/local/zendsvr(6/7)/var/log/tkit_debug.log
15 | ; This log will grow large, so leave this false when you do not need to log everything.
16 | debug = false
17 | debugLogFile = "/usr/local/zendsvr6/var/log/tkit_debug.log"
18 |
19 | ; Enable internal, low-level XMLSERVICE trace into table XMLSERVLOG/LOG
20 | ; (New in PHP tkit 1.3.1, requiring XMLSERVICE 1.7.1)
21 | ; default is false
22 | trace = false
23 |
24 | ; encoding (ISO-8859-1 is default. For some languages, such as Japanese, UTF-8 seems better.)
25 | encoding = "ISO-8859-1"
26 | ;encoding = "UTF-8"
27 |
28 | ; Advanced CCSID options. Use all three options together.
29 | ; Details under the heading "CCSID user override - xmlservice options (hex/before/after)":
30 | ; http://www.youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICECCSID
31 | ;ccsidBefore = "819/37"
32 | ;ccsidAfter = "37/819"
33 | ;useHex = true
34 |
35 | ; paseCcsid controls CCSID for type of functions such as WRKACTJOB ('system' command in PASE)
36 | ; Default is 819. Another practical value is 1208 (UTF-8).
37 | ;paseCcsid = 819
38 |
39 | ; Optionally provide submit options here
40 | ; Format: JOBDLIB/JOBD/JOBNAME. If not specified, will be ZENDSVR6/ZSVR_JOBD/XTOOLKIT
41 | ;sbmjob_params = "ZENDSVR6/ZSVR_JOBD/XTOOLKIT"
42 | ; Or specify another sbmjob combination, such as QSYS/QSRVJOB/XTOOLKIT,
43 | ; if ZENDSVR6 library isn't present on the system or LPAR.
44 | ;sbmjob_params = "QSYS/QSRVJOB/XTOOLKIT"
45 |
46 | ; If you plan to connect to v5r4 IBM i systems from this toolkit installation, set v5r4=true.
47 | ; The toolkit will then optimize program calls for v5r4 (important when calling non-ILE programs on v5r4).
48 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('v5r4'=>true));
49 | ; The default is false.
50 | v5r4 = false
51 |
52 | ; Data Structure integrity
53 | ; Whether to retain the tree-like hierarchy of data structures (dataStructureIntegrity = true)
54 | ; or to ignore DSes, flattening out all data elements to a single level (dataStructureIntegrity = false)
55 | ; Starting in Zend Server 6, the default here is true.
56 | ; For backward compatibility with pre-1.4.0 behavior, change one or both to false.
57 | dataStructureIntegrity = true
58 | ; Array Integrity
59 | ; Allow true array parameters with better functionality.
60 | ; For backward compatibility with pre-1.4.0, set to false.
61 | arrayIntegrity = true
62 |
63 | ; CW only: stateless mode is default for i5_connect (though automatically overridden if private conns are used)
64 | stateless = true
65 |
66 | [transport]
67 | ; transport type allows configuration of transport from this INI.
68 | ;transportType = "ibm_db2" ; ibm_db2 is default. Other choices: "odbc", "http", "https"
69 | ; for http transport only
70 | ;httpTransportUrl = "https://example.com/cgi-bin/xmlcgi.pgm"
71 | ;sslCaFile = "/path/to/cert.pem"
72 | ;serverName = "example.com"
73 | ; default plug size, which is the expected output size. 4K, 32K, 512K (default), 65K, 512K, 1M, 5M, 10M, 15M
74 | ; can also change in code with $conn->setOptions(array('plugSize' => '4K')); or desired size
75 | ;plugSize = "512K"
76 |
77 |
78 | [log]
79 | ; Both CW and regular toolkit: warnings and errors will be written to the logfile (CW and regular toolkit).
80 | logfile = "/usr/local/zendsvr6/var/log/toolkit.log"
81 |
82 | ; CW only: If logCwConnect = true then CW connection events will be written to the logfile.
83 | ; This log will grow large, so set logCwConnects=false in production.
84 | ; Certain warnings and errors will be written regardless.
85 | logCwConnect = false
86 |
87 |
88 | ; CW only: map hosts from ip/host to database names
89 | [hosts]
90 | ; map ip/host names to database names (WRKDBRDIRE)
91 | ; because old toolkit used ip/host name; Zend's toolkit uses database name.
92 | ; Two common keys are set by default. In CW, specify 'localhost' as host name if running on local IBM i.
93 | localhost = "*LOCAL"
94 | 127.0.0.1 = "*LOCAL"
95 |
96 | ; examples of other mappings
97 | ;1.2.3.4 = DB1
98 | ;myhost = MAINDB
99 | ;example.com = LPARDB
100 |
101 |
102 |
103 | [testing]
104 | ; parse_only means do not run your program. Only parse the XML and return debug info. Useful for testing dim/dou/counters
105 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('parseOnly'=>true));
106 | ; The default is false.
107 | ;parse_only = false
108 | ; parse_debug_level determines the amount of parsing detail to be logged in debug log (1-9: 1=none, 9=all)
109 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('parseDebugLevel'=>1)); // any number 1-9
110 | ; The default is null.
111 | ;parse_debug_level = 1
112 |
113 | [cw]
114 | ; if want to close db connection on i5_close();
115 | fullDbClose = false
116 |
117 | ; CW Demo configuration (may be deprecated in a future release)
118 | [demo]
119 | demo_library=CWDEMO
120 |
121 | ; For CW demo script, optional settings: initlibl, ccsid, jobname, idle_timeout, transport_type
122 | ; These affect the demo script only.
123 | ; May be helpful to specify QGPL if not ordinarily present because it's required in liblist to enable spool file access (Qshell's catsplf command used by the CW).
124 | ;initlibl = "QGPL"
125 | ;ccsid = 37
126 | ;jobname = PHPJOBX
127 | ;idle_timeout = 30
128 | ;transport_type = "odbc" ; ibm_db2 is default. Other choice is "odbc"
129 |
130 | ; for demo, use a persistent connection (true or false)
131 | persistent = true
132 |
133 | ; for demo, whether to use a private connection (true or false)
134 | private = false
135 |
136 | ; for demo script, if specified private above, this is the conn# to use.
137 | ; A value of 0 means the toolkit should generate the number.
138 | ; Recommendation: use 0 the first time to allow the toolkit to generate a number,
139 | ; then edit the INI file to specify the generated number, then run demo again.
140 | ; Private connections are slow the first time, then fast afterard.
141 | private_num = 0
--------------------------------------------------------------------------------
/ToolkitApi/CW/ToolkitServiceCw.php:
--------------------------------------------------------------------------------
1 | conn))
35 | {
36 | self::$instance->disconnect();
37 | }
38 |
39 | // if we're forcing a new instance, or an instance hasn't been created yet, create one
40 | if ($forceNew || self::$instance == NULL) {
41 | $toolkitService = __CLASS__;
42 | self::$instance = new $toolkitService($databaseNameOrResource, $userOrI5NamingFlag, $password, $extensionPrefix, $isPersistent);
43 | }
44 |
45 | if (self::$instance) {
46 | // instance exists
47 | return self::$instance;
48 | } else {
49 | // some problem
50 | return false;
51 | }
52 | }
53 |
54 | /**
55 | * Return true if an instance of this object has already been created.
56 | * Return false if no instance has been instantiated.
57 | *
58 | * Same as the method in ToolkitApi\Toolkit.
59 | * Cwclasses has its own instance variable so we need this method here, too.
60 | *
61 | * Useful when users need to know if a "toolkit connection" has already been made.
62 | * Usage:
63 | * $isConnected = Toolkit::hasInstance();
64 | *
65 | * @return boolean
66 | */
67 | public static function hasInstance()
68 | {
69 | if (isset(self::$instance) && is_object(self::$instance)) {
70 | return true;
71 | } else {
72 | return false;
73 | }
74 | }
75 |
76 | /**
77 | * @param $num
78 | */
79 | public function setPrivateConnNum($num)
80 | {
81 | $this->_privateConnNum = $num;
82 | }
83 |
84 | /**
85 | * @return null
86 | */
87 | public function getPrivateConnNum()
88 | {
89 | return $this->_privateConnNum;
90 | }
91 |
92 | /**
93 | * establish whether the connection is new or not. Used by i5_get_property()
94 | *
95 | * @param bool $isNew
96 | */
97 | public function setIsNewConn($isNew = true)
98 | {
99 | $this->_isNewConn = $isNew;
100 | }
101 |
102 | /**
103 | * @return bool
104 | */
105 | public function isNewConn()
106 | {
107 | return $this->_isNewConn;
108 | }
109 |
110 | /**
111 | * when script ends, non-persistent connection should close
112 | */
113 | public function __destruct()
114 | {
115 | /* call to disconnect() function to down connection */
116 | $disconnect = false;
117 |
118 | // CW only: if connection is in a separate job and nonpersistent, end job (mimicking behavior of old toolkit)
119 | if (!$this->isStateless() && !$this->getIsPersistent()) {
120 | $disconnect = true;
121 | }
122 |
123 | if ($disconnect) {
124 | $this->disconnect();
125 | }
126 |
127 | // parent destruct clears the object
128 | // parent::__destruct();
129 |
130 | // need to clear extended cwclasses instance as well.
131 | if ($disconnect) {
132 | self::$instance = null;
133 | }
134 | }
135 |
136 | /**
137 | * Get the most recent system error code, if available.
138 | * TODO this may not work because CPFs are done at a class level (data areas etc.)
139 | */
140 | public function getCPFErr()
141 | {
142 | // TODO get from Verify_CPFError or the other one
143 | return $this->CPFErr;
144 | }
145 |
146 | /**
147 | * After calling a program or command, we can export output as variables.
148 | * This method creates an array that can later be extracted into variables.
149 | * param array $outputDesc Format of output params 'CODE'=>'CODEvar' where the value becomes a PHP var name
150 | * param array $outputValues Optional. Array of output values to export
151 | *
152 | * @param array $outputDesc
153 | * @param array $outputValues
154 | * @return boolean true on success, false on some error
155 | */
156 | public function setOutputVarsToExport(array $outputDesc, array $outputValues)
157 | {
158 | // for each piece of output, export it according to var name given in $outputDesc.
159 | if ($outputValues && is_array($outputValues) && count($outputValues)) {
160 | // initialize
161 | $this->_outputVarsToExport = array();
162 |
163 | foreach ($outputValues as $paramName=>$value) {
164 | if (isset($outputDesc[$paramName])) {
165 | $variableNameToExport = $outputDesc[$paramName];
166 | // create the global variable named by $ varName.
167 |
168 | $GLOBALS[$variableNameToExport] = $value;
169 |
170 | $this->_outputVarsToExport[$variableNameToExport] = $value;
171 | }
172 | }
173 | }
174 |
175 | return true;
176 | }
177 |
178 | /**
179 | * @return array
180 | */
181 | public function getOutputVarsToExport()
182 | {
183 | return $this->_outputVarsToExport;
184 | }
185 |
186 | /**
187 | * pass in array of job attributes => values to update in the current job.
188 | * returns true on success, false on failure (failure probably means lack of authority).
189 | *
190 | * @param array $attrs
191 | * @return bool
192 | */
193 | public function changeJob(array $attrs)
194 | {
195 | $cmdString = 'CHGJOB';
196 | $success = i5_command($cmdString, $attrs);
197 | return $success;
198 | }
199 | }
--------------------------------------------------------------------------------
/ToolkitApi/toolkit.ini:
--------------------------------------------------------------------------------
1 | ; toolkit.ini for Zend/PHP Toolkit and Compatibility Wrapper (CW)
2 | ; with default values appropriate for Zend Server 9
3 | ;comment
4 | [system]
5 | ; set library where XMLSERVICE objects live
6 | XMLServiceLib = "QXMLSERV" ; Library for XMLSERVICE shipped by IBM
7 | ;XMLServiceLib = "ZENDPHP7" ; production Zend Server 9.x
8 |
9 | ; Location of ZSXMLSRV "helper" service program. Overrides ToolkitServiceSet's ZSTOOLKITLIB constant
10 | HelperLib = "ZENDPHP7" ; library of ZS "helper" service program. ZENDSVR, ZENDSVR6, or ZENDPHP7
11 |
12 | ; debug sets PHP toolkit's debug mode on or off (true/false).
13 | ; Default log file: /usr/local/zendphp7/var/log/tkit_debug.log
14 | ; This log will grow large, so leave this false when you do not need to log everything.
15 | debug = false
16 | debugLogFile = "/usr/local/zendphp7/var/log/tkit_debug.log"
17 |
18 | ; Enable internal, low-level XMLSERVICE trace into table XMLSERVLOG/LOG
19 | ; (New in PHP tkit 1.3.1, requiring XMLSERVICE 1.7.1)
20 | ; default is false
21 | trace = false
22 |
23 | ; encoding (ISO-8859-1 is default. For some languages, such as Japanese, UTF-8 seems better.)
24 | encoding = "ISO-8859-1"
25 | ;encoding = "UTF-8"
26 |
27 | ; Advanced CCSID options. Use all three options together.
28 | ; Details under the heading "CCSID user override - xmlservice options (hex/before/after)":
29 | ; http://www.youngiprofessionals.com/wiki/index.php/XMLSERVICE/XMLSERVICECCSID
30 | ;ccsidBefore = "819/37"
31 | ;ccsidAfter = "37/819"
32 | ;useHex = true
33 |
34 | ; paseCcsid controls CCSID for type of functions such as WRKACTJOB ('system' command in PASE)
35 | ; Default is 819. Another practical value is 1208 (UTF-8).
36 | ;paseCcsid = 819
37 |
38 | ; Optionally provide submit options here
39 | ; Format: JOBDLIB/JOBD/JOBNAME. If not specified, will be ZENDSVR6/ZSVR_JOBD/XTOOLKIT
40 | ;sbmjob_params = "ZENDSVR6/ZSVR_JOBD/XTOOLKIT"
41 | ; Or specify another sbmjob combination, such as QSYS/QSRVJOB/XTOOLKIT,
42 | ; if ZENDSVR6 library isn't present on the system or LPAR.
43 | ;sbmjob_params = "QSYS/QSRVJOB/XTOOLKIT"
44 |
45 | ; If you plan to connect to v5r4 IBM i systems from this toolkit installation, set v5r4=true.
46 | ; The toolkit will then optimize program calls for v5r4 (important when calling non-ILE programs on v5r4).
47 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('v5r4'=>true));
48 | ; The default is false.
49 | v5r4 = false
50 |
51 | ; Data Structure integrity
52 | ; Whether to retain the tree-like hierarchy of data structures (dataStructureIntegrity = true)
53 | ; or to ignore DSes, flattening out all data elements to a single level (dataStructureIntegrity = false)
54 | ; Starting in Zend Server 6, the default here is true.
55 | ; For backward compatibility with pre-1.4.0 behavior, change one or both to false.
56 | dataStructureIntegrity = true
57 | ; Array Integrity
58 | ; Allow true array parameters with better functionality.
59 | ; For backward compatibility with pre-1.4.0, set to false.
60 | arrayIntegrity = true
61 |
62 | ; CW only: stateless mode is default for i5_connect (though automatically overridden if private conns are used)
63 | stateless = true
64 |
65 | [transport]
66 | ; transport type allows configuration of transport from this INI.
67 | ;transportType = "ibm_db2" ; ibm_db2 is default. Other choices: "odbc", "http", "https"
68 | ; for http transport only
69 | ;httpTransportUrl = "https://example.com/cgi-bin/xmlcgi.pgm"
70 | ;sslCaFile = "/path/to/cert.pem"
71 | ;serverName = "example.com"
72 | ; default plug size, which is the expected output size. 4K, 32K, 512K (default), 65K, 512K, 1M, 5M, 10M, 15M
73 | ; can also change in code with $conn->setOptions(array('plugSize' => '4K')); or desired size
74 | ;plugSize = "512K"
75 | ; Override the binary called in the local and SSH transports.
76 | ; Useful for shimming the binary, or running it elsewhere.
77 | ;xmlserviceCliPath = "/QOpenSys/pkgs/bin/xmlservice-cli"
78 |
79 |
80 | [log]
81 | ; Both CW and regular toolkit: warnings and errors will be written to the logfile (CW and regular toolkit).
82 | logfile = "/usr/local/zendphp7/var/log/toolkit.log"
83 |
84 | ; CW only: If logCwConnect = true then CW connection events will be written to the logfile.
85 | ; This log will grow large, so set logCwConnects=false in production.
86 | ; Certain warnings and errors will be written regardless.
87 | logCwConnect = false
88 |
89 |
90 | ; CW only: map hosts from ip/host to database names
91 | [hosts]
92 | ; map ip/host names to database names (WRKDBRDIRE)
93 | ; because old toolkit used ip/host name; Zend's toolkit uses database name.
94 | ; Two common keys are set by default. In CW, specify 'localhost' as host name if running on local IBM i.
95 | localhost = "*LOCAL"
96 | 127.0.0.1 = "*LOCAL"
97 |
98 | ; examples of other mappings
99 | ;1.2.3.4 = DB1
100 | ;myhost = MAINDB
101 | ;example.com = LPARDB
102 |
103 |
104 |
105 | [testing]
106 | ; parse_only means do not run your program. Only parse the XML and return debug info. Useful for testing dim/dou/counters
107 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('parseOnly'=>true));
108 | ; The default is false.
109 | ;parse_only = false
110 | ; parse_debug_level determines the amount of parsing detail to be logged in debug log (1-9: 1=none, 9=all)
111 | ; This setting is equivalent to the following PHP code: $conn->setToolkitServiceParams(array('parseDebugLevel'=>1)); // any number 1-9
112 | ; The default is null.
113 | ;parse_debug_level = 1
114 |
115 | [cw]
116 | ; if want to close db connection on i5_close();
117 | fullDbClose = false
118 |
119 | ; CW Demo configuration (may be deprecated in a future release)
120 | [demo]
121 | demo_library=CWDEMO
122 |
123 | ; For CW demo script, optional settings: initlibl, ccsid, jobname, idle_timeout, transport_type
124 | ; These affect the demo script only.
125 | ; May be helpful to specify QGPL if not ordinarily present because it's required in liblist to enable spool file access (Qshell's catsplf command used by the CW).
126 | ;initlibl = "QGPL"
127 | ;ccsid = 37
128 | ;jobname = PHPJOBX
129 | ;idle_timeout = 30
130 | ;transport_type = "odbc" ; ibm_db2 is default. Other choice is "odbc"
131 |
132 | ; for demo, use a persistent connection (true or false)
133 | persistent = true
134 |
135 | ; for demo, whether to use a private connection (true or false)
136 | private = false
137 |
138 | ; for demo script, if specified private above, this is the conn# to use.
139 | ; A value of 0 means the toolkit should generate the number.
140 | ; Recommendation: use 0 the first time to allow the toolkit to generate a number,
141 | ; then edit the INI file to specify the generated number, then run demo again.
142 | ; Private connections are slow the first time, then fast afterard.
143 | private_num = 0
144 |
--------------------------------------------------------------------------------
/ToolkitApi/SpooledFiles.php:
--------------------------------------------------------------------------------
1 | ToolkitSrvObj = $ToolkitSrvObj;
26 |
27 | // @todo do not assume a specific plug size.
28 | $this->ToolkitSrvObj->setOptions(array('plugSize'=>'1M'));
29 |
30 | $this->TMPFName = $this->ToolkitSrvObj->generate_name();
31 |
32 | //do not use a QTEMP as temporary library. [not sure why not--A.S.]
33 | if ($UserLib != NULL && strcmp($UserLib, "QGPL")) {
34 | $this->TmpLib = $UserLib;
35 | }
36 |
37 | return $this;
38 | } else {
39 | return false;
40 | }
41 | }
42 |
43 | /**
44 | *
45 | */
46 | public function __destruct()
47 | {
48 | // empty
49 | }
50 |
51 | /**
52 | * @return mixed
53 | */
54 | public function getError()
55 | {
56 | return $this->ErrMessage;
57 | }
58 |
59 | /**
60 | * @param string $UserName
61 | * @return array|bool|null
62 | * @throws \Exception
63 | */
64 | public function GetSPLList($UserName = "*CURRENT")
65 | {
66 | $list = NULL;
67 | $this->clearError();
68 |
69 | $this->TmpUserSpace = new TmpUserSpace($this->ToolkitSrvObj, DFTLIB);
70 |
71 | $UsFullName = $this->TmpUserSpace->getUSFullName();
72 | $params[] = $this->ToolkitSrvObj->AddParameterChar('in', 20, "User Space Name", 'userspacename', $UsFullName);
73 | $params[] = $this->ToolkitSrvObj->AddParameterChar('in', 10, "User Name", 'username', $UserName);
74 | //$retval[]= $this->ToolkitSrvObj->AddReturnParameter('10i0', 'retval', 0);
75 | $retval[]= $this->ToolkitSrvObj->AddParameterInt32('out', 'retval', 'retval', 0);
76 |
77 | $this->ToolkitSrvObj->PgmCall(ZSTOOLKITPGM, $this->ToolkitSrvObj->getOption('HelperLib'),
78 | $params, $retval,
79 | array ('func' => 'LISTSPLF' ) );
80 |
81 | if (!$this->ToolkitSrvObj->isError()) {
82 | sleep(1);
83 | $readlen = $this->TmpUserSpace->RetrieveUserSpaceSize();
84 | $SpoolFilesList = $this->TmpUserSpace->ReadUserSpace(1, $readlen);
85 | $this->TmpUserSpace->DeleteUserSpace();
86 |
87 | if (trim($SpoolFilesList) > 0)
88 | {
89 | $list = $this->buildSpoolList(str_split($SpoolFilesList, $this->SPOOLFILELIST_SIZE));
90 | return $list;
91 | } else {
92 | $this->setError("No spooled files found for ".$UserName);
93 | return NULL; //no spollfiles!
94 | }
95 | } else {
96 | $this->setError($this->ToolkitSrvObj->getLastError());
97 | }
98 |
99 | unset($this->TmpUserSpace);
100 | return false;
101 | }
102 |
103 | /**
104 | * @param $SpoolInfListArr
105 | * @return array|null
106 | */
107 | private function buildSpoolList($SpoolInfListArr )
108 | {
109 | $list= NULL;
110 |
111 | foreach($SpoolInfListArr as $tmparr)
112 | {
113 | $list[] = array('Number' => substr($tmparr, 0, 4),
114 | 'Name' => substr($tmparr, 4, 10),
115 | 'JobNumber' => substr($tmparr, 14, 6),
116 | 'JobName' => substr($tmparr, 20,10),
117 | 'JobUser' => substr($tmparr, 30, 10),
118 | 'UserData' => substr($tmparr, 40, 10),
119 | 'QueueName' => substr($tmparr, 50, 20),
120 | 'TotalPages' => substr($tmparr, 70, 5),
121 | 'Status' => substr($tmparr, 75, 10),
122 | 'DateOpen'=> substr($tmparr, 85, 7),
123 | 'TimeOpen'=>substr($tmparr, 92, 6)
124 | );
125 | }
126 |
127 | return $list;
128 | }
129 |
130 | /**
131 | * multi user using!
132 | *
133 | * @param $SplfName
134 | * @param $SplfNbr
135 | * @param $JobNmbr
136 | * @param $JobName
137 | * @param $JobUser
138 | * @param string $TMPFName
139 | * @return mixed|string
140 | */
141 | public function GetSPLF($SplfName , $SplfNbr, $JobNmbr, $JobName, $JobUser, $TMPFName='')
142 | {
143 | $this->clearError();
144 | if ($TMPFName != '') {
145 | $this->TMPFName = $TMPFName;
146 | }
147 |
148 | // @todo under the flag for current Object???
149 | $crtf = "CRTDUPOBJ OBJ(ZSF255) FROMLIB(" . $this->ToolkitSrvObj->getOption('HelperLib') . ") OBJTYPE(*FILE) TOLIB($this->TmpLib) NEWOBJ($this->TMPFName)";
150 | $this->ToolkitSrvObj->ClCommandWithCpf($crtf); // was ClCommand
151 |
152 | // clear the temp file
153 | $clrpfm = "CLRPFM $this->TmpLib/$this->TMPFName";
154 | $this->ToolkitSrvObj->ClCommandWithCpf($clrpfm); // these all were CLCommand but we need CPFs.
155 |
156 | // copy spooled file to temp file
157 | $cmd = sprintf ("CPYSPLF FILE(%s) TOFILE($this->TmpLib/$this->TMPFName) JOB(%s/%s/%s) SPLNBR(%s)",
158 | $SplfName, trim($JobNmbr), trim($JobUser), trim($JobName), $SplfNbr);
159 |
160 | $this->ToolkitSrvObj->ClCommandWithCpf($cmd);
161 | sleep(1);
162 | // read the data from temp file
163 | $Txt = $this->ReadSPLFData();
164 |
165 | // delete temp file
166 | $dltf = "DLTF FILE($this->TmpLib/$this->TMPFName)";
167 | $this->ToolkitSrvObj->ClCommandWithCpf($dltf);
168 |
169 | return $Txt;
170 | }
171 |
172 | /**
173 | * @return mixed|string
174 | * @throws \Exception
175 | */
176 | private function ReadSPLFData()
177 | {
178 | $Txt='';
179 | $schemaSep = $this->ToolkitSrvObj->getOption('schemaSep'); // . or /
180 | $stmt = "SELECT ZSF255 FROM {$this->TmpLib}{$schemaSep}{$this->TMPFName} FOR FETCH ONLY";
181 |
182 | try {
183 | $Txt = $this->ToolkitSrvObj->executeQuery($stmt);
184 | } catch(Exception $e) {
185 | $this->setError("ReadSPLFData() error:" . $e->getMessage());
186 | }
187 |
188 | return $Txt;
189 | }
190 |
191 | /**
192 | * @param $msg
193 | */
194 | private function setError($msg)
195 | {
196 | $this->ErrMessage = $msg;
197 | }
198 |
199 | /**
200 | *
201 | */
202 | private function clearError()
203 | {
204 | $this->ErrMessage = '';
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/ToolkitApi/Db2supp.php:
--------------------------------------------------------------------------------
1 | setErrorCode('08001');
34 | $this->setErrorMsg('Authorization failure on distributed database connection attempt. SQLCODE=-30082');
35 |
36 | return false;
37 | }
38 |
39 | if ($options) {
40 | $driver_options = array();
41 |
42 | // Test for existence of driver options
43 | if (array_key_exists('driver_options', $options)) {
44 | $driver_options = $options['driver_options'] ?: array();
45 | }
46 |
47 | if ((isset($options['persistent'])) && $options['persistent']) {
48 | $conn = db2_pconnect($database, $user, $password, $driver_options);
49 | } else {
50 | $conn = db2_connect($database, $user, $password, $driver_options);
51 | }
52 |
53 | if (is_resource($conn)) {
54 | return $conn;
55 | }
56 | }
57 |
58 | $this->setErrorCode(db2_conn_error());
59 | $this->setErrorMsg(db2_conn_errormsg());
60 |
61 | return false;
62 | }
63 |
64 | /**
65 | * @param $conn
66 | */
67 | public function disconnect($conn)
68 | {
69 | if (is_resource($conn)) {
70 | db2_close($conn);
71 | }
72 | }
73 |
74 | /**
75 | * disconnect, truly close, a persistent connection.
76 | *
77 | * NOTE: Only available on i5/OS
78 | *
79 | * @param $conn
80 | */
81 | public function disconnectPersistent($conn)
82 | {
83 | if (is_resource($conn)) {
84 | db2_pclose($conn);
85 | }
86 | }
87 |
88 | /**
89 | * @return string
90 | */
91 | public function getErrorCode()
92 | {
93 | return $this->last_errorcode;
94 | }
95 |
96 | /**
97 | * @return string
98 | */
99 | public function getErrorMsg()
100 | {
101 | return $this->last_errormsg;
102 | }
103 |
104 | /**
105 | * set error code and message based on last db2 prepare or execute error.
106 | *
107 | * @todo: consider using GET DIAGNOSTICS for even more message text:
108 | * http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Frzala%2Frzalafinder.htm
109 | *
110 | * @param null $stmt
111 | */
112 | protected function setStmtError($stmt = null)
113 | {
114 | if ($stmt) {
115 | $this->setErrorCode(db2_stmt_error($stmt));
116 | $this->setErrorMsg(db2_stmt_errormsg($stmt));
117 | } else {
118 | $this->setErrorCode(db2_stmt_error());
119 | $this->setErrorMsg(db2_stmt_errormsg());
120 | }
121 | }
122 |
123 | /**
124 | * @param $errorCode
125 | */
126 | protected function setErrorCode($errorCode)
127 | {
128 | $this->last_errorcode = $errorCode;
129 | }
130 |
131 | /**
132 | * @param $errorMsg
133 | */
134 | protected function setErrorMsg($errorMsg)
135 | {
136 | $this->last_errormsg = $errorMsg;
137 | }
138 |
139 | /**
140 | * this function used for special stored procedure call only
141 | *
142 | * @param $conn
143 | * @param $sql
144 | * @return bool
145 | */
146 | public function execXMLStoredProcedure($conn, $sql, $bindArray)
147 | {
148 |
149 | $internalKey = $bindArray['internalKey'];
150 | $controlKey = $bindArray['controlKey'];
151 | $inputXml = $bindArray['inputXml'];
152 | $outputXml = $bindArray['outputXml'];
153 |
154 | // @todo see why error doesn't properly bubble up to top level.
155 | $crsr = @db2_prepare($conn, $sql);
156 | if (!$crsr) {
157 | $this->setStmtError();
158 | return false;
159 | }
160 |
161 | // stored procedure takes four parameters. Each 'name' will be bound to a real PHP variable
162 | $params = array(
163 | array('position' => 1, 'name' => "internalKey", 'inout' => DB2_PARAM_IN),
164 | array('position' => 2, 'name' => "controlKey", 'inout' => DB2_PARAM_IN),
165 | array('position' => 3, 'name' => "inputXml", 'inout' => DB2_PARAM_IN),
166 | array('position' => 4, 'name' => "outputXml", 'inout' => DB2_PARAM_OUT),
167 | );
168 |
169 | // bind the four parameters
170 | foreach ($params as $param) {
171 | $ret = db2_bind_param ($crsr, $param['position'], $param['name'], $param['inout']);
172 | if (!$ret) {
173 | // unable to bind a param. Set error and exit
174 | $this->setStmtError($crsr);
175 | return false;
176 | }
177 | }
178 |
179 | $ret = @db2_execute($crsr);
180 | if (!$ret) {
181 | // execution of XMLSERVICE stored procedure failed.
182 | $this->setStmtError($crsr);
183 | return false;
184 | }
185 |
186 | return $outputXml;
187 | }
188 |
189 | /**
190 | * returns a first column from sql stmt result set
191 | *
192 | * used in one place: iToolkitService's ReadSPLFData().
193 | *
194 | * @todo eliminate this method if possible.
195 | *
196 | * @param $conn
197 | * @param $sql
198 | * @throws \Exception
199 | * @return array
200 | */
201 | public function executeQuery($conn, $sql)
202 | {
203 | $txt = array();
204 | $stmt = db2_exec($conn, $sql, array('cursor' => DB2_SCROLLABLE));
205 | if (is_resource($stmt)) {
206 | while (db2_fetch_row($stmt)) {
207 | $column = db2_result($stmt, 0);
208 | $txt[] = $column;
209 | }
210 | } else {
211 | $this->setStmtError();
212 | Throw new \Exception("Failure executing SQL: ($sql) " . db2_stmt_errormsg(), db2_stmt_error());
213 | }
214 |
215 | return $txt;
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/tests/ToolkitApiTest/ToolkitTest.php:
--------------------------------------------------------------------------------
1 | toolkit = new Toolkit('*LOCAL', '0', 'testPwd', 'http', false);
41 | }
42 |
43 | public function testCanAddSigned8ByteIntegerParameter(): void
44 | {
45 | $parameter = $this->toolkit->AddParameterInt8('both', 'test comment', 'testVar', 8);
46 |
47 | $this->assertTrue($parameter instanceof Int8Param);
48 | }
49 |
50 | public function testCanAddSigned16ByteIntegerParameter(): void
51 | {
52 | $parameter = $this->toolkit->AddParameterInt16('both', 'test comment', 'testVar', 10);
53 |
54 | $this->assertTrue($parameter instanceof Int16Param);
55 | }
56 |
57 | public function testCanAddSigned32ByteIntegerParameter(): void
58 | {
59 | $parameter = $this->toolkit->AddParameterInt32('both', 'test comment', 'testVar', 100);
60 |
61 | $this->assertTrue($parameter instanceof Int32Param);
62 | }
63 |
64 | public function testCanAddSigned64ByteIntegerParameter(): void
65 | {
66 | $parameter = $this->toolkit->AddParameterInt64('both', 'test comment', 'testVar', 1000);
67 |
68 | $this->assertTrue($parameter instanceof Int64Param);
69 | }
70 |
71 | public function testCanAddUnsigned8ByteIntegerParameter(): void
72 | {
73 | $parameter = $this->toolkit->AddParameterUInt8('both', 'test comment', 'testVar', 8);
74 |
75 | $this->assertTrue($parameter instanceof UInt8Param);
76 | }
77 |
78 | public function testCanAddUnsigned16ByteIntegerParameter(): void
79 | {
80 | $parameter = $this->toolkit->AddParameterUInt16('both', 'test comment', 'testVar', 8);
81 |
82 | $this->assertTrue($parameter instanceof UInt16Param);
83 | }
84 |
85 | public function testCanAddUnsigned32ByteIntegerParameter(): void
86 | {
87 | $parameter = $this->toolkit->AddParameterUInt32('both', 'test comment', 'testVar', 8);
88 |
89 | $this->assertTrue($parameter instanceof UInt32Param);
90 | }
91 |
92 | public function testCanAddUnsigned64ByteIntegerParameter(): void
93 | {
94 | $parameter = $this->toolkit->AddParameterUInt64('both', 'test comment', 'testVar', 8);
95 |
96 | $this->assertTrue($parameter instanceof UInt64Param);
97 | }
98 |
99 | public function testCanAddCharacterParameter(): void
100 | {
101 | $parameter = $this->toolkit->AddParameterChar('both', 10, 'CODE', 'CODE', 'code');
102 |
103 | $this->assertTrue($parameter instanceof CharParam);
104 | }
105 |
106 | public function testCanAddFloatParameter(): void
107 | {
108 | $parameter = $this->toolkit->AddParameterFloat('both', 'test comment', 'varName', 'false');
109 |
110 | $this->assertTrue($parameter instanceof FloatParam);
111 | }
112 |
113 | public function testCanAddRealParameter(): void
114 | {
115 | $parameter = $this->toolkit->AddParameterReal('both', 'test comment', 'varName', 'testValue');
116 |
117 | $this->assertTrue($parameter instanceof RealParam);
118 | }
119 |
120 | public function testCanAddPackedDecimalParameter(): void
121 | {
122 | $parameter = $this->toolkit->AddParameterPackDec('both', 7,4, 'INDEC1', 'var3', '001.0001');
123 |
124 | $this->assertTrue($parameter instanceof PackedDecParam);
125 | }
126 |
127 | public function testCanAddZonedParameter(): void
128 | {
129 | $parameter = $this->toolkit->AddParameterZoned('both', 12, 2, 'Check amount', 'amount', '2000.25');
130 |
131 | $this->assertTrue($parameter instanceof ZonedParam);
132 | }
133 |
134 | public function testCanAddParameterHole(): void
135 | {
136 | $parameter = $this->toolkit->AddParameterHole(12, 'hole');
137 |
138 | $this->assertTrue($parameter instanceof HoleParam);
139 | }
140 |
141 | public function testCanAddBinaryParameter(): void
142 | {
143 | $parameter = $this->toolkit->AddParameterBin('both', 20, 'UncodeSample', 'p1', 'test');
144 |
145 | $this->assertTrue($parameter instanceof BinParam);
146 | }
147 |
148 | public function testCanAddParameterSize(): void
149 | {
150 | $size = $this->toolkit->AddParameterSize('test comment', 'varName', 3);
151 |
152 | $this->assertTrue($size instanceof SizeParam);
153 | }
154 |
155 | public function testCanAddParameterSizePack(): void
156 | {
157 | $parameter = $this->toolkit->AddParameterSizePack('test comment', 'varName', 4);
158 |
159 | $this->assertTrue($parameter instanceof SizePackParam);
160 | }
161 |
162 | public function testCanSetPersistent(): void
163 | {
164 | $isPersistent = false;
165 |
166 | $this->toolkit->setIsPersistent($isPersistent);
167 |
168 | $this->assertEquals($isPersistent, $this->toolkit->getIsPersistent());
169 | }
170 |
171 | public function testCanReturnScriptAbsolutePath(): void
172 | {
173 | $path = Toolkit::classPath();
174 |
175 | $this->assertEquals($path, $this->toolkit->classPath());
176 | }
177 |
178 | public function testCanGetPhpOperatingSystem(): void
179 | {
180 | $os = php_uname('s');
181 |
182 | $this->assertEquals($os, $this->toolkit->getPhpOperatingSystem());
183 | }
184 |
185 | public function testCanTellIfPhpIsRunningOnIbmI(): void
186 | {
187 | $isRunningOnIbmI = (php_uname('s') === 'OS400');
188 |
189 | $this->assertEquals($isRunningOnIbmI, $this->toolkit->isPhpRunningOnIbmI());
190 | }
191 |
192 | public function testDatabaseNameOrResourceIsNotBoolean(): void
193 | {
194 | $resource = false;
195 | $this->expectException(Exception::class);
196 | new Toolkit($resource);
197 | }
198 |
199 | public function testDatabaseNameOrResourceIsNotFloat(): void
200 | {
201 | $resource = 1.81;
202 | $this->expectException(Exception::class);
203 | new Toolkit($resource);
204 | }
205 |
206 | public function testDatabaseNameOrResourceIsNotObject(): void
207 | {
208 | $resource = new DataArea();
209 | $this->expectException(Exception::class);
210 | new Toolkit($resource);
211 | }
212 |
213 | public function testDatabaseNameOrResourceIsNotInteger(): void
214 | {
215 | $resource = 12;
216 | $this->expectException(Exception::class);
217 | new Toolkit($resource);
218 | }
219 |
220 | public function testDatabaseNameOrResourceIsNotArray(): void
221 | {
222 | $resource = array(1, 2, 3);
223 | $this->expectException(Exception::class);
224 | new Toolkit($resource);
225 | }
226 |
227 | public function testDatabaseNameOrResourceIsNotNull(): void
228 | {
229 | $resource = null;
230 | $this->expectException(Exception::class);
231 | new Toolkit($resource);
232 | }
233 |
234 | }
235 |
--------------------------------------------------------------------------------
/ToolkitApi/JobLogs.php:
--------------------------------------------------------------------------------
1 | ToolkitSrvObj = $ToolkitSrvObj;
26 |
27 | // @todo do not assume a specific plug size.
28 | $this->ToolkitSrvObj->setOptions(array('plugSize'=>'1M'));
29 |
30 | //do not use a QTEMP as temporary library.
31 | if (strcmp($tmpUSLib, "QGPL")) {
32 | $this->TmpLib = $tmpUSLib;
33 | }
34 |
35 | return $this;
36 | } else {
37 | return false;
38 | }
39 | }
40 |
41 | /**
42 | * @param $newSize
43 | */
44 | public function setTemp_US_Size($newSize) {
45 | if ($newSize > 128000) {
46 | $this->Temp_US_Size = $newSize;
47 | }
48 | }
49 |
50 | /**
51 | * @param null $user
52 | * @param string $jobstatus
53 | * @return array|bool
54 | * @throws \Exception
55 | */
56 | public function JobList($user = NULL, $jobstatus = "*ACTIVE")
57 | {
58 | if ($user != NULL) {
59 | $ForUser = sprintf("%-10s", $user);
60 | } else {
61 | $ForUser = "*CURRENT ";
62 | }
63 |
64 | $JobStatus = sprintf("%-10s", $jobstatus);
65 | $this->TmpUserSpace = new TmpUserSpace($this->ToolkitSrvObj, $this->TmpLib, $this->Temp_US_Size);
66 | $FullUSName = $this->TmpUserSpace->getUSFullName();
67 |
68 | $params[]=$this->ToolkitSrvObj->AddParameterChar('input', 20, 'USER SPACE NAME', 'userspacename', $FullUSName);
69 | $params[]=$this->ToolkitSrvObj->AddParameterChar('input', 10, 'USER NAME', 'username', $ForUser);
70 | $params[]=$this->ToolkitSrvObj->AddParameterChar('input', 10, 'Job status', 'jobstatus', $JobStatus);
71 |
72 | $ret = $this->ToolkitSrvObj->PgmCall(ZSTOOLKITPGM, $this->ToolkitSrvObj->getOption('HelperLib'), $params, NULL, array ('func' => 'JOBLIST'));
73 | sleep(1);
74 | $JobList = $this->TmpUserSpace->ReadUserSpace(1, $this->TmpUserSpace->RetrieveUserSpaceSize());
75 |
76 | $this->TmpUserSpace->DeleteUserSpace();
77 | unset($this->TmpUserSpace);
78 | if (trim($JobList)!='') {
79 | return (str_split($JobList, $this->JOBLIST_RECORD_SIZE));
80 | } else {
81 | return false;
82 | }
83 | }
84 |
85 | /**
86 | * @param $JobListString
87 | * @return array
88 | */
89 | public function createJobListArray($JobListString)
90 | {
91 | $JobList = array();
92 | if (is_array($JobListString)) {
93 | $i = 0;
94 | foreach ($JobListString as $element)
95 | {
96 | $el = str_split($element, 10);
97 | $JobList[$i]['JOBNAME'] =$el[0];
98 | $JobList[$i]['JOBUSER'] =$el[1];
99 | $JobList[$i]['JOBNUMBER']=$el[2];
100 | $JobList[$i]['JOBSTATUS']=$el[3];
101 | $JobList[$i]['JOBSUBS'] =(isset($el[4])) ? $el[4] : ''; // avoid undefined offset
102 | $JobList[$i]['ACTJOBSTATUS']=(isset($el[5])) ? $el[5] : ''; // avoid undefined offset
103 | $i++;
104 | }
105 | }
106 |
107 | return $JobList;
108 | }
109 |
110 | /**
111 | * it seems that all three parms must be entered; it's for a specific job.
112 | *
113 | * @param $JobName
114 | * @param $JobUser
115 | * @param $JobNumber
116 | * @param string $direction
117 | * @return array|bool
118 | * @throws \Exception
119 | */
120 | public function JobLog($JobName, $JobUser, $JobNumber, $direction = 'L')
121 | {
122 | if ($JobName=='' ||$JobUser=='' || $JobNumber == '') {
123 | return false;
124 | }
125 |
126 | $this->TmpUserSpace = new TmpUserSpace($this->ToolkitSrvObj, $this->TmpLib);
127 | $FullUSName = $this->TmpUserSpace->getUSFullName();
128 | $InputArray[]=$this->ToolkitSrvObj->AddParameterChar('input', 20, 'USER SPACE NAME', 'userspacename', $FullUSName);
129 | $InputArray[]=$this->ToolkitSrvObj->AddParameterChar('input', 10, 'JOB NAME', 'jobname', $JobName);
130 | $InputArray[]=$this->ToolkitSrvObj->AddParameterChar('input', 10, 'USER NAME', 'username', $JobUser);
131 | //L from the last log message to the first one
132 | //from the first message to the last one
133 | $dir = 'L';
134 |
135 | if (strtoupper($direction) == "N") {
136 | $dir = $direction;
137 | }
138 |
139 | $InputArray[]=$this->ToolkitSrvObj->AddParameterChar('input', 6, 'Job Number', 'jobnumber', $JobNumber);
140 | //From the Last - "L"
141 | $InputArray[]=$this->ToolkitSrvObj->AddParameterChar('input', 1, 'Direction', 'direction', $dir);
142 | $ret_code ='0';
143 | $InputArray[]=$this->ToolkitSrvObj->AddParameterChar('both', 1, 'retcode', 'retcode', $ret_code);
144 |
145 | $OutputArray = $this->ToolkitSrvObj->PgmCall(ZSTOOLKITPGM, $this->ToolkitSrvObj->getOption('HelperLib'), $InputArray, NULL, array('func'=>'JOBLOGINFO'));
146 | if (isset($OutputArray['io_param']['retcode'])) {
147 | //may be authorization problem
148 | if ($OutputArray['io_param']['retcode'] == '1') {
149 | //No data created in US.
150 | return false;
151 | }
152 | }
153 |
154 | sleep(1);
155 |
156 | $JobLogRows = $this->TmpUserSpace->ReadUserSpace(1, $this->TmpUserSpace->RetrieveUserSpaceSize());
157 | $this->TmpUserSpace->DeleteUserSpace();
158 | unset ($this->TmpUserSpace);
159 |
160 | if (trim($JobLogRows) != '') {
161 | $logArray = str_split($JobLogRows, $this->JOBLOG_RECORD_SIZE);
162 | return $logArray;
163 | } else {
164 | return false;
165 | }
166 | }
167 |
168 | /**
169 | *
170 | * @todo currentJobLog. retrieve log for it in either direction.
171 | *
172 | * @param $JobName
173 | * @param $JobUser
174 | * @param $JobNumber
175 | * @return array|bool
176 | */
177 | public function GetJobInfo($JobName, $JobUser, $JobNumber)
178 | {
179 | /**
180 | * used format:JOBI0200
181 | */
182 | if ($JobName=='' ||$JobUser=='' || $JobNumber == '') {
183 | return false; //nothing to show
184 | }
185 |
186 | $reciever =" ";
187 | $jobName26 = sprintf("%-10s%-10s%-6s", $JobName, $JobUser, $JobNumber);
188 |
189 | // changed
190 | $receiverSize = 1000; // 200
191 | $params[] = Toolkit::AddParameterChar('input', 26, "QualifiedJobName", 'JobName', trim($jobName26));
192 | $params[] = Toolkit::AddParameterChar('both', $receiverSize, "reciever", 'reciever', $reciever);
193 | $ret = $this->ToolkitSrvObj->PgmCall(ZSTOOLKITPGM, $this->ToolkitSrvObj->getOption('HelperLib'), $params, NULL, array('func'=>'GETJOBINFO'));
194 | if ($ret && trim($ret['io_param']['reciever'])!='') {
195 | return ($this->parseJobInfString($ret['io_param']['reciever']));
196 | }
197 |
198 | return false;
199 | }
200 |
201 | /**
202 | * @param $jobinfo
203 | * @return array
204 | */
205 | private function parseJobInfString($jobinfo)
206 | {
207 | return array(
208 | 'JobName'=>substr($jobinfo, 0, 10),
209 | 'JobUser'=>substr($jobinfo, 10, 10),
210 | 'JobNumber'=>substr($jobinfo, 20, 6),
211 | 'JobStatus'=>substr($jobinfo, 26, 10),
212 | 'ActJobStat'=>substr($jobinfo, 36, 4),
213 | 'JobType'=>substr($jobinfo, 40, 1),
214 | 'JobRunPriority'=>substr($jobinfo, 41, 5),
215 | 'JobTimeSlice'=>substr($jobinfo, 46, 5),
216 | 'PoolId'=>substr($jobinfo, 51, 5),
217 | 'Functionname'=>substr($jobinfo, 56, 10),
218 | );
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/ToolkitApi/httpsupp.php:
--------------------------------------------------------------------------------
1 | XMLCGI.PGM--->XMLSERVICE
15 | * Apache conf (httpd.conf):
16 | * ScriptAlias /cgi-bin/ /QSYS.LIB/XMLSERVICE.LIB/
17 | *
18 | *
19 | * AllowOverride None
20 | * order allow,deny
21 | * allow from all
22 | * SetHandler cgi-script
23 | * Options +ExecCGI
24 | *
25 | *
26 | * @todo define common transport class/interface extended/implemented by all transports. They have much in common.
27 | *
28 | * @package ToolkitApi
29 | */
30 | class httpsupp
31 | {
32 | protected $last_errorcode;
33 | protected $last_errormsg;
34 | protected $_ipc;
35 | protected $_ctl;
36 | protected $_url;
37 | protected $_db;
38 | protected $_user;
39 | protected $_pw;
40 | protected $_debug;
41 | //ssl variables
42 | protected $_sslcafile;
43 | protected $_servername;
44 |
45 | /**
46 | * @param string $ipc route to XMLSERVICE job (/tmp/xmlibmdb2)
47 | * @param string $ctl XMLSERVICE control (*sbmjob)
48 | * @param string $url URL to xmlcgi.pgm (example: http://ibmi/cgi-bin/xmlcgi.pgm )
49 | * @param string $debug *in|*out|*all (*in - dump XML input (call)) (*out - dump XML output (return)) (*all - dump XML input/output)
50 | */
51 | public function __construct($ipc='/tmp/xmldb2', $ctl='*sbmjob', $url='http://example.com/cgi-bin/xmlcgi.pgm', $debug='*none', $sslcafile=null, $servername=null )
52 | {
53 | $this->setIpc($ipc);
54 | $this->setCtl($ctl);
55 | $this->setUrl($url);
56 | $this->setSSLCAFile($sslcafile);
57 | $this->setServerName($servername);
58 | $this->_debug = $debug;
59 | }
60 |
61 | /**
62 | * @param $xmlIn
63 | * @param $outSize
64 | * @return string
65 | */
66 | public function send($xmlIn, $outSize)
67 | {
68 | $clobIn = $xmlIn;
69 | $clobOut = $outSize;
70 | $postdata = http_build_query(
71 | array(
72 | 'db2' => $this->getDb(),
73 | 'uid' => $this->getUser(),
74 | 'pwd' => $this->getPw(),
75 | 'ipc' => $this->getIpc(),
76 | 'ctl' => $this->getCtl(),
77 | 'xmlin' => $clobIn,
78 | 'xmlout' => $clobOut // size expected XML output
79 | )
80 | );
81 |
82 | $opts = array(
83 | 'http' =>
84 | array(
85 | 'method' => 'POST',
86 | 'header' => 'Content-type: application/x-www-form-urlencoded\r\n'.
87 | 'Content-Length: ' . strlen($postdata) . '\r\n',
88 | 'content' => $postdata
89 | )
90 | );
91 |
92 | if (substr($this->getUrl(), 0, 8) == "https://")
93 | {
94 | //If this the URL is HTTPS, then Add SSL to options to support a
95 | //secure connection.
96 | //Explanation of Options: http://phpsecurity.readthedocs.org/en/latest/Transport-Layer-Security-%28HTTPS-SSL-and-TLS%29.html
97 | $opts['ssl'] = array(
98 | 'verify_peer' => true, //Require verification of SSL certificate used.
99 | 'cafile' => $this->getSSLCAFile(), //__DIR__ . '/cacert.pem' //Location of Certificate Authority file on local filesystem which should be used with the verify_peer context option to authenticate the identity of the remote peer. PEM or CRT file. You can use this file: http://curl.haxx.se/ca/cacert.pem
100 | 'verify_depth' => 5, // Abort if the certificate chain is too deep.
101 | 'CN_match' => $this->getServerName(), //EX: secure.example.com
102 | 'disable_compression' => true,
103 | 'SNI_enabled' => true,
104 | 'ciphers' => 'ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4');
105 | }
106 |
107 | $context = stream_context_create($opts);
108 | // execute (call IBM i)
109 | $linkall = $this->getUrl();
110 |
111 | if (!$linkall) {
112 | die('HTTP transport URL was not set');
113 | }
114 |
115 | $clobOut = file_get_contents($linkall, false, $context);
116 | $clobOut = $this->driverJunkAway($clobOut);
117 |
118 | if ($this->_debug == '*all' || $this->_debug == '*in') {
119 | echo "IN->".$clobIn;
120 | }
121 |
122 | if ($this->_debug == '*all' || $this->_debug == '*out') {
123 | echo "OUT->".$clobOut;
124 | }
125 |
126 | return $clobOut;
127 | }
128 |
129 | /**
130 | * @return string
131 | */
132 | public function getErrorCode()
133 | {
134 | return $this->last_errorcode;
135 | }
136 |
137 | /**
138 | * @return string
139 | */
140 | public function getErrorMsg()
141 | {
142 | return $this->last_errormsg;
143 | }
144 |
145 | /**
146 | * @param $errorCode
147 | */
148 | protected function setErrorCode($errorCode)
149 | {
150 | $this->last_errorcode = $errorCode;
151 | }
152 |
153 | /**
154 | * @param $errorMsg
155 | */
156 | protected function setErrorMsg($errorMsg)
157 | {
158 | $this->last_errormsg = $errorMsg;
159 | }
160 |
161 | /**
162 | * @param $ipc
163 | */
164 | public function setIpc($ipc)
165 | {
166 | $this->_ipc = $ipc;
167 | }
168 |
169 | /**
170 | * @return null
171 | */
172 | public function getIpc()
173 | {
174 | return $this->_ipc;
175 | }
176 |
177 | /**
178 | * @param string $ctl
179 | */
180 | public function setCtl($ctl = '')
181 | {
182 | $this->_ctl = $ctl;
183 | }
184 |
185 | /**
186 | * @return null
187 | */
188 | public function getCtl()
189 | {
190 | return $this->_ctl;
191 | }
192 |
193 | /**
194 | * @param string $url\
195 | */
196 | public function setUrl($url = '')
197 | {
198 | $this->_url = $url;
199 | }
200 |
201 | /**
202 | * @return null
203 | */
204 | public function getUrl()
205 | {
206 | return $this->_url;
207 | }
208 |
209 | /**
210 | * @param null $sslcafile
211 | * @throws \Exception
212 | */
213 | public function setSSLCAFile($sslcafile = null)
214 | {
215 | if(substr($this->getUrl(), 0, 8) == "https://" && $sslcafile==null)
216 | {
217 | throw new \Exception('No SSL CA File specified. Must pass in CA File to use https url');
218 | }
219 | $this->_sslcafile = $sslcafile;
220 | }
221 |
222 | /**
223 | * @return null
224 | */
225 | public function getSSLCAFile()
226 | {
227 | return $this->_sslcafile;
228 | }
229 |
230 | /**
231 | * @param string $servername\
232 | */
233 | public function setServerName($servername = null)
234 | {
235 | if($servername==null && isset($_SERVER['SERVER_NAME']))
236 | {
237 | $servername=$_SERVER['SERVER_NAME'];
238 | }
239 | $this->_servername = $servername;
240 | }
241 |
242 | public function getServerName()
243 | {
244 | return $this->_servername;
245 | }
246 |
247 | /**
248 | *
249 | * @todo shared transport method
250 | *
251 | * @param $xml
252 | * @return string
253 | */
254 | public function driverJunkAway($xml)
255 | {
256 | // trim blanks
257 | $clobOut = trim($xml);
258 | if (!$clobOut) return $clobOut;
259 |
260 | // result set has extra data (junk)
261 | $fixme = '';
262 | $pos = strpos($clobOut,$fixme);
263 |
264 | if ($pos > -1) {
265 | $clobOut = substr($clobOut,0,$pos+strlen($fixme));
266 | } else { // maybe error/performance report
267 | $fixme = '';
268 | $pos = strpos($clobOut,$fixme);
269 |
270 | if ($pos > -1) {
271 | $clobOut = substr($clobOut,0,$pos+strlen($fixme));
272 | }
273 | }
274 |
275 | return $clobOut;
276 | }
277 |
278 | /**
279 | * @param string $db
280 | * @param $user
281 | * @param $pw
282 | * @return $this
283 | */
284 | public function http_connect($db, $user, $pw)
285 | {
286 | // accommodate ('', '', '') style of connection
287 | if(!$db) {
288 | $db = '*LOCAL';
289 | }
290 |
291 | $this->_db = $db;
292 | $this->_user = $user;
293 | $this->_pw = $pw;
294 |
295 | return $this;
296 | }
297 |
298 | /**
299 | * @param string $database
300 | * @param $user
301 | * @param $password
302 | * @return httpsupp
303 | */
304 | public function connect($database, $user, $password)
305 | {
306 | // accommodate ('', '', '') style of connection
307 | if(!$database) {
308 | $database = '*LOCAL';
309 | }
310 |
311 | return $this->http_connect($database, $user, $password);
312 |
313 | }
314 |
315 | /**
316 | * @return null
317 | */
318 | protected function getUser()
319 | {
320 | return $this->_user;
321 | }
322 |
323 | /**
324 | * @return null
325 | */
326 | protected function getPw()
327 | {
328 | return $this->_pw;
329 | }
330 |
331 | /**
332 | * @return null
333 | */
334 | protected function getDb()
335 | {
336 | return $this->_db;
337 | }
338 | }
339 |
--------------------------------------------------------------------------------
/ToolkitApi/DataArea.php:
--------------------------------------------------------------------------------
1 | ToolkitSrvObj = $ToolkitSrvObj;
23 | return $this;
24 | } else {
25 | return false;
26 | }
27 | }
28 |
29 | /**
30 | * for *char data area. According to create other data area types
31 | * use CL command
32 | *
33 | * @param string $DataAreaName
34 | * @param string $DataAreaLib *CURLIB is correct, the default with CRTDTAARA.
35 | * @param int $size
36 | * @return bool
37 | * @throws \Exception
38 | */
39 | public function createDataArea($DataAreaName = '', $DataAreaLib = "*CURLIB", $size = 2000)
40 | {
41 | if ($DataAreaName !='' && $this->DataAreaName == NULL) { /*was not set before*/
42 | $this->setDataAreaName($DataAreaName , $DataAreaLib);
43 | }
44 |
45 | if ($size > 2000 || $size <= 0) {
46 | $dataAreaLen = 2000;
47 | } else {
48 | $dataAreaLen = $size;
49 | }
50 |
51 | $cmd = sprintf("QSYS/CRTDTAARA DTAARA(%s/%s) TYPE(*CHAR) LEN($dataAreaLen)",
52 | ($DataAreaLib != '' ? $DataAreaLib : $this->DataAreaLib),
53 | ($DataAreaName !='' ? $DataAreaName : $this->DataAreaName));
54 |
55 | // @todo get CPF code
56 | if (!$this->ToolkitSrvObj->CLCommand($cmd)) {
57 | $this->ErrMessage = "Create Data Area failed." . $this->ToolkitSrvObj->getLastError();
58 | throw new \Exception($this->ErrMessage);
59 | }
60 |
61 | return true;
62 | }
63 |
64 | /**
65 | * @return string
66 | */
67 | private function getAPIDataAreaName()
68 | {
69 | return (sprintf("%-10s%-10s", $this->DataAreaName, $this->DataAreaLib));
70 | }
71 |
72 | /**
73 | * @return null|string
74 | */
75 | protected function getQualifiedDataAreaName() {
76 | // return dtaara name in lib/dtaara format.
77 | if ($this->DataAreaLib) {
78 | return "{$this->DataAreaLib}/{$this->DataAreaName}";
79 | } else {
80 | // no library (e.g. *LDA dtaara). Return only dtaara name.
81 | return $this->DataAreaName;
82 | }
83 | }
84 |
85 | /**
86 | * *LIBL to read/write data area. *CURLIB to create.
87 | *
88 | * @param $dataAreaName
89 | * @param string $dataAreaLib
90 | * @throws \Exception
91 | */
92 | public function setDataAreaName($dataAreaName, $dataAreaLib = "*LIBL")
93 | {
94 | /**
95 | * special values:
96 | * LDA Local data area
97 | * GDA Group data area
98 | * PDA Program initialization parameter data area
99 | */
100 | $dataAreaName = trim(strtoupper($dataAreaName));
101 |
102 | if ($dataAreaName == '') {
103 | throw new \Exception("Data Area name parameter should be defined ");
104 | }
105 |
106 | // no library allowed for these special values.
107 | if (in_array($dataAreaName, array('*LDA', '*GDA', '*PDA'))) {
108 | $dataAreaLib = '';
109 | }
110 |
111 | $this->DataAreaName = $dataAreaName;
112 | $this->DataAreaLib = $dataAreaLib;
113 | }
114 |
115 | /**
116 | * @param int $fromPosition
117 | * @param string $dataLen
118 | * @return bool
119 | */
120 | public function readDataArea($fromPosition = 1 , $dataLen = '*ALL')
121 | {
122 | if (!$this->ToolkitSrvObj instanceof Toolkit)
123 | return false;
124 |
125 | $Err = ' ';
126 | $value = '';
127 | if ($fromPosition == 0) {
128 | $fromPosition = 1;
129 | }
130 |
131 | $maxValueSize = 2000; // largest allowed data area size
132 |
133 | $adjustedStartRequested = $fromPosition;
134 | $adjustedLengthRequested = $dataLen;
135 |
136 | // if data len is *ALL, position and length receive special values..
137 | if (strtoupper($dataLen) == '*ALL') { // either numeric or *ALL
138 | $adjustedStartRequested = -1; // *ALL;
139 | $adjustedLengthRequested = $maxValueSize;
140 | }
141 |
142 | $toolkit = $this->ToolkitSrvObj;
143 |
144 | /**
145 | * Retrieve Data Area (QWCRDTAA) API
146 | * http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Fapis%2Fqwcrdtaa.htm
147 | *
148 | * Required Parameter Group:
149 | * 1 Receiver variable Output Char(*)
150 | * 2 Length of receiver variable Input Binary(4) Max length is 2000
151 | * 3 Qualified data area name Input Char(20)
152 | * 4 Starting position Input Binary(4)
153 | * 5 Length of data Input Binary(4)
154 | * 6 Error code I/O Char(*)
155 | *
156 | *
157 | * format of receiver variable
158 | * 0 0 BINARY(4) Bytes available (The length of all data available to return. All available data is returned if enough space is provided.)
159 | * 4 4 BINARY(4) Bytes returned (The length of all data actually returned)
160 | * 8 8 CHAR(10) Type of value returned (*CHAR, *DEC, *LGL)
161 | * 18 12 CHAR(10) Library name (blank if *LDA et al.)
162 | * 28 1C BINARY(4) Length of value returned
163 | * 32 20 BINARY(4) Number of decimal positions
164 | * 36 24 CHAR(*) Value (contents of data area)
165 | */
166 |
167 | // @todo allow data structure in data area, if packed/binary allowed.
168 |
169 | $receiverVar = array();
170 | $receiverVar[] = $toolkit->AddParameterInt32('out', 'Bytes available: length of all data available to return', 'bytesAvail', $maxValueSize);
171 | $receiverVar[] = $toolkit->AddParameterInt32('out', 'Length of all data returned, limited by size of receiver', 'bytesReturned', 0);
172 | $receiverVar[] = $toolkit->AddParameterChar('out', '10', 'Type of value returned (*CHAR, *DEC, *LGL)', 'Type', '');
173 | $receiverVar[] = $toolkit->AddParameterChar('out', '10', 'Library where data area was found', 'Library', '');
174 | $receiverVar[] = $toolkit->AddParameterInt32('out', 'Length of value returned', 'lengthReturned', 0);
175 | $receiverVar[] = $toolkit->AddParameterInt32('out', 'Number of decimal positions', 'decimalPositions', 0);
176 | $receiverVar[] = $toolkit->AddParameterChar('out', $maxValueSize, 'Value returned', 'value', ''); // set length to $maxValueSize to be safe
177 |
178 | $receiverLength = $maxValueSize + 36; // 4 4-byte integers + 2 10-byte character strings = 36
179 |
180 | // "NAME LIB " no slash. Left-aligned.
181 | $twentyCharQualifiedName = $this->getAPIDataAreaName();
182 |
183 | $toolkitParams = array();
184 | $toolkitParams [] = $toolkit->AddDataStruct($receiverVar, 'receiver');
185 | $toolkitParams [] = $toolkit->AddParameterInt32('in', 'Length of receiver variable', 'receiverLen', $receiverLength);
186 | $toolkitParams [] = $toolkit->AddParameterChar('in', 20, 'Data area name', 'DtaaraName', $twentyCharQualifiedName);
187 | // Starting position: The first byte of the data area to be retrieved. A value of 1 will identify the first character in the data area. The maximum value allowed for the starting position is 2000. A value of -1 will return all the characters in the data area.
188 | $toolkitParams [] = $toolkit->AddParameterInt32('in', 'Starting position requested', 'fromPosition', $adjustedStartRequested);
189 | $toolkitParams [] = $toolkit->AddParameterInt32('in', 'Data length requested', 'dataLength', $adjustedLengthRequested);
190 | $toolkitParams [] = $toolkit->AddErrorDataStructZeroBytes(); // so errors bubble up to joblog
191 |
192 | // we're using a data structure here so integrity must be on
193 | // @todo pass as option on the program call
194 | $dsIntegrity = $toolkit->getOption('dataStructureIntegrity'); // save original value
195 | $toolkit->setOptions(array('dataStructureIntegrity'=>true));
196 |
197 | $retPgmArr = $toolkit->PgmCall('QWCRDTAA', '', $toolkitParams);
198 |
199 | $toolkit->setOptions(array('dataStructureIntegrity'=>$dsIntegrity)); // restore original value
200 |
201 | // check for any errors
202 | if ($toolkit->getErrorCode()) {
203 | // an error
204 | return false;
205 | } else {
206 | // extricate the data from the receiver variable ds wrapper
207 | $value = $retPgmArr['io_param']['receiver']['value'];
208 | }
209 |
210 | return ($value) ? $value : false;
211 | }
212 |
213 | /**
214 | * @param $msg
215 | */
216 | private function setError($msg){
217 | $this->ErrMessage = $msg;
218 | }
219 |
220 | /**
221 | * @return mixed
222 | */
223 | public function getError() {
224 | return $this->ErrMessage;
225 | }
226 |
227 | /**
228 | * @param $value
229 | * @param int $fromPosition
230 | * @param int $dataLen
231 | * @throws \Exception
232 | */
233 | public function writeDataArea($value, $fromPosition = 0, $dataLen = 0)
234 | {
235 | $substring = ''; // init
236 | if ($fromPosition > 0) {
237 | $substring = sprintf("(%d %d)", $fromPosition, $dataLen);
238 | }
239 |
240 | // @todo use API instead. Handle numeric and character data., *CHAR and *DEC as well.
241 | // and/or quote the string. Needs to be case-sensitive and handle numeric input.
242 | $cmd = sprintf("CHGDTAARA DTAARA(%s $substring) VALUE($value)",
243 | $this->getQualifiedDataAreaName());
244 |
245 | if (!$this->ToolkitSrvObj->CLCommand($cmd)) {
246 | $this->ErrMessage = "Write into Data Area failed." . $this->ToolkitSrvObj->getLastError();
247 | throw new \Exception($this->ErrMessage);
248 | }
249 | }
250 |
251 | /**
252 | * requires explicit library
253 | *
254 | * @param string $DataAreaName
255 | * @param string $DataAreaLib
256 | * @throws \Exception
257 | */
258 | public function deleteDataArea($DataAreaName = '', $DataAreaLib = '')
259 | {
260 | $cmd = sprintf("QSYS/DLTDTAARA DTAARA(%s/%s)",
261 | ($DataAreaLib != '' ? $DataAreaLib : $this->DataAreaLib),
262 | ($DataAreaName != NULL ? $DataAreaName : $this->DataAreaName));
263 |
264 | if (!$this->ToolkitSrvObj->CLCommand($cmd)) {
265 | $this->ErrMessage = "Delete Data Area failed." . $this->ToolkitSrvObj->getLastError();
266 | throw new \Exception($this->ErrMessage);
267 | }
268 | }
269 | }
270 |
--------------------------------------------------------------------------------
/ToolkitApi/DataQueue.php:
--------------------------------------------------------------------------------
1 | Toolkit = $ToolkitSrvObj ;
24 | return $this;
25 | }
26 |
27 | return false;
28 | }
29 |
30 | /**
31 | * @return mixed
32 | */
33 | public function getError()
34 | {
35 | return $this->ErrMessage;
36 | }
37 |
38 | /**
39 | * @param $DataQName
40 | * @param $DataQLib
41 | * @param int $MaxLength
42 | * @param string $Sequence
43 | * @param int $KeyLength
44 | * @param string $Authority
45 | * @param int $QSizeMaxNumEntries
46 | * @param int $QSizeInitNumEntries
47 | * @return bool
48 | * @throws \Exception
49 | */
50 | public function CreateDataQ($DataQName, $DataQLib,
51 | $MaxLength=128,
52 | $Sequence ='*FIFO', $KeyLength=0,
53 | $Authority = '*LIBCRTAUT',
54 | $QSizeMaxNumEntries=32999, $QSizeInitNumEntries = 16)
55 | {
56 | $this->DataQueueName = $DataQName;
57 | $this->DataQueueLib = $DataQLib;
58 |
59 | if (strcmp(strtoupper($Sequence), '*KEYED') == 0||
60 | strcmp(strtoupper($Sequence), '*FIFO')== 0 ||
61 | strcmp(strtoupper($Sequence), '*LIFO')== 0) {
62 | $DataQType = $Sequence;
63 | } else {
64 | return $this->SetError("Invalid Data Queue type parameter");
65 | }
66 |
67 | $KeyedSetting = '';
68 |
69 | if (strcmp(strtoupper($Sequence), '*KEYED') == 0) {
70 | $DQKeylen = min($KeyLength, 256 );
71 | $KeyedSetting = "KEYLEN($DQKeylen)";
72 | }
73 |
74 | // @todo validation: if $KeyLength supplied, sequence must be *KEYED.
75 |
76 | if (is_integer($QSizeMaxNumEntries)) {
77 | $MaxQSize = $QSizeMaxNumEntries;
78 | } else {
79 | if (strcmp($QSizeMaxNumEntries, '*MAX16MB') == 0 || strcmp($QSizeMaxNumEntries, '*MAX2GB')== 0) {
80 | $MaxQSize = (string) $QSizeMaxNumEntries;
81 | }
82 | }
83 |
84 | if ($QSizeInitNumEntries > 0) {
85 | $InitEntryies = $QSizeInitNumEntries;
86 | }
87 |
88 | $AdditionalSetting = sprintf("$KeyedSetting SENDERID(*YES) SIZE(%s %d)", $MaxQSize, $InitEntryies);
89 |
90 | ($MaxLength > 64512) ? $MaxLen = 64512: $MaxLen = $MaxLength;
91 |
92 | $cmd = sprintf("QSYS/CRTDTAQ DTAQ(%s/%s) MAXLEN(%s) SEQ(%s) %s AUT(%s)",
93 | $this->DataQueueLib,$this->DataQueueName,
94 | $MaxLen, $DataQType, $AdditionalSetting, $Authority);
95 |
96 | if (!$this->Toolkit->CLCommand($cmd)) {
97 | $this->ErrMessage = "Create Data Queue failed.". $this->Toolkit->getLastError();
98 | throw new \Exception($this->ErrMessage);
99 | }
100 | return true;
101 | }
102 |
103 | /**
104 | * @param string $DataQName
105 | * @param string $DataQLib
106 | * @return bool
107 | * @throws \Exception
108 | */
109 | public function DeleteDQ($DataQName ='', $DataQLib = '')
110 | {
111 | $cmd = sprintf("QSYS/DLTDTAQ DTAQ(%s/%s)",
112 | ($DataQLib != '' ? $DataQLib : $this->DataQueueLib),
113 | ($DataQName != NULL ? $DataQName : $this->DataQueueName));
114 |
115 | if (!$this->Toolkit->CLCommand($cmd)) {
116 | $this->ErrMessage = "Delete Data Queue failed.". $this->Toolkit->getLastError();
117 | throw new \Exception($this->ErrMessage);
118 | }
119 |
120 | return true;
121 | }
122 |
123 | /**
124 | * Correct spelling with this alias
125 | *
126 | * @param $WaitTime
127 | * @param string $KeyOrder
128 | * @param int $KeyLength
129 | * @param string $KeyData
130 | * @param string $WithRemoveMsg
131 | * @return bool
132 | */
133 | public function receiveDataQueue($WaitTime, $KeyOrder = '', $KeyLength = 0, $KeyData = '', $WithRemoveMsg = 'N')
134 | {
135 | // call misspelled one
136 | return $this->receieveDataQueue($WaitTime, $KeyOrder, $KeyLength, $KeyData, $WithRemoveMsg);
137 | }
138 |
139 | /**
140 | * @param $WaitTime
141 | * @param string $KeyOrder
142 | * @param int $KeyLength
143 | * @param string $KeyData
144 | * @param string $WithRemoveMsg
145 | * @return bool
146 | */
147 | public function receieveDataQueue($WaitTime, $KeyOrder = '', $KeyLength = 0, $KeyData = '', $WithRemoveMsg = 'N')
148 | {
149 | // uses QRCVDTAQ API
150 | // http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Fapis%2Fqrcvdtaq.htm
151 |
152 | $params [] = $this->Toolkit->AddParameterChar('in', 10, 'dqname', 'dqname', $this->DataQueueName);
153 | $params [] = $this->Toolkit->AddParameterChar('in', 10, 'dqlib', 'dqlib', $this->DataQueueLib);
154 |
155 | // @todo do not hard-code data size. Use system of labels as allowed by XMLSERVICE (as done in CW's i5_dtaq_receive).
156 | $DataLen = 300;
157 | $Data = ' ';
158 |
159 | $params [] = $this->Toolkit->AddParameterPackDec('out', 5, 0, 'datalen', 'datalen', $DataLen); // @todo this is output only so no need to specify a value
160 | $params [] = $this->Toolkit->AddParameterChar('out', (int) $DataLen, 'datavalue', 'datavalue', $Data); // @todo this is output only so no need to specify a value.
161 |
162 | // Wait time: < 0 waits forever. 0 process immed. > 0 is number of seconds to wait.
163 | $params [] = $this->Toolkit->AddParameterPackDec('in', 5, 0, 'waittime', 'waittime', $WaitTime);
164 |
165 | if (!$KeyLength) {
166 | // 0, make order, length and data also zero or blank, so thatthey'll be ignored by API. Must send them, though.
167 |
168 | // if an unkeyed queue, API still expects to receive key info,
169 | // but it must be blank and zero.
170 | $KeyOrder = ''; // e.g. EQ, other operators, or blank
171 | $KeyLength = 0;
172 | $KeyData = '';
173 | }
174 |
175 | $params [] = $this->Toolkit->AddParameterChar('in', 2, 'keydataorder', 'keydataorder', $KeyOrder);
176 | $params [] = $this->Toolkit->AddParameterPackDec('in', 3, 0, 'keydatalen', 'keydatalen', $KeyLength);
177 | $params [] = $this->Toolkit->AddParameterChar('both', (int) $KeyLength, 'keydata', 'keydata', $KeyData);
178 |
179 | $params [] = $this->Toolkit->AddParameterPackDec('in', 3, 0, 'senderinflen', 'senderinflen', 44);
180 | // Sender info may contain packed data, so don't receive it till we can put it in a data structure.
181 | // @todo use a data structure to receive sender info as defined in QRCVDTAQ spec.
182 | $params [] = $this->Toolkit->AddParameterHole(44, 'senderinf');
183 |
184 | // whether to remove message from data queue
185 | if ($WithRemoveMsg == 'N') {
186 | $Remove= '*NO ';
187 | } else {
188 | $Remove= '*YES ';
189 | }
190 |
191 | $params[] = $this->Toolkit->AddParameterChar('in', 10, 'remove', 'remove', $Remove);
192 | // @todo note from API manual: If this parameter is not specified, the entire message will be copied into the receiver variable.
193 | $params[] = $this->Toolkit->AddParameterPackDec('in', 5, 0, 'size of data receiver', 'receiverSize', $DataLen);
194 |
195 | $params[] = $this->Toolkit->AddErrorDataStructZeroBytes(); // so errors bubble up to joblog
196 |
197 | $retPgmArr = $this->Toolkit->PgmCall('QRCVDTAQ', 'QSYS', $params);
198 | if (isset($retPgmArr['io_param'])) {
199 | $DQData = $retPgmArr['io_param'];
200 |
201 | if ($DQData['datalen']> 0) {
202 | return $DQData;
203 | }
204 | }
205 |
206 | return false;
207 | }
208 |
209 | /**
210 | * @param $DataQName
211 | * @param $DataQLib
212 | */
213 | public function SetDataQName($DataQName, $DataQLib)
214 | {
215 | $this->DataQueueName = $DataQName;
216 | $this->DataQueueLib = $DataQLib;
217 | }
218 |
219 | /**
220 | * @param $DataLen
221 | * @param $Data
222 | * @param int $KeyLength
223 | * @param string $KeyData
224 | * @return array|bool
225 | */
226 | public function SendDataQueue($DataLen, $Data, $KeyLength=0, $KeyData='')
227 | {
228 | // QSNDDTAQ API:
229 | // http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Fapis%2Fqsnddtaq.htm
230 |
231 | $params[] = $this->Toolkit->AddParameterChar('in', 10, 'dqname', 'dqname', $this->DataQueueName);
232 | $params[] = $this->Toolkit->AddParameterChar('in', 10, 'dqlib', 'dqlib',$this->DataQueueLib);
233 |
234 | $params[] = $this->Toolkit->AddParameterPackDec('in', 5, 0, 'datalen', 'datalen', $DataLen, null);
235 | $params[] = $this->Toolkit->AddParameterChar('in', $DataLen, 'datavalue','datavalue', $Data);
236 | if ($KeyLength > 0 ) {
237 | $params[] = $this->Toolkit->AddParameterPackDec('in', 3, 0, 'keydatalen', 'keydatalen', $KeyLength, null);
238 | $params[] = $this->Toolkit->AddParameterChar('in', $KeyLength, 'keydata', 'keydata', $KeyData);
239 | }
240 |
241 | $ret = $this->Toolkit->PgmCall('QSNDDTAQ', 'QSYS', $params);
242 |
243 | return $ret;
244 | }
245 |
246 | /**
247 | * @param string $KeyOrder
248 | * @param int $KeyLength
249 | * @param string $KeyData
250 | * @return bool
251 | */
252 | public function ClearDQ($KeyOrder= '', $KeyLength=0, $KeyData='')
253 | {
254 | //QCLRDTAQ
255 | $params[]=$this->Toolkit->AddParameterChar('in', 10, 'dqname', 'dqname', $this->DataQueueName);
256 | $params[]=$this->Toolkit->AddParameterChar('in', 10, 'dqlib', 'dqlib', $this->DataQueueLib);
257 | if ($KeyLength > 0) {
258 | $params[] = $this->Toolkit->AddParameterChar('in', 2, 'keydataorder', 'keydataorder', $KeyOrder);
259 | $params[] = $this->Toolkit->AddParameterPackDec('in', 3, 0, 'keydatalen', 'keydatalen', $KeyLength);
260 | $params[] = $this->Toolkit->AddParameterChar('in', ((int)$KeyLength), 'keydata', 'keydata', $KeyData);
261 | //$params[] = array('ds'=>$this->Toolkit->GenerateErrorParameter());
262 | $ds =$this->Toolkit->GenerateErrorParameter();
263 | $params[] = Toolkit::AddDataStruct($ds);
264 | }
265 |
266 | $retArr = $this->Toolkit->PgmCall('QCLRDTAQ', 'QSYS', $params);
267 |
268 | if (isset($retArr['exceptId']) && strcmp ($retArr['exceptId'], '0000000')) {
269 | $this->CPFErr = $retArr['exceptId'];
270 | $this->ErrMessage ="Clear Data Queue failed. Error: $this->CPFErr";
271 | return false;
272 | }
273 |
274 | return true;
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/ToolkitApi/CW/DataDescriptionPcml.php:
--------------------------------------------------------------------------------
1 | I5_TYPE_CHAR,
14 | 'packed' => I5_TYPE_PACKED,
15 | // 4 byte float
16 | 'float' => I5_TYPE_FLOAT,
17 | // data structure
18 | 'struct' => I5_TYPE_STRUCT,
19 | // omit INT from type map because we'll need program logic to determine if short or regular int.
20 | 'zoned' => I5_TYPE_ZONED,
21 | // TODO not sure if byte really maps to binary. No one knows what BYTE really does
22 | 'byte' => I5_TYPE_BYTE,
23 | );
24 |
25 | // PCML usage mapping
26 | protected $_pcmlInoutMap = array('input' => I5_IN,
27 | 'output' => I5_OUT,
28 | 'inputoutput' => I5_INOUT,
29 | // inherit means inherit from parent element, and if no parent element, do INOUT.
30 | // TODO implement "inherit" more precisely, checking parent element's usage.
31 | 'inherit' => I5_INOUT,
32 | );
33 |
34 | // maintain an array of pcml structures
35 | protected $_pcmlStructs = array();
36 |
37 | /**
38 | * Constructor takes a PCML string and converts to an array-based old toolkit data description string.
39 | *
40 | * @param string $pcml The string of PCML
41 | * @param ToolkitInterface $connection connection object for toolkit
42 | * @throws \Exception
43 | */
44 | public function __construct($pcml, ToolkitInterface $connection)
45 | {
46 | $this->setConnection($connection);
47 |
48 | // Convert PCML from ANSI format (which old toolkit required) to UTF-8 (which SimpleXML requires).
49 |
50 | $encoding = $connection->getConfigValue('system', 'encoding', 'ISO-8859-1'); // XML encoding
51 |
52 | /*
53 | * Look for optionally set /is';
60 | if (preg_match($regex, $pcml, $matches) && $matches[1] != 'UTF-8') {
61 | //remove xml-tag
62 | $pcml = substr($pcml, strlen($matches[0]));
63 | $pcml = mb_convert_encoding($pcml, 'UTF-8', $matches[1]);
64 | } elseif ($encoding != 'UTF-8') {
65 | $pcml = mb_convert_encoding($pcml, 'UTF-8', $encoding);
66 | }
67 |
68 | //program name is stored as: /pcml/program name="/qsys.lib/eacdemo.lib/teststruc.pgm"
69 | $xmlObj = new \SimpleXMLElement($pcml);
70 |
71 | // get root node and make sure it's named 'pcml'
72 | if(!isset($xmlObj[0]) || ($xmlObj[0]->getName() != 'pcml')) {
73 | throw new \Exception("PCML file must contain pcml tag");
74 | }
75 |
76 | $pcmlObj = $xmlObj[0];
77 |
78 | // get program name, path, etc.
79 | if(!isset($pcmlObj->program) || (!$pcmlObj->program)) {
80 | throw new \Exception("PCML file must contain program tag");
81 | }
82 | $programNode = $pcmlObj->program;
83 |
84 | $pgmAttrs = $programNode->attributes();
85 |
86 | /**
87 | * sample:
88 | *
95 | *
96 | */
97 |
98 | // let's focus on name, path, and entrypoint, the only attributes likely to be used here.
99 | $path = (isset($pgmAttrs['path'])) ? $pgmAttrs['path'] : '';
100 | $entrypoint = (isset($pgmAttrs['entrypoint'])) ? $pgmAttrs['entrypoint'] : '';
101 |
102 | // Note: if entrypoint is supplied, it's the function in a service program. "name" will be the same as entrypoint.
103 | // if entrypoint is not supplied, name is the actual program name.
104 | // Therefore, "name" seems somewhat worthless.
105 |
106 | // break up path, separated now by slashes. can be varied lib and pgm.
107 | // remove the /qsys.lib that may be in front but only if it's simply qualifying another library. qsys may be the actual program library, too.
108 |
109 | $objArray = $this->splitPcmlProgramPath($path);
110 | if ($objArray['lib']) {
111 | $pgmName = "{$objArray['lib']}/{$objArray['obj']}";
112 | } else {
113 | $pgmName = $objArray['obj'];
114 | }
115 |
116 | // now add the entrypoint, if any, as a procedure/function.
117 | if ($entrypoint) {
118 | // append the entry point enclosed in parentheses.
119 | $pgmName .= "($entrypoint)";
120 | }
121 |
122 | // Now create data description array.
123 | $dataDescriptionArray = $this->pcmlToArray($xmlObj);
124 |
125 | //Change the encoding back to the one wanted by the user, since SimpleXML encodes its output always in UTF-8
126 | $pgmName = mb_convert_encoding($pgmName, $encoding, 'UTF-8');
127 | mb_convert_variables($encoding, 'UTF-8', $dataDescriptionArray);
128 |
129 | // call parent's constructor with:
130 | //$descObj = new DataDescriptionPcml($description, $connection);
131 | parent::__construct($pgmName, $dataDescriptionArray, $connection);
132 | }
133 |
134 | /**
135 | * given a single ->data or ->struct element, return an array containing its contents as old toolkit-style data description.
136 | *
137 | * @param \SimpleXmlElement $dataElement
138 | * @return array
139 | */
140 | public function singlePcmlToArray(\SimpleXmlElement $dataElement)
141 | {
142 | $tagName = $dataElement->getName();
143 |
144 | // get attributes of this element.
145 | $attrs = $dataElement->attributes();
146 |
147 | // both struct and data have name, count (optional), usage
148 | $name = (isset($attrs['name'])) ? (string) $attrs['name'] : '';
149 | $count = (isset($attrs['count'])) ? (string) $attrs['count'] : '';
150 | $usage = (isset($attrs['usage'])) ? (string) $attrs['usage'] : '';
151 | $structName = (isset($attrs['struct'])) ? (string) $attrs['struct'] : '';
152 |
153 | // fill this if we have a struct
154 | $subElements = array();
155 |
156 | // should all be data
157 | if ($tagName == 'data') {
158 |
159 | $type = (isset($attrs['type'])) ? (string) $attrs['type'] : '';
160 |
161 | // if a struct then we need to recurse.
162 | if ($type != 'struct') {
163 |
164 | // regular type (char, int...), not a struct, so the data element's name is just 'name'.
165 | $nameName = 'Name';
166 | } else {
167 | // it IS a struct.
168 |
169 | // old toolkit uses DSName for a data structure's name.
170 | $nameName = 'DSName';
171 |
172 | $theStruct = null; // init
173 |
174 | // look for matching struct
175 | if ($this->_pcmlStructs) {
176 | // TODO verify type with is_array and count
177 | foreach ($this->_pcmlStructs as $possibleStruct) {
178 | $possStructAttrs = $possibleStruct->attributes();
179 | if ($possStructAttrs['name'] == $structName) {
180 | $theStruct = $possibleStruct;
181 | $structAttrs = $possStructAttrs;
182 | break;
183 | }
184 | }
185 | }
186 |
187 | // if struct was not found, generate error for log
188 | if (!$theStruct) {
189 | // $this->getConnection->logThis("PCML structure '$structName' not found.");
190 | return null;
191 | }
192 |
193 | // if we got here, we found our struct.
194 |
195 | // count can also be defined at the structure level. If so, it will override count from data level)
196 | if (isset($structAttrs['count'])) {
197 | $count = (string) $structAttrs['count'];
198 | }
199 |
200 | // "usage" (in/out/inherit) can be defined here, at the structure level.
201 | $structUsage = (isset($structAttrs['usage'])) ? (string) $structAttrs['usage'] : '';
202 |
203 | // if we're not inheriting from our parent data element, but there is a struct usage, use the struct's usage (input, output, or inputoutput).
204 | if (!empty($structUsage) && ($structUsage != 'inherit')) {
205 | $usage = $structUsage;
206 | }
207 |
208 | $structSubDataElementsXmlObj = $theStruct->xpath('data');
209 | if ($structSubDataElementsXmlObj) {
210 | foreach ($structSubDataElementsXmlObj as $subDataElementXmlObj) {
211 |
212 | if ($subDataElementXmlObj->attributes()->usage == 'inherit') {
213 | // subdata is inheriting type from us. Give it to them.
214 | $subDataElementXmlObj->attributes()->usage = $usage;
215 | }
216 |
217 | // here's where the recursion comes in. Convert data and add to array for our struct.
218 | $subElements[] = $this->singlePcmlToArray($subDataElementXmlObj);
219 | }
220 | }
221 | }
222 |
223 | $length = (isset($attrs['length'])) ? (string) $attrs['length'] : '';
224 | $precision = (isset($attrs['precision'])) ? (string) $attrs['precision'] : '';
225 |
226 | //$struct = (isset($attrs['struct'])) ? (string) $attrs['struct'] : ''; // if this is pointing to a struct name
227 |
228 | // find CW data type equivalent of PCML data type
229 | if (isset($this->_pcmlTypeMap[$type])) {
230 | // a simple type mapping
231 | $newType = (string) $this->_pcmlTypeMap[$type];
232 | } elseif ($type == 'int') {
233 | // one of the integer types. Need to use length to determine which one.
234 | if ($length == '2') {
235 | $newType = I5_TYPE_SHORT;
236 | } elseif ($length == '4') {
237 | $newType = I5_TYPE_INT;
238 | } else {
239 | $newType = ''; // no match
240 | }
241 | } else {
242 | $newtype = '';
243 |
244 | }
245 |
246 | $newInout = (isset($this->_pcmlInoutMap[$usage])) ? (string) $this->_pcmlInoutMap[$usage] : '';
247 |
248 | // create new length using precision if necessary
249 | if ($precision) {
250 | $newLength = "$length.$precision";
251 | } else {
252 | $newLength = $length;
253 | }
254 | }
255 |
256 | // count
257 | $newCount = 0; // initialize
258 | $newCountRef = '';
259 | if (is_numeric($count) && ($count > 0)) {
260 | $newCount = $count;
261 | } elseif (is_string($count) && !empty($count)) {
262 | // count is character, so it's really a countref
263 | $newCountRef = $count;
264 | }
265 |
266 | $element = array();
267 |
268 | $element[$nameName] = $name;
269 |
270 | // if not a struct, provide data type.
271 | if ($type != 'struct') {
272 | $element['Type'] = $newType;
273 | }
274 |
275 | if ($newCount) {
276 | $element['Count'] = $newCount;
277 | }
278 | if ($newCountRef) {
279 | $element['CountRef'] = $newCountRef;
280 | }
281 | if ($newLength) {
282 | $element['Length'] = $newLength;
283 | }
284 | if ($newInout) {
285 | $element['IO'] = $newInout;
286 | }
287 |
288 | if (count($subElements)) {
289 | $element['DSParm'] = $subElements;
290 | }
291 |
292 | return $element;
293 | }
294 |
295 | /**
296 | * given an XML object containing a PCML program definition, return an old toolkit style of data description array.
297 | *
298 | * @param \SimpleXMLElement $xmlObj
299 | * @return array
300 | */
301 | public function pcmlToArray(\SimpleXMLElement $xmlObj)
302 | {
303 | $dataDescription = array();
304 |
305 | // put structs in its own variable that can be accessed independently.
306 | $this->_pcmlStructs = $xmlObj->xpath('struct');
307 |
308 | // looking for ->data and ->struct.
309 | $dataElements = $xmlObj->xpath('program/data');
310 |
311 | if ($dataElements) {
312 | foreach ($dataElements as $dataElement) {
313 |
314 | $dataDescription[] = $this->singlePcmlToArray($dataElement);
315 | }
316 | }
317 |
318 | return $dataDescription;
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/ToolkitApi/UserSpace.php:
--------------------------------------------------------------------------------
1 | ToolkitSrvObj = $ToolkitSrvObj ;
20 | }
21 |
22 | return $this;
23 | }
24 |
25 | /**
26 | * @return string
27 | */
28 | public function getCpfErr()
29 | {
30 | return $this->CPFErr;
31 | }
32 |
33 | /**
34 | * @return mixed
35 | */
36 | public function getError()
37 | {
38 | return $this->ErrMessage;
39 | }
40 |
41 | // @todo in cw.php, user space api should do an error action with CPF code if needed
42 | /* private function verify_CPFError($retPgmArr, $functionErrMsg)
43 | {
44 | // it's an error if we didn't get output array at all
45 | if (!is_array($retPgmArr)){
46 | $this->ErrMessage = $functionErrMsg . $this->ToolkitSrvObj->getLastError();
47 | return true;
48 | }
49 |
50 | $retArr = $retPgmArr['io_param'];
51 |
52 | // get errorDs from named ds (CW style) or directly (PHP toolkit style)
53 | $errorDs = (isset($retArr['errorDs'])) ? $retArr['errorDs'] : $retArr;
54 | // if there's a CPF-style error code
55 | if (isset($errorDs) && ($errorDs['exceptId'] != '0000000')){
56 | $this->CPFErr = $errorDs['exceptId'];
57 | // @todo future, get actual error text from joblog
58 | $this->ErrMessage = $functionErrMsg . $this->CPFErr;
59 | return true; //some problem
60 | } else {
61 | // no CPF error detected.
62 | $this->CPFErr = '0000000';
63 | $this->ErrMessage = '';
64 | return false;
65 | }
66 |
67 |
68 | } //(verify_CPFError)
69 | */
70 |
71 | /**
72 | * @param null $UserSpaceName
73 | * @param null $USLib
74 | * @param int $InitSize
75 | * @param string $publicAuthority
76 | * @param string $InitValue
77 | * @param string $extendedAttribute
78 | * @param string $textDescription
79 | * @return bool
80 | */
81 | public function CreateUserSpace($UserSpaceName = NULL, $USLib = NULL, $InitSize =1024, $publicAuthority = '*ALL', $InitValue=' ',
82 | $extendedAttribute='PF', $textDescription='ZS XML Service User Space')
83 | {
84 | // @todo check that 1 <= InitSize <= 16776704
85 |
86 | // set defaults in case blank is passed in
87 | $InitSize = ($InitSize) ? $InitSize : 1024;
88 | $publicAuthority = ($publicAuthority) ? $publicAuthority : '*ALL';
89 | $InitValue= ($InitValue) ? $InitValue : '00'; // single binary hex value X'00, most efficient initialization, according to documentation of QUSCRTUS
90 | $extendedAttribute = ($extendedAttribute) ? $extendedAttribute : 'PF';
91 | $textDescription = ($textDescription) ? $textDescription : 'ZS XML Service User Space';
92 |
93 | // format the user space name and library into 20 char format
94 | $this->setUSName($UserSpaceName, $USLib);
95 |
96 | // format extended attribute into proper format (left-aligned)
97 | $extAttrFormatted = sprintf("%-10s", $extendedAttribute);
98 |
99 | // format authority into proper format (left-aligned)
100 | $authFormatted = sprintf("%-10s", $publicAuthority);
101 |
102 | $params[] = Toolkit::AddParameterChar('in', 20, "USER SPACE NAME", 'userspacename', $this->getUSFullName());
103 | $params[] = Toolkit::AddParameterChar('in', 10, "Extended Attribute",'extendedattribute', $extAttrFormatted);
104 | $params[] = Toolkit::AddParameterInt32('in', "Initial Size", 'initialsize', $InitSize);
105 | $params[] = Toolkit::AddParameterBin('in', 1, "Initial Value: one byte to fill whole space with", 'initval', $InitValue);
106 | $params[] = Toolkit::AddParameterChar('in', 10, "Public Authority", 'authority', $authFormatted);
107 | $params[] = Toolkit::AddParameterChar('in', 50, "Description", 'description', $textDescription);
108 | $params[] = Toolkit::AddParameterChar('in', 10, "Replace US", 'replaceuserspace', "*NO ");
109 | $params[] = Toolkit::AddErrorDataStruct();
110 |
111 | // $params = $this->DefineUserSpaceParameters($InitSize, $Auth, $InitChar);
112 | $retPgmArr = $this->ToolkitSrvObj->PgmCall('QUSCRTUS', 'QSYS', $params);
113 |
114 | if ($this->ToolkitSrvObj->verify_CPFError($retPgmArr , "Create user space failed.")) {
115 | return false;
116 | }
117 |
118 | return true; //created
119 | }
120 |
121 | /**
122 | * @return array|bool
123 | */
124 | public function RetrieveUserSpaceAttr()
125 | {
126 | $BytesRet = 0;
127 | $BytesAv = 25;
128 | $USSize = 0;
129 | $Ext = ' ';
130 | $InitVal = ' ';
131 | $libName = ' ';
132 |
133 | /*Reciever var*/
134 | $ds[]=Toolkit::AddParameterInt32('out', "Bytes returned", 'ret_bytes', $BytesRet);
135 | $ds[]=Toolkit::AddParameterInt32('out', "Bytes available", 'bytes_avail', $BytesAv);
136 | $ds[]=Toolkit::AddParameterInt32('out', "Space size", 'spacesize', $USSize);
137 | $ds[]=Toolkit::AddParameterChar('out', 1, "Automatic extendibility",'extend_automatic', $Ext);
138 | $ds[]=Toolkit::AddParameterChar('out', 1, "Initial value", 'initval', $InitVal);
139 | $ds[]=Toolkit::AddParameterChar('out', 10, "User space library name", 'uslib', $libName);
140 | //$params[] = array('ds'=>$ds);
141 | $params[] = Toolkit::AddDataStruct($ds, 'receiver'); // note that ds names are discarded
142 | $params[] = Toolkit::AddParameterInt32('in', "Length of reciever",'reciver_len', 24);
143 | $params[] = Toolkit::AddParameterChar('in', 8, "Format name", 'format', "SPCA0100");
144 | $params[] = Toolkit::AddParameterChar('in', 20, "User space name and library", 'usfullname', $this->getUSFullName());
145 | $params[] = Toolkit::AddErrorDataStruct();
146 |
147 | $retPgmArr = $this->ToolkitSrvObj->PgmCall('QUSRUSAT', 'QSYS', $params);
148 |
149 | if ($this->ToolkitSrvObj->verify_CPFError($retPgmArr, "Retrieve user space attributes failed. Error: ")) {
150 | return false;
151 | }
152 |
153 | // If data structure integrity turned off, ds'es are discarded when reading output. The subfields become independent.
154 | // So 'receiver' may not exist. But this changes with data structure integrity, so allow for receiver var.
155 | if (isset($retPgmArr['io_param']['receiver'])) {
156 | // receiver ds var does exist.
157 | $retArr = $retPgmArr['io_param']['receiver'];
158 | } else {
159 | // ds subfields are directly under io_param.
160 | $retArr = $retPgmArr['io_param'];
161 | }
162 |
163 | // return selected values from return array.
164 | return array("Space Size"=>$retArr['spacesize'],
165 | "Automatic extendibility"=> $retArr['extend_automatic'],
166 | "Initial value"=>$retArr['initval'],
167 | "User space library name"=>$retArr['uslib']);
168 | }
169 |
170 | /**
171 | * @return int
172 | */
173 | public function RetrieveUserSpaceSize()
174 | {
175 | $ret = $this->RetrieveUserSpaceAttr();
176 | return (isset($ret['Space Size'])? $ret['Space Size']: -1); // -1 is an error condition
177 | }
178 |
179 | /**
180 | * @return bool
181 | */
182 | public function DeleteUserSpace()
183 | {
184 | $params[] = Toolkit::AddParameterChar('in', 20, "User space name", 'userspacename', $this->getUSFullName());
185 | $params[] = Toolkit::AddErrorDataStruct();
186 |
187 | $retPgmArr = $this->ToolkitSrvObj->PgmCall('QUSDLTUS', 'QSYS', $params);
188 |
189 | if ($this->ToolkitSrvObj->verify_CPFError($retPgmArr, "Delete user space failed. Error:")) {
190 | return false;
191 | }
192 |
193 | return true;
194 | }
195 |
196 | /**
197 | * @todo write binary data?
198 | *
199 | * @param int $startpos
200 | * @param $valuelen
201 | * @param $value
202 | * @return bool
203 | */
204 | public function WriteUserSpace($startpos, $valuelen, $value)
205 | {
206 | //Size ($comment, $varName = '', $labelFindLen = null) {
207 | $params[] = Toolkit::AddParameterChar ('in', 20, "User space name and lib", 'usfullname', $this->getUSFullName());
208 | $params[] = Toolkit::AddParameterInt32('in', "Starting position",'pos_from', $startpos);
209 | $params[] = Toolkit::AddParameterInt32('in', "Length of data", 'dataLen', $valuelen);
210 | $params[] = Toolkit::AddParameterChar('in', $valuelen, "Input data", 'data_value', $value);
211 | $params[] = Toolkit::AddParameterChar('in', 1, "Force changes to auxiliary storage", 'aux_storage', '0');
212 | $params[] = Toolkit::AddErrorDataStruct();
213 | $retPgmArr = $this->ToolkitSrvObj->PgmCall('QUSCHGUS', 'QSYS', $params);
214 |
215 | if ($this->ToolkitSrvObj->verify_CPFError($retPgmArr , "Write into User Space failed. Error:")) {
216 | return false;
217 | }
218 |
219 | return true;
220 | }
221 |
222 | /**
223 | * CW version. $param must be an array of ProgramParameter objects or a single ProgramParameter object.
224 | *
225 | * @param int $startPos
226 | * @param ProgramParameter $param
227 | * @return bool
228 | */
229 | public function WriteUserSpaceCw($startPos, ProgramParameter $param)
230 | {
231 | /*
232 | if (!is_object($param) && !is_array($param)) {
233 | throw new \Exception('Parameter passed to WriteUserSpaceCw must be an array or ProgramParameter object.');
234 | }
235 | */
236 |
237 | // @todo any error, write to toolkit log.
238 |
239 | $labelForSizeOfInputData = 'dssize';
240 | $param->setParamLabelLen($labelForSizeOfInputData);
241 | //Size ($comment, $varName = '', $labelFindLen = null) {
242 | $params[] = Toolkit::AddParameterChar('in', 20,"User space name and lib", 'usfullname', $this->getUSFullName());
243 | $params[] = Toolkit::AddParameterInt32('in', "Starting position", 'pos_from', $startPos);
244 | $params[] = Toolkit::AddParameterSize("Length of data",'dataLen', $labelForSizeOfInputData);
245 | $params[] = $param;
246 | $params[] = Toolkit::AddParameterChar('in', 1, "Force changes to auxiliary storage", 'aux_storage', '0');
247 | $params[] = Toolkit::AddErrorDataStruct();
248 |
249 | $retPgmArr = $this->ToolkitSrvObj->PgmCall('QUSCHGUS', 'QSYS', $params);
250 |
251 | if ($this->ToolkitSrvObj->getErrorCode()) {
252 | return false;
253 | } else {
254 | return true;
255 | }
256 | }
257 |
258 | /**
259 | * if receiveDescription given, readlen = 0
260 | *
261 | * @param int $frompos
262 | * @param int $readlen
263 | * @param null $receiveStructure
264 | * @return bool
265 | * @throws \Exception
266 | */
267 | public function ReadUserSpace($frompos=1, $readlen = 0, $receiveStructure = null)
268 | {
269 | //how to see via green screen DSPF STMF('/QSYS.lib/qgpl.lib/ZS14371311.usrspc')
270 |
271 | $dataRead = ' ';
272 | $params[] = Toolkit::AddParameterChar('in', 20, "User space name and library", 'userspacename', $this->getUSFullName());
273 | $params[] = Toolkit::AddParameterInt32('in', "From position", 'position_from', $frompos);
274 |
275 | $receiverVarName = 'receiverdata';
276 |
277 | if ($receiveStructure) {
278 | // must be a ProgramParameter
279 | if (!is_object($receiveStructure)) {
280 | throw new \Exception('Parameter 3 passed to ReadUserSpace must be a ProgramParameter object.');
281 | }
282 |
283 | $labelForSizeOfInputData = 'dssize';
284 | //
285 | $params[] = Toolkit::AddParameterSize("Length of data", 'dataLen', $labelForSizeOfInputData);
286 |
287 | // wrap simple ds around receive structure so we can assign a varname to retrieve later.
288 | $receiveDs[] = $receiveStructure;
289 | $params[] = Toolkit::AddDataStruct($receiveDs, $receiverVarName, 0, '', false, $labelForSizeOfInputData);
290 |
291 | } else {
292 | // regular readlen, no special structure or size labels.
293 | $params[] = Toolkit::AddParameterInt32('in', "Size of data", 'datasize', $readlen);
294 | $params[] = Toolkit::AddParameterChar('out', $readlen, $receiverVarName, $receiverVarName, $receiveStructure);
295 | }
296 |
297 | $params[] = Toolkit::AddErrorDataStruct();
298 |
299 | $retPgmArr = $this->ToolkitSrvObj->PgmCall('QUSRTVUS', 'QSYS', $params);
300 |
301 | if ($this->ToolkitSrvObj->verify_CPFError($retPgmArr , "Read user space failed. Error:"))
302 | return false;
303 | $retArr = $retPgmArr['io_param'];
304 |
305 | // return our receiverstructure.
306 | return $retArr[$receiverVarName];
307 | }
308 |
309 | /* private function DefineUserSpaceParameters($InitSize, $Auth, $InitChar)
310 | {
311 | $params[] = Toolkit::AddParameterChar('in',20, "USER SPACE NAME", 'userspacename', $this->getUSFullName());
312 | $params[] = Toolkit::AddParameterChar('in',10, "USER TYPE",'userspacetype', "PF ");
313 | $params[] = Toolkit::AddParameterInt32('in', "US SIZE", 'userspacesize', $InitSize);
314 | $params[] = Toolkit::AddParameterChar('in',1, "INITIALIZATION VALUE", 'initval', $InitChar);
315 | $params[] = Toolkit::AddParameterChar('in',10, "AUTHORITY", 'authority', $Auth);
316 | $params[] = Toolkit::AddParameterChar('in',50, "COMMENTS", 'comment', "ZS XML Service");
317 | $params[] = Toolkit::AddParameterChar('in',10, "Replace US", 'replaceuserspace', "*NO ");
318 | $params[] = Toolkit::AddErrorDataStruct();
319 |
320 | return $params;
321 | }
322 | */
323 |
324 | /**
325 | * @return null|string
326 | */
327 | protected function generate_name()
328 | {
329 | $localtime = localtime();
330 | $this->USName = sprintf("ZS%d%d%d%d",
331 | $localtime[0],/*sec*/
332 | $localtime[1],/*min*/
333 | $localtime[2],/*our*/
334 | $localtime[3] /*day*/
335 | );
336 | return $this->USName;
337 | }
338 |
339 | /**
340 | * @param null $name
341 | * @param null $lib
342 | */
343 | public function setUSName($name = NULL, $lib = NULL)
344 | {
345 | if ($name === NULL) {
346 | $this->USName = $this->generate_name ();
347 | } else {
348 | $this->USName = $name;
349 | }
350 |
351 | if ($lib === NULL) {
352 | $this->USlib = DFTLIB;
353 | } else {
354 | $this->USlib = $lib;
355 | }
356 | }
357 |
358 | /**
359 | * @return null
360 | */
361 | public function getUSName()
362 | {
363 | return $this->USName;
364 | }
365 |
366 | /**
367 | * Name and Library
368 | *
369 | * @return null|string
370 | */
371 | public function getUSFullName()
372 | {
373 | if ($this->USName != null) {
374 | return sprintf("%-10s%-10s", $this->USName, $this->USlib);
375 | }
376 |
377 | return NULL;
378 | }
379 | }
380 |
--------------------------------------------------------------------------------