Пример #1
0
</style>

<title><?php 
echo $scriptTitle;
?>
</title>
</head>
<?php 
echo h1($scriptTitle);
echo h2('Version check');
// display CW version or warning message.
$downloadSite = 'http://www.youngiprofessionals.com/wiki/XMLSERVICE';
$downloadLink = '<a href="' . $downloadSite . '" target="_blank">' . $downloadSite . '</a>';
if (function_exists('i5_version')) {
    echo "You are running CW version <b>" . i5_version() . "</b>.<BR> Any updates will be found at {$downloadLink}.<BR>";
} else {
    echo "This version of CW is out of date.<BR>Please download the latest CW from {$downloadLink}.<BR><BR>";
}
echo h2('Connection');
// choose connection function based on persistence choice
$connFunction = $persistent ? 'i5_pconnect' : 'i5_connect';
echo "About to connect with {$connFunction}('', '', '') (feel free to specify a real user here)<BR>";
// options (liblist, ccsid, jobname) can be changed by the user in toolkit.ini.
$options = array();
if ($setLibList) {
    $options[I5_OPTIONS_INITLIBL] = $setLibList;
    echo "I5_OPTIONS_INITLIBL = '{$setLibList}'<BR>";
}
if ($setCcsid) {
    $options[I5_OPTIONS_RMTCCSID] = $setCcsid;
Пример #2
0
/**
 * return toolkit object on success, false on error
 * if 'persistent' passed in options, do a persistent conn.
 * if CW_EXISTING_TRANSPORT_RESOURCE passed in options, use it as database conn.
 * 
 * @param string $host
 * @param string $user
 * @param string $password
 * @param array $options
 * @return mixed
 */
function i5_connect($host = 'localhost', $user = '', $password = '', $options = array())
{
    // Special warning. We do not support proprietary codepagefile.
    if (isset($options[I5_OPTIONS_CODEPAGEFILE])) {
        logThis("Instead of using I5_OPTIONS_CODEPAGEFILE, please use a combination of I5_OPTIONS_RMTCCSID and I5_OPTIONS_LOCALCP as appropriate.");
    }
    // create "change job" parameters as we go, based on options
    $jobParams = array();
    $libl = array();
    // check and store RMTCCSID option
    if (isset($options[I5_OPTIONS_RMTCCSID])) {
        if (!is_numeric(trim($options[I5_OPTIONS_RMTCCSID]))) {
            i5ErrorActivity(I5_ERR_PHP_TYPEPARAM, I5_CAT_PHP, 'Value of I5_OPTIONS_RMTCCSID must be numeric', 'Value of I5_OPTIONS_RMTCCSID must be numeric');
            return false;
        } else {
            $jobParams['ccsid'] = trim($options[I5_OPTIONS_RMTCCSID]);
        }
    }
    // check and handle I5_OPTIONS_INITLIBL option
    if (isset($options[I5_OPTIONS_INITLIBL])) {
        $initLiblString = trim($options[I5_OPTIONS_INITLIBL]);
        if (empty($initLiblString) || !is_string($initLiblString)) {
            i5ErrorActivity(I5_ERR_PHP_TYPEPARAM, I5_CAT_PHP, 'Value of I5_OPTIONS_INITLIBL must be a string', 'Value of I5_OPTIONS_INITLIBL must be a string');
            return false;
        } else {
            // initLibl must be a comma-delimited OR space-delimited (or both) list of libraries.
            /* Split the string by any number of commas or space characters,
             * which include " ", \r, \t, \n and \f
             * We can't use explode() because the delimiters may be a combination of space and comma.
             */
            $libl = preg_split('/[\\s,]+/', trim($options[I5_OPTIONS_INITLIBL]));
            if (!is_array($libl) || empty($libl)) {
                // if didn't get an array or it's empty, the string must have been bad.
                i5ErrorActivity(I5_ERR_PHP_NBPARAM_BAD, I5_CAT_PHP, 'Value of I5_OPTIONS_INITLIBL not a comma-delimited string of libraries', 'Value of I5_OPTIONS_INITLIBL not a comma-delimited string of libraries');
                return false;
            }
        }
    }
    // check and store CW_PERSISTENT option
    $isPersistent = false;
    // default
    if (isset($options[CW_PERSISTENT])) {
        if (!is_bool($options[CW_PERSISTENT])) {
            i5ErrorActivity(I5_ERR_PHP_TYPEPARAM, I5_CAT_PHP, 'Value of CW_PERSISTENT must be boolean', 'Value of CW_PERSISTENT must be boolean');
            return false;
        } else {
            $isPersistent = $options[CW_PERSISTENT];
        }
    }
    $isNewConn = true;
    //default: it's a new conn, not reusing an old one.
    // check and handle I5_OPTIONS_PRIVATE_CONNECTION option
    if (isset($options[I5_OPTIONS_PRIVATE_CONNECTION])) {
        // only works if connection is persistent, too.
        if (!$isPersistent) {
            // not persistent. this is an error.
            i5ErrorActivity(I5_ERR_PHP_TYPEPARAM, I5_CAT_PHP, 'I5_OPTIONS_PRIVATE_CONNECTION was set but connection was not persistent. Try again using i5_pconnect().', 'I5_OPTIONS_PRIVATE_CONNECTION was set but connection was not persistent. Try again using i5_pconnect().');
            return false;
        }
        // verify that the connection value is numeric
        $privateConnNum = trim($options[I5_OPTIONS_PRIVATE_CONNECTION]);
        if (!is_numeric($privateConnNum)) {
            i5ErrorActivity(I5_ERR_PHP_TYPEPARAM, I5_CAT_PHP, 'Value of I5_OPTIONS_PRIVATE_CONNECTION must be numeric', 'Value of I5_OPTIONS_PRIVATE_CONNECTION must be numeric');
            return false;
        }
        // if a 0 is passed, generate a connection number that will be used in the IPC.
        if ($privateConnNum == 0) {
            // generate a number to be saved in connection class
            // (Old toolkit used job number. New toolkit needs IPC before job is created.)
            list($microseconds, $seconds) = explode(' ', microtime());
            // remove decimal points or any other non-numeric from microseconds
            $microseconds = preg_replace('/\\D/', '', $microseconds);
            $privateConnNum = getmypid() . $seconds . $microseconds;
            //getmypid() is a per-process number.
        } else {
            // re-using an old (non-zero) connection number. NOT a new connection.
            $isNewConn = false;
        }
        // Note: if a nonexistent private connection number is passed in, XMLSERVICE will create the IPC.
        // The old toolkit returned an error.
        // We COULD duplicate that "error" behavior by checking for the existence of the number in advance,
        // but that might harm performance.
    }
    // check and handle I5_OPTIONS_IDLE_TIMEOUT
    // Number of seconds of not being used after which a persistent/private connection job will end.
    $idleTimeout = 0;
    // default of 0 means no timeout (infinite wait)
    if (isset($options[I5_OPTIONS_IDLE_TIMEOUT])) {
        $idleTimeout = $options[I5_OPTIONS_IDLE_TIMEOUT];
    }
    $jobName = '';
    // init
    if (isset($options[I5_OPTIONS_JOBNAME])) {
        $jobName = trim($options[I5_OPTIONS_JOBNAME]);
    }
    // check and store CW_EXISTING_TRANSPORT_CONN option (such as to reuse a db connection)
    $existingTransportResource = null;
    $existingTransportI5NamingFlag = false;
    if (isset($options[CW_EXISTING_TRANSPORT_CONN])) {
        if (!is_resource($options[CW_EXISTING_TRANSPORT_CONN])) {
            i5ErrorActivity(I5_ERR_PHP_TYPEPARAM, I5_CAT_PHP, 'Value of CW_EXISTING_TRANSPORT_CONN must be a resource', 'Value of CW_EXISTING_TRANSPORT_CONN must be a resource');
            return false;
        } else {
            $existingTransportResource = $options[CW_EXISTING_TRANSPORT_CONN];
            $existingTransportI5NamingFlag = isset($options[CW_EXISTING_TRANSPORT_I5_NAMING]) ? $options[CW_EXISTING_TRANSPORT_I5_NAMING] : false;
        }
    }
    // check and store CW_TRANSPORT_TYPE, if given. It's optional.
    $transportType = '';
    // empty is ok.
    $iniTransportType = isset($options[CW_TRANSPORT_TYPE]) ? $options[CW_TRANSPORT_TYPE] : getConfigValue('transport', 'transportType', 'ibm_db2');
    if ($iniTransportType) {
        $validTransports = array('ibm_db2', 'odbc', 'http', 'https');
        if (!in_array($iniTransportType, $validTransports)) {
            // invalid transport specified.
            $errmsg = "Invalid CW_TRANSPORT_TYPE option ({$iniTransportType}). Omit or choose between " . explode(', ', $validTransports) . ".";
            i5ErrorActivity(I5_ERR_PHP_TYPEPARAM, I5_CAT_PHP, $errmsg, $errmsg);
            return false;
        } else {
            // valid transport
            $transportType = $iniTransportType;
        }
    }
    // convert host to dbname
    $dbname = getConfigValue('hosts', $host);
    if (!$dbname) {
        i5ErrorActivity(I5_CONN_TIMEOUT, I5_CAT_TCPIP, "Undefined host ('{$host}')", "Try 'localhost' instead, or specify lookup in " . CONFIG_FILE . " ({$host}=DBNAME).");
        return false;
    }
    $user = trim($user);
    if (!$user) {
        /*        if user was not specified, use '', ''
                which will translate to QTMHHTTP
                when old toolkit is disabled, we won't be able to get 'i5comm.default_user'
                from PHP.INI, and db2 will say QTMHHTTP anyway (default value of i5comm.default.user, too),
                so just use it and document it.
        */
        // OK. db2 can work with this.
        $user = '';
        $password = '';
    } else {
        // a user was supplied. Check user. Given the user, we also expect a password.
        // user/pw rules
        // @todo share these with i5_adopt_authority
        // forbid QSECOFR and usernames starting with *. (don't want *CURRENT, etc.)
        // @todo Actually, not sure if QSECOFR and special profiles should be forbidden. Check again with old toolkit.
        if (strtoupper($user) == 'QSECOFR' || substr($user, 0, 1) == '*' || empty($password) || substr($password, 0, 1) == '*') {
            i5ErrorActivity(I5_ERR_WRONGLOGIN, I5_CAT_PHP, 'Bad login user or password', 'Cannot connect with QSECOFR, blank password, or special profiles');
            return false;
        }
    }
    // Check if INI file has asked us to always close previous connection before initiating new one within a single PHP request/script run.
    // For compatibility with old toolkit behavior where a new connection would reset library lists and the like.
    // It's false by default for backward compatibility with older releases of CW.
    $forceNew = getConfigValue('cw', 'fullDbClose', false);
    // get instance of toolkit (singleton)
    try {
        if ($existingTransportResource) {
            // use existing resource
            $tkit = ToolkitServiceCw::getInstance($existingTransportResource, $existingTransportI5NamingFlag, '', '', $isPersistent, $forceNew);
        } else {
            // specify dbname, user, and password, transport type to create new transport
            $tkit = ToolkitServiceCw::getInstance($dbname, $user, $password, $transportType, $isPersistent, $forceNew);
        }
        // if getInstance() returned false (unlikely)
        if (!$tkit) {
            setError(I5_ERR_NOTCONNECTED, I5_CAT_PHP, 'Cannot get a connection', 'Cannot get a connection');
        }
    } catch (Exception $e) {
        // If user or password is wrong, give errNum I5_ERR_WRONGLOGIN with category I5_CAT_PHP.
        // Determine reason for failure.
        // Probably database authentication error or invalid or unreachable database.
        $code = $e->getCode();
        $msg = $e->getMessage();
        switch ($code) {
            case 8001:
                // Authorization failure on distributed database connection attempt.
                // Poss. wrong user or password
                $errNum = I5_ERR_WRONGLOGIN;
                break;
            case 42705:
                // db not found in relational directory.
                // treat as host not found.
                $errNum = I5_CONN_TIMEOUT;
                break;
            default:
                $errNum = I5_ERR_PHP_AS400_MESSAGE;
                break;
        }
        i5ErrorActivity($errNum, I5_CAT_PHP, $code, $msg);
        return false;
    }
    // successfully instantiated toolkit connection and instance. Mark it as CW.
    $tkit->setIsCw(true);
    // override toolkit settings if nec.
    $sbmjobParams = getConfigValue('system', 'sbmjob_params');
    $xmlServiceLib = getConfigValue('system', 'XMLServiceLib', 'ZENDSVR');
    $stateless = false;
    // default
    $cwVersion = i5_version();
    // If we have a private conn, create an IPC based on it.
    $connectionMsg = '';
    if (isset($privateConnNum) && $privateConnNum) {
        $ipc = makeIpc($user, $privateConnNum);
        // save private conn number. Can be retrieved later with getPrivateConnNum
        $tkit->setPrivateConnNum($privateConnNum);
        $tkit->setIsNewConn($isNewConn);
        $connectionMsg = "Running statefully with IPC '{$ipc}', private connection '{$privateConnNum}'. CW version {$cwVersion}. Service library: {$xmlServiceLib}";
    } else {
        // Not private. We may be stateless (inline).
        $stateless = getConfigValue('system', 'stateless', false);
        if ($stateless) {
            // don't need IPC if stateless, running in QSQ job.
            $ipc = '';
            $connectionMsg = "Running stateless; no IPC needed. CW version {$cwVersion}. Service library: {$xmlServiceLib}";
        } else {
            // @todo does this make sense? Not stateless but not private? Any purpose to stateless setting in INI file?
            // Not stateless, so create an IPC
            // @todo this will change based on persistent/nonpersistent logic
            // IPC to use in separate toolkit job using just user id and unique additions in makeIpc
            $ipc = makeIpc($user);
            $connectionMsg = "Not private but not stateless; running with IPC '{$ipc}'. CW version {$cwVersion}. Service library: {$xmlServiceLib}";
        }
    }
    // If INI file tells us to log CW's connection messages, do so.
    if (getConfigValue('log', 'logCwConnect', true)) {
        logThis($connectionMsg);
    }
    // handle connection options (e.g. encoding). for those options we don't support, write to log.
    if ($jobName) {
        // override any values for the last parm of $sbmjobParams
        // check that $sbmjobParams is set and has at least one slash
        if (!isset($sbmjobParams) || empty($sbmjobParams)) {
            // not specified in .INI file, but may be a default in toolkit itself.
            if (!$tkit->getToolkitServiceParam('sbmjobParams')) {
                i5ErrorActivity(I5_ERR_PHP_NBPARAM_BAD, I5_CAT_PHP, 'Job name was set but SBMJOB params were not. Please set SBMJOB params in toolkit.ini', 'Job name was set but SBMJOB params were not. Please set SBMJOB params in toolkit.ini or in ToolkitService.php default settings');
                return false;
            } else {
                // use the default as starting point
                $sbmjobParams = $tkit->getToolkitServiceParam('sbmjobParams');
            }
        }
        // check that sbmjob params has at least one, but not more than two, slashes in it. Final format: lib/jobd/jobname
        // Break string on forward slash.
        $sbmjobParts = explode('/', $sbmjobParams);
        if (count($sbmjobParts) > 3 || count($sbmjobParts) < 1) {
            // should be either 1 or 2 slashes. Not more and not less
            i5ErrorActivity(I5_ERR_PHP_TYPEPARAM, I5_CAT_PHP, 'Job name was set but SBMJOB param string was not valid. Should have one or two forward slashes. Please set SBMJOB params in toolkit.ini', 'Job name was set but SBMJOB param string was not valid. Should have one or two forward slashes. Please set SBMJOB params in toolkit.ini');
            return false;
        }
        // replace last part of string with job name.
        $sbmjobParts[2] = $jobName;
        // reconstruct sbmjob param string.
        $sbmjobParams = implode('/', $sbmjobParts);
    }
    // set IPC and other settings
    $serviceParams = array('internalKey' => $ipc, 'stateless' => $stateless);
    // additional settings
    if ($idleTimeout) {
        $serviceParams['idleTimeout'] = $idleTimeout;
    }
    if ($sbmjobParams) {
        // taking into account jobname preferences
        $serviceParams['sbmjobParams'] = $sbmjobParams;
    }
    // CW always retains data structure hierarchy (integrity) in parameters.
    $serviceParams['dataStructureIntegrity'] = true;
    // these will be in addition to, or overriding, any params set in toolkit service constructor.
    $tkit->setOptions($serviceParams);
    // initialize
    $cmdArray = array();
    // update the current job with options
    // @todo: do we have to run these if it's an existing IPC/connection, private conn? Perhaps the initialization happened already.
    if (count($jobParams)) {
        $cmdStr = "CHGJOB";
        foreach ($jobParams as $name => $value) {
            $cmdStr .= " {$name}({$value})";
        }
        // add string to array of commands to run in one shot
        $cmdArray[] = $cmdStr;
    }
    // update library list
    if (count($libl)) {
        // this is what the old toolkit seemed to do
        // @todo send multiple adds in one big XML string
        foreach ($libl as $lib) {
            $cmdArray[] = "ADDLIBLE LIB({$lib})";
        }
    }
    // run multiple commands if there are any.
    if (count($cmdArray)) {
        // We collect a success flag but don't examine it.
        // Old toolkit didn't do anything special if a connection option had invalid values.
        // We COULD write a message to the log, at best.
        $tkit->ClCommandWithCpf($cmdArray);
    }
    // return toolkit object for other functions to use
    return $tkit;
}
Пример #3
0
function runCwTest()
{
    // @todo need to somehow get ToolkitService so we can use getConfigValue()
    // some items to turn on and off in the test
    $doPcml = true;
    $doUserSpace = true;
    $doDataQueue = true;
    $doPgmCallComplex = true;
    $doPgmCallSimple = true;
    $doObjectList = true;
    $doJobLists = true;
    $doJobLogs = true;
    $doSpooledFiles = true;
    $doAdoptAuthority = true;
    ini_set('display_errors', 1);
    set_time_limit(480);
    // Include CW constants
    $cw_const_path = __DIR__ . '/vendor/zendtech/ibmitoolkit/ToolkitApi/CW/cwconstants.php';
    if (!file_exists($cw_const_path)) {
        throw new Exception("File " . $cw_const_path . " doesn't exist");
    }
    require_once $cw_const_path;
    $cw_path = __DIR__ . '/vendor/zendtech/ibmitoolkit/ToolkitApi/CW/cw.php';
    if (!file_exists($cw_path)) {
        throw new Exception("File " . $cw_path . " doesn't exist");
    }
    require_once $cw_path;
    //    require_once('CW/cw.php'); // don't need if added auto_append in PHP.INI
    // Use configurable demo lib/name from toolkit ini
    $demoLib = trim(getConfigValue('demo', 'demo_library'));
    if (!$demoLib) {
        die('Demo library not set in toolkit.ini.');
    }
    // Use configurable encoding from toolkit ini
    // We use encoding in meta tag so characters appear correctly in browser
    $encoding = trim(getConfigValue('system', 'encoding'));
    if (!$encoding) {
        die('Encoding not set in toolkit.ini. Example: ISO-8859-1');
    }
    // optional demo values
    $setLibList = trim(getConfigValue('demo', 'initlibl', ''));
    $setCcsid = trim(getConfigValue('demo', 'ccsid', ''));
    $setJobName = trim(getConfigValue('demo', 'jobname', ''));
    $setIdleTimeout = trim(getConfigValue('demo', 'idle_timeout', ''));
    $transportType = trim(getConfigValue('demo', 'transport_type', ''));
    // optional demo connection values
    $private = false;
    // default
    $privateNum = false;
    // default
    $persistent = trim(getConfigValue('demo', 'persistent', false));
    if ($persistent) {
        // private can only happen with persistence
        $private = trim(getConfigValue('demo', 'private', false));
        $privateNum = trim(getConfigValue('demo', 'private_num', '0'));
    }
    //(persistent)
    $scriptTitle = 'Test script for IBM i Compatibility Wrapper (CW)';
    // TODO get test user from toolkit.ini
    // this user, TKITU1, should exist on the system
    $user = '******';
    $testPw = 'WEBTEST';
    ?>

    <html>
    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=<?php 
    echo $encoding;
    ?>
">

        <style type="text/css">
            body {
                font: 15px;
            }

            h1 {
                font: 28px arial,sans-serif;
                font-weight: bold;
                border-style: solid;
                color: #2278A5;
                border: 1px 1px 1px 1px;
                padding: 2px 2px 2px 2px;
                margin-bottom: 30px;
            }

            h2 {
                font: 20px arial,sans-serif;
                font-weight: bold;
                background-color: lightblue;
            }

        </style>

        <title><?php 
    echo $scriptTitle;
    ?>
</title>
    </head>
    <?php 
    echo h1($scriptTitle);
    echo h2('Version check');
    // display CW version or warning message.
    $downloadSite = 'http://www.youngiprofessionals.com/wiki/XMLSERVICE';
    $downloadLink = '<a href="' . $downloadSite . '" target="_blank">' . $downloadSite . '</a>';
    if (function_exists('i5_version')) {
        echo "You are running CW version <b>" . i5_version() . "</b>.<BR> Any updates will be found at {$downloadLink}.<BR>";
    } else {
        echo "This version of CW is out of date.<BR>Please download the latest CW from {$downloadLink}.<BR><BR>";
    }
    echo h2('Connection');
    // choose connection function based on persistence choice
    $connFunction = $persistent ? 'i5_pconnect' : 'i5_connect';
    echo "About to connect with {$connFunction}('', '', '') (feel free to specify a real user here)<BR>";
    // options (liblist, ccsid, jobname) can be changed by the user in toolkit.ini.
    $options = array();
    if ($setLibList) {
        $options[I5_OPTIONS_INITLIBL] = $setLibList;
        echo "I5_OPTIONS_INITLIBL = '{$setLibList}'<BR>";
    }
    if ($setCcsid) {
        $options[I5_OPTIONS_RMTCCSID] = $setCcsid;
        echo "I5_OPTIONS_RMTCCSID = '{$setCcsid}'<BR>";
    }
    if ($setJobName) {
        $options[I5_OPTIONS_JOBNAME] = $setJobName;
        echo "I5_OPTIONS_JOBNAME = '{$setJobName}'<BR>";
    }
    if ($setIdleTimeout) {
        $options[I5_OPTIONS_IDLE_TIMEOUT] = $setIdleTimeout;
        echo "I5_OPTIONS_IDLE_TIMEOUT = '{$setIdleTimeout}'<BR>";
    }
    if ($transportType) {
        $options[CW_TRANSPORT_TYPE] = $transportType;
        echo "CW_TRANSPORT_TYPE = '{$transportType}'<BR>";
    }
    if ($persistent && $private) {
        $options[I5_OPTIONS_PRIVATE_CONNECTION] = $privateNum;
        echo "I5_OPTIONS_PRIVATE_CONNECTION = '{$privateNum}'<BR>";
    }
    // (private and privateNum)
    echo '<BR>';
    /*
     * // Optionally re-use an existing database connection for your transport
     * // If you specify a naming mode (i5/sql) in your connection, make sure they match.
     * $namingMode = DB2_I5_NAMING_ON;
     * $existingDb = db2_pconnect('', '','', array('i5_naming' => $namingMode));
     * // Add to existing connection options
     * $options[CW_EXISTING_TRANSPORT_CONN] = $existingDb;
     * $options[CW_EXISTING_TRANSPORT_I5_NAMING] = $namingMode;
     */
    $start = microtime(true);
    // about to connect. Can use i5_connect or i5_pconnect.
    $conn = $connFunction('localhost', '', '', $options);
    $end = microtime(true);
    $elapsed = $end - $start;
    echo "Ran {$connFunction} function, with options, in {$elapsed} seconds.<BR>";
    // if unable to connect, find out why.
    if (!$conn) {
        die('<BR>Could not connect. Reason: ' . printArray(i5_error()));
    }
    echo "Connection object output: '{$conn}'<BR><BR>";
    if ($private) {
        // if a private connection, show what number was used or generated.
        $privateConnNum = i5_get_property(I5_PRIVATE_CONNECTION, $conn);
        echo "Private conn number from i5_get_property(I5_PRIVATE_CONNECTION, \$conn): {$privateConnNum}<BR><BR>";
        $isNew = i5_get_property(I5_NEW_CONNECTION, $conn);
        echo "Is new connection?: {$isNew}<BR><BR>";
    }
    // CONNECTED.
    // check that demo library exists
    echo "About to verify that the demo library, '{$demoLib}', exists.<BR>";
    $list = i5_objects_list('QSYS', $demoLib, '*LIB', $conn);
    if (!$list) {
        echo 'Error getting object list: ' . printArray(i5_error()) . '<BR><BR>';
    } else {
        if ($listItem = i5_objects_list_read($list)) {
            echo "Demo library '{$demoLib}' exists.<BR><BR>";
        } else {
            die("<BR>Demo library '{$demoLib}' NOT found. Ending.");
        }
    }
    i5_objects_list_close($list);
    // ON TO ACTUAL FUNCTIONALITY
    if ($doPcml) {
        echo h2('PCML program calls');
        $pcml = '<pcml version="4.0">
       <program name="YYPLUS" entrypoint="YYPLUS"  path="/QSYS.LIB/' . $demoLib . '.LIB/YYSRVNORES.SRVPGM" >
          <data name="START" type="int" length="4" precision="31" usage="inputoutput" />
          <data name="RESULT" type="int" length="4" precision="31" usage="inputoutput" />
       </program>
        </pcml>';
        echo 'About to do simple PCML program prepare.<BR>';
        $pgmHandle = i5_program_prepare_PCML($pcml);
        if (!$pgmHandle) {
            echo 'Error preparing simple PCML program: ' . printArray(i5_error()) . '<BR><BR>';
        } else {
            $input = array('START' => '25', 'RESULT' => '0');
            $output = array('START' => 'START', 'RESULT' => 'RESULT');
            echo 'About to do simple PCML program call.<BR>';
            $success = i5_program_call($pgmHandle, $input, $output);
            $result = $output['RESULT'];
            if ($success) {
                echo "Success. Output variables: START: {$start}. RESULT: {$result}.";
            } else {
                echo "Problem calling PCML-described program. Error: " . print_r(i5_error(), true);
            }
        }
        echo '<BR><BR>';
        $pcml = "<pcml version=\"4.0\">\n           <struct name=\"S2\">\n              <data name=\"ZOND2\" type=\"zoned\" length=\"10\" precision=\"5\" usage=\"inherit\" />\n              <data name=\"PACK2\" type=\"packed\" length=\"19\" precision=\"5\" usage=\"inherit\" />\n              <data name=\"PACK3\" type=\"packed\" length=\"19\" precision=\"5\" usage=\"inherit\" />\n              <data name=\"ALPH2\" type=\"char\" length=\"20\" usage=\"inherit\" />\n           </struct>\n           <struct name=\"S1\">\n              <data name=\"ZOND\" type=\"zoned\" length=\"10\" precision=\"5\" usage=\"inherit\" />\n              <data name=\"PACK1\" type=\"packed\" length=\"19\" precision=\"5\" usage=\"inherit\" />\n              <data name=\"ALPH1\" type=\"char\" length=\"10\" usage=\"inherit\" />\n           </struct>\n           <program name=\"TESTSTRUC\" path=\"/QSYS.LIB/{$demoLib}.LIB/TESTSTRUC.PGM\">\n              <data name=\"CODE\" type=\"char\" length=\"10\" usage=\"output\" />\n              <data name=\"S1\" type=\"struct\" struct=\"S1\" usage=\"inputoutput\" />\n              <data name=\"S2\" type=\"struct\" struct=\"S2\" usage=\"inputoutput\" />\n              <data name=\"PACK\" type=\"packed\" length=\"1\" precision=\"1\" usage=\"output\" />\n              <data name=\"CH10\" type=\"char\" length=\"19\" usage=\"output\" />\n              <data name=\"CH11\" type=\"char\" length=\"20\" usage=\"output\" />\n              <data name=\"CH12\" type=\"char\" length=\"29\" usage=\"output\" />\n              <data name=\"CH13\" type=\"char\" length=\"33\" usage=\"output\" />\n           </program>\n        </pcml>";
        echo 'About to do a complex PCML program prepare.<BR>';
        $pgmHandle = i5_program_prepare_PCML($pcml);
        if ($pgmHandle) {
            echo "Successfully prepared complex PCML program description.<BR>";
        } else {
            echo "Problem while preparing complex PCML program description.<BR>";
        }
        // define some input values
        $pack3value = 7789777.44;
        $alph2value = 4;
        $paramIn = array("S1" => array("ZOND" => 54.77, "PACK1" => 16.2, "ALPH1" => "MyValue"), "S2" => array("ZOND2" => 44.66, "PACK2" => 24444.99945, "PACK3" => $pack3value, "ALPH2" => $alph2value));
        // now we need to define where to place output values; it will create new local variables
        $paramOut = array("S1" => "S1_Value", "S2" => "S2_Value", "CH10" => "CH10_Value", "CH11" => "CH11_Value", "CH12" => "CH12_Value", "CH13" => "CH13_Value", "CODE" => "Code_Value", "PACK" => "Pack");
        echo 'About to do complex PCML program call.';
        $success = i5_program_call($pgmHandle, $paramIn, $paramOut);
        if (function_exists('i5_output')) {
            extract(i5_output());
        }
        // i5_output() required if called in a function
        if ($success) {
            echo "Success.";
            echo "<BR>S1: " . var_export($S1_Value, true);
            echo "<BR>S2: " . var_export($S2_Value, true);
            echo "<BR>CH10: " . var_export($CH10_Value, true);
            echo "<BR>CH11: " . var_export($CH11_Value, true);
            echo "<BR>CH12: " . var_export($CH12_Value, true);
            echo "<BR>CH13: " . var_export($CH13_Value, true);
            echo "<BR>Code: " . var_export($Code_Value, true);
            echo "<BR>Pack: " . var_export($Pack, true);
        } else {
            echo "Problem calling PCML-described program. Error: " . printArray(i5_error());
        }
    }
    $bigDesc = array(array("DSName" => "BIGDS", "DSParm" => array(array("Name" => "P1", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10, "Count" => 5), array("Name" => "P2C", "IO" => I5_INOUT, "Type" => I5_TYPE_LONG, "Length" => 4), array("Name" => "P2", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 1, "CountRef" => "P2C"), array("DSName" => "PS", "Count" => 2, "DSParm" => array(array("Name" => "PS1", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10), array("Name" => "PS2", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10), array("Name" => "PS3", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10))))));
    $bigInputValues = array("BIGDS" => array("P1" => array("t1", "t2", "t3", "t4", "t5"), "P2C" => 2, "P2" => array("a", "b"), "PS" => array(array("PS1" => "test1", "PS2" => "test2", "PS3" => "test3"), array("PS1" => "test3", "PS2" => "test4", "PS3" => "test5"))));
    if ($doUserSpace) {
        echo h2('User spaces');
        $userSpaceName = 'DEMOSPACE';
        $userSpaceLib = $demoLib;
        $usObj = new UserSpace($conn);
        $usObj->setUSName($userSpaceName, $userSpaceLib);
        // toolkit does not have an i5_userspace_delete so delete with a command.
        $ret = i5_command("DLTUSRSPC USRSPC({$userSpaceLib}/{$userSpaceName})", $conn);
        if (function_exists('i5_output')) {
            extract(i5_output());
        }
        // i5_output() required if called in a function
        $status = $ret ? 'successfully' : 'badly';
        echo "deleted user space: {$status}<BR>";
        //$us = $usObj->CreateUserSpace('ALANUS', 'ALAN', $InitSize =1024, $Authority = '*ALL', $InitChar=' ');
        $usProperties = array(I5_NAME => $userSpaceName, I5_LIBNAME => $userSpaceLib, I5_INIT_VALUE => 'Y');
        echo "About to create user space.<BR>";
        $us = i5_userspace_create($usProperties, $conn);
        if (!$us) {
            echo "Error returned: " . printArray(i5_error()) . "<BR><BR>";
        } else {
            echo "Success!<BR><BR>";
        }
        // prepare userspace for a put
        $us = i5_userspace_prepare("{$userSpaceLib}/{$userSpaceName}", $bigDesc, $conn);
        if (!$us) {
            echo "Error returned from user space prepare: " . printArray(i5_error()) . "<BR><BR>";
        } else {
            echo "Success preparing user space.<BR><BR>";
        }
        // do the userspace put
        $success = i5_userspace_put($us, $bigInputValues);
        if (!$success) {
            echo "Error returned from user space put: " . printArray(i5_error()) . "<BR><BR>";
        } else {
            echo "Success putting data into user space.<BR><BR>";
        }
        // do the userspace get
        // removed counfref because doesn't work when getting.
        $bigDesc = array(array("DSName" => "BIGDS", "DSParm" => array(array("Name" => "P1", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10, "Count" => 5), array("Name" => "P2C", "IO" => I5_INOUT, "Type" => I5_TYPE_LONG, "Length" => 4), array("Name" => "P2", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 1, "Count" => 2), array("DSName" => "PS", "Count" => 2, "DSParm" => array(array("Name" => "PS1", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10), array("Name" => "PS2", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10), array("Name" => "PS3", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10))))));
        // prepare userspace for a get
        $us = i5_userspace_prepare("{$userSpaceLib}/{$userSpaceName}", $bigDesc, $conn);
        if (!$us) {
            echo "Error returned from user space prepare: " . printArray(i5_error()) . "<BR><BR>";
        } else {
            echo "Success preparing user space.<BR><BR>";
        }
        $success = i5_userspace_get($us, array("BIGDS" => "BIGDS"));
        if (function_exists('i5_output')) {
            extract(i5_output());
        }
        // i5_output() required if called in a function
        if (!$success) {
            echo "Error returned from user space get: " . i5_error() . "<BR><BR>";
        } else {
            echo "Success getting data from user space. BIGDS=" . printArray($BIGDS) . "<BR><BR>";
        }
    }
    // data queue
    if ($doDataQueue) {
        echo h2('Data queues');
        $queueName = 'KEYEDQ';
        $keyLen = 10;
        $qObj = new DataQueue($conn);
        echo "<BR>About to delete data queue {$queueName}. (Will fail if doesn't exist yet)<BR>";
        try {
            $qObj->DeleteDQ($queueName, $demoLib);
            echo "Success deleting data queue {$queueName}.";
        } catch (Exception $e) {
            echo "Error deleting data queue: " . $e . "<BR><BR>";
        }
        echo "<BR>About to create data queue {$queueName}.<BR>";
        try {
            $qObj->CreateDataQ($queueName, $demoLib, 128, '*KEYED', $keyLen);
            // length 10 key
            echo "Success creating data queue {$queueName}.";
        } catch (Exception $e) {
            echo "Error creating data queue: " . $e . "<BR><BR>";
        }
        // test case adapted from p398 of Zend Server 5.1 manual
        $simpleStructure = array('DSName' => 'PS', 'DSParm' => array(array('type' => 0, 'name' => 'PS1', 'length' => '10'), array('type' => 6, 'name' => 'PS2', 'length' => '10.4'), array('type' => 0, 'name' => 'PS3', 'length' => '10')));
        // prepare
        $queue = i5_dtaq_prepare("{$demoLib}/{$queueName}", $simpleStructure, $keyLen);
        if (!$queue) {
            echo "Error preparing data queue.<BR><BR>";
        }
        // send
        $key = 'abc';
        $data = array('PS1' => 'test1', 'PS2' => 13.1415, 'PS3' => 'test2');
        echo "<BR>About to send simple structure to keyed data queue {$queueName} with key {$key}.<BR>";
        $success = i5_dtaq_send($queue, $key, $data);
        if (!$success) {
            echo "Error returned from data queue send: " . printArray(i5_error()) . "<BR><BR>";
        } else {
            echo "Success sending data to data queue.<BR><BR>";
        }
        echo "<BR>About to receive simple structure from keyed data queue {$queueName} with key {$key}.<BR>";
        $data = i5_dtaq_receive($queue, 'EQ', $key);
        // receive
        if (!$data) {
            echo "Error returned from simple data queue receive: " . printArray(i5_error());
        } else {
            echo "Success getting simple data structure from data queue: " . printArray($data);
        }
        echo '<BR>';
        // unkeyed queue with complex structure
        $queueName = 'NEWQ';
        $qObj = new DataQueue($conn);
        echo "<BR>About to delete data queue {$queueName}. (Will fail if doesn't exist yet)<BR>";
        try {
            $qObj->DeleteDQ($queueName, $demoLib);
            echo "Success deleting data queue {$queueName}.";
        } catch (Exception $e) {
            echo "Error deleting data queue: " . $e . "<BR><BR>";
        }
        echo "<BR>About to create data queue {$queueName}.<BR>";
        try {
            $qObj->CreateDataQ($queueName, $demoLib);
            echo "Success creating data queue {$queueName}.";
        } catch (Exception $e) {
            echo "Error creating data queue: " . $e . "<BR><BR>";
        }
        $bigDesc = array(array("DSName" => "BIGDS", "DSParm" => array(array("Name" => "P1", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10, "Count" => 5), array("Name" => "P2C", "IO" => I5_INOUT, "Type" => I5_TYPE_LONG, "Length" => 4), array("Name" => "P2", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 1, "Count" => 2), array("DSName" => "PS", "Count" => 2, "DSParm" => array(array("Name" => "PS1", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10), array("Name" => "PS2", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10), array("Name" => "PS3", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10))))));
        // prepare
        $queue = i5_dtaq_prepare("{$demoLib}/{$queueName}", $bigDesc);
        if (!$queue) {
            echo "Error preparing data queue.<BR><BR>";
        }
        // send
        echo "<BR>About to send big data structure to data queue {$queueName}.<BR>";
        $success = i5_dtaq_send($queue, '', $bigInputValues);
        //
        if (!$success) {
            echo "Error returned from data queue send: " . i5_error() . "<BR><BR>";
        } else {
            echo "Success sending data to data queue.<BR><BR>";
        }
        echo "<BR>About to receive big data structure from data queue {$queueName}.<BR>";
        $data = i5_dtaq_receive($queue);
        //, $operator = null, $key = '', $timeout = 0)
        // receive
        if (!$data) {
            echo "Error returned from data queue receive: " . printArray(i5_error());
        } else {
            echo "Success getting data from data queue: " . printArray($data);
        }
        echo '<BR>';
        // Now a short-form DQ test
        // short-form description
        $littleDesc = array("Name" => "sometext", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 20);
        $littleInput = "Small text input";
        echo "<BR>About to send small short-form data structure to data queue {$queueName}.<BR>";
        // prepare
        $queue = i5_dtaq_prepare("{$demoLib}/{$queueName}", $littleDesc);
        if (!$queue) {
            echo "Error preparing data queue.<BR><BR>";
        }
        // send
        $success = i5_dtaq_send($queue, '', $littleInput);
        //
        if (!$success) {
            echo "Error returned from data queue send of small input: " . i5_error() . "<BR><BR>";
        } else {
            echo "Success sending the string '{$littleInput}' to data queue.<BR><BR>";
        }
        echo "<BR>About to receive small data structure from data queue {$queueName}.<BR>";
        $data = i5_dtaq_receive($queue);
        //, $operator = null, $key = '', $timeout = 0)
        // receive
        if (!$data) {
            echo "Error returned from data queue receive of small data: " . i5_error() . "<BR><BR>";
        } else {
            echo "Success getting small data from data queue: '{$data}'<BR><BR>";
        }
        echo '<BR><BR>';
    }
    if ($doObjectList) {
        echo h2('Object lists');
        echo "About to do object list with '{$demoLib}', '*ALL','*PGM'<BR>";
        // object list
        $list = i5_objects_list($demoLib, '*ALL', '*PGM', $conn);
        if (!$list) {
            echo 'Error getting object list: ' . printArray(i5_error()) . '<BR><BR>';
        } else {
            while ($listItem = i5_objects_list_read($list)) {
                echo printArray($listItem);
            }
            echo 'End of list. Error information: ' . printArray(i5_error()) . '<BR><BR>';
        }
        i5_objects_list_close($list);
    }
    if ($doPgmCallSimple) {
        echo h2('Program calls');
        echo 'Program call with simple parameters<BR>';
        $progname = "{$demoLib}/TESTSTP2";
        $desc = array(array("Name" => "code", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => "10"), array("Name" => "name", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => "10"));
        $desc = array(0 => array('type' => 0, 'name' => 'code', 'length' => 10, 'io' => 3), 1 => array('type' => 0, 'name' => 'name', 'length' => 10, 'io' => 3));
        echo "<b>About to call {$progname} with two char parameters.</b><BR>";
        $prog = i5_program_prepare($progname, $desc);
        if ($prog === FALSE) {
            $errorTab = i5_error();
            echo "Program prepare failed <br>\n";
            var_dump($errorTab);
            die;
        }
        /* Execute Program */
        $params = array("code" => "123", "name" => "ABC");
        $retvals = array("code" => "code", "name" => "name");
        $ret = i5_program_call($prog, $params, $retvals);
        if (function_exists('i5_output')) {
            extract(i5_output());
        }
        // i5_output() required if called in a function
        if ($ret === FALSE) {
            $errorTab = i5_error();
            echo "FAIL : i5_program_call failure message: " . $conn->getLastError() . " with code <br>";
            var_dump($errorTab);
        } else {
            // success
            echo "Success! The return values are: <br>", "Name: ", $name, "<br> Code: ", $code, "<br><BR>";
        }
        $close_val = i5_program_close($prog);
        if ($close_val === false) {
            print "FAIL : i5_program_close returned fales, closing an open prog.<br>\n";
            $errorTab = i5_error();
            var_dump($errorTab);
        }
    }
    // (simple call)
    // *** data structure call! ***
    if ($doPgmCallComplex) {
        echo '<BR>Program call with complex parameters<BR>';
        $progname = "{$demoLib}/RPCTEST";
        echo "<b>About to call {$progname} with data structure parameters.</b>";
        /*Call a program with parameters that include a DS */
        $desc = array(array("Name" => "P1", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10, "Count" => 5), array("Name" => "P2C", "IO" => I5_INOUT, "Type" => I5_TYPE_LONG, "Length" => 4), array("Name" => "P2", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 1, "CountRef" => "P2C"), array("DSName" => "PS", "Count" => 2, "DSParm" => array(array("Name" => "PS1", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10), array("Name" => "PS2", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10), array("Name" => "PS3", "IO" => I5_INOUT, "Type" => I5_TYPE_CHAR, "Length" => 10))));
        $prog = i5_program_prepare($progname, $desc);
        if ($prog === FALSE) {
            $errorTab = i5_error();
            echo "Program prepare failed <br>\n";
            var_dump($errorTab);
            die;
        }
        /* Execute Program */
        // The nameless elements in array.
        $params1 = array(array("PS1" => "test1", "PS2" => "test2", "PS3" => "test3"), array("PS1" => "test3", "PS2" => "test4", "PS3" => "test5"));
        $params2 = array("P1" => array("t1", "t2", "t3", "t4", "t5"), "P2C" => 2, "P2" => array("a", "b"), "PS" => $params1);
        $retvals = array("P1" => "P1", "PS" => "PS", "P2" => "P2", "P2C" => "P2C");
        $ret = i5_program_call($prog, $params2, $retvals);
        if (function_exists('i5_output')) {
            extract(i5_output());
        }
        // i5_output() required if called in a function
        if ($ret === FALSE) {
            $errorTab = i5_error();
            echo "FAIL : i5_program_call failure message: " . $conn->getLastError() . " with code <br>";
            var_dump($errorTab);
        } else {
            // success
            echo "<BR><BR>Success! The return values are: <br>";
            echo "P1 : " . printArray($P1) . "<BR>";
            echo "P2C : " . $P2C . "<BR>";
            echo "P2 : " . printArray($P2) . "<BR>";
            echo "PS: " . printArray($PS) . "<BR>";
        }
        $close_val = i5_program_close($prog);
        if ($close_val === false) {
            print "FAIL : i5_program_close returned fales, closing an open prog.<br>\n";
            $errorTab = i5_error();
            var_dump($errorTab);
        }
    }
    //(pgmcall complex)
    echo h2('Commands');
    $msg = 'HELLO';
    $cmdString = "SNDMSG MSG({$msg}) TOUSR({$user})";
    $start = microtime(true);
    $commandSuccessful = i5_command($cmdString, array(), array(), $conn);
    $end = microtime(true);
    $elapsed = $end - $start;
    echo "Ran command {$cmdString} using a single string in {$elapsed} seconds. Return: " . OkBad($commandSuccessful) . "<BR><BR>";
    $badUser = '******';
    $msg = 'HELLO';
    $cmdString = "SNDMSG MSG({$msg}) TOUSR({$badUser})";
    $start = microtime(true);
    $commandSuccessful = i5_command($cmdString, array(), array(), $conn);
    $end = microtime(true);
    $elapsed = $end - $start;
    echo "Ran command {$cmdString} using a single string to BAD user in {$elapsed} seconds.. Return: " . OkBad($commandSuccessful) . "<BR>";
    if (!$commandSuccessful) {
        echo "Error returned: " . printArray(i5_error()) . "<BR><BR>";
    }
    $cmdString = 'RTVJOBA';
    $input = array();
    // we want variable name ccsid to be created
    $output = array('ccsid' => array('ccsid', 'dec(5 0)'), 'dftccsid' => array('defaultCcsid', 'dec(5 0)'), 'curuser' => 'currentUser', 'nbr' => 'jobNumber', 'job' => 'jobName', 'user' => 'jobUser', 'usrlibl' => 'userLibl');
    $start = microtime(true);
    $commandSuccessful = i5_command($cmdString, $input, $output, $conn);
    if (function_exists('i5_output')) {
        extract(i5_output());
    }
    // i5_output() required if called in a function
    $end = microtime(true);
    $elapsed = $end - $start;
    echo "Ran command {$cmdString} with an output array in {$elapsed} seconds. Return: " . OkBad($commandSuccessful) . " with CCSID '{$ccsid}', default CCSID '{$defaultCcsid}', current user '{$currentUser}', job name '{$jobName}', job number '{$jobNumber}', job user '{$jobUser}', with user liblist '{$userLibl}'.<BR><BR>";
    // Note: old toolkit cannot get interactive output of this sort (DSPJOBLOG). This is additional functionality of the new toolkit.
    $cmdString = "DSPJOBLOG JOB({$jobNumber}/{$jobUser}/{$jobName})";
    echo "About to run " . $cmdString . ".<BR>";
    $conn->setToolkitServiceParams(array('plugSize' => '5M'));
    // bigger to handle large joblog
    $interactiveOutput = $conn->CLInteractiveCommand($cmdString);
    $conn->setToolkitServiceParams(array('plugSize' => '512K'));
    // put back to default
    echo printArray($interactiveOutput) . "<BR><BR>";
    $msg = 'HELLO_WITH_INPUTS_ARRAY';
    $cmdString = "SNDMSG";
    $inputs = array('MSG' => $msg, 'TOUSR' => $user);
    $commandSuccessful = i5_command($cmdString, $inputs);
    echo "Ran command {$cmdString} with an input array: " . printArray($inputs) . "Return:  " . OkBad($commandSuccessful) . ".<BR><BR>";
    $msg = "MixedCaseNoSpaces";
    $cmdString = "SNDMSG";
    $inputs = array('MSG' => $msg, 'TOUSR' => $user);
    $commandSuccessful = i5_command($cmdString, $inputs);
    echo "Ran command {$cmdString} with an input array: " . printArray($inputs) . "Return:  " . OkBad($commandSuccessful) . ".<BR><BR>";
    $msg = "Davey Jones embedded spaces without quotes--caused error in old toolkit";
    $cmdString = "SNDMSG";
    $inputs = array('MSG' => $msg, 'TOUSR' => $user);
    $commandSuccessful = i5_command($cmdString, $inputs);
    echo "Ran command {$cmdString} with an input array: " . printArray($inputs) . "Return:  " . OkBad($commandSuccessful) . ".<BR><BR>";
    $msg = "O'flanagan single quote--caused error in old toolkit";
    $cmdString = "SNDMSG";
    $inputs = array('MSG' => $msg, 'TOUSR' => $user);
    $commandSuccessful = i5_command($cmdString, $inputs);
    echo "Ran command {$cmdString} with an input array: " . printArray($inputs) . "Return: " . OkBad($commandSuccessful) . ".<BR><BR>";
    echo h2('Error functions');
    echo "Let's test i5_errormsg() and i5_errno()<BR>Get last error message: " . i5_errormsg();
    echo "<BR>Get last error number: " . i5_errno() . "<BR><BR>";
    echo h2('Get system value');
    $start = microtime(true);
    $date = i5_get_system_value('QDATE');
    $end = microtime(true);
    $elapsed = $end - $start;
    echo "QDATE system value: '{$date}', obtained in {$elapsed} seconds.<BR>";
    echo h2('Data areas');
    $dtaara = "{$demoLib}/ALLEYOOP";
    $ret = i5_data_area_create($dtaara, 72);
    if ($ret) {
        echo "Created data area {$dtaara} successfully.<BR>";
    } else {
        echo "Could not create data area {$dtaara}.<BR>";
    }
    $ret = i5_data_area_delete($dtaara);
    if ($ret) {
        echo "Deleted data area {$dtaara} successfully.<BR>";
    } else {
        echo "Could not delete data area {$dtaara}.<BR>";
    }
    $dtaara = 'BETTYBOOP';
    $ret = i5_data_area_create($dtaara, 100);
    if ($ret) {
        echo "Created data area {$dtaara} successfully.<BR>";
    } else {
        echo "Could not create data area {$dtaara}. Reason: " . i5_errormsg() . " (it may already exist)<BR>";
    }
    $dtaara = 'BETTYBOOP';
    $stringToWrite = 'Very nice';
    $ret = i5_data_area_write($dtaara, $stringToWrite, 5, 20);
    if ($ret) {
        echo "Wrote '{$stringToWrite}' to data area {$dtaara} successfully.<BR>";
        // try to read now.
        $start = microtime(true);
        $readData = i5_data_area_read($dtaara, 3, 40);
        $end = microtime(true);
        $elapsed = $end - $start;
        if ($readData) {
            echo "Read a portion of '{$readData}' from data area {$dtaara} successfully in {$elapsed} seconds.<BR>";
        } else {
            echo "Could not read from data area {$dtaara}. Reason: " . i5_errormsg() . "<BR>";
        }
        // try to read now.
        $start = microtime(true);
        $readData = i5_data_area_read($dtaara);
        // the whole thing
        $end = microtime(true);
        $elapsed = $end - $start;
        if ($readData) {
            echo "Read ALL of '{$readData}' from data area {$dtaara} successfully in {$elapsed} seconds.<BR>";
        } else {
            echo "Could not read from data area {$dtaara}. Reason: " . i5_errormsg() . "<BR>";
        }
    } else {
        echo "Could not write to data area {$dtaara}. Reason: " . i5_errormsg() . "<BR>";
    }
    // job list
    if ($doJobLists) {
        echo h2('Job lists');
        echo "About to get up to 5 jobs with jobname ZENDSVR (can also do I5_JOBUSER, I5_USERNAME, I5_JOBNUMBER, and I5_JOBTYPE).<BR>";
        $list = i5_job_list(array(I5_JOBNAME => 'ZENDSVR'));
        if (!$list) {
            echo 'Error getting job list: ' . printArray(i5_error()) . '<BR>';
        } else {
            $jobCount = 0;
            while (($listItem = i5_job_list_read($list)) && ++$jobCount <= 5) {
                echo printArray($listItem) . '<BR>';
            }
            echo 'End of list.<BR><BR>';
        }
        i5_job_list_close($list);
        // Get info about current job
        echo "Getting information about current job.<BR>";
        $list = i5_job_list();
        //array(I5_USERNAME=>'*ALL'), $conn);
        if (!$list) {
            echo 'Error getting job list: ' . printArray(i5_error()) . '<BR>';
        } else {
            // should be only one for current job.
            $listItem = i5_job_list_read($list);
            echo "<BR>list item for current job: " . printArray($listItem) . "<BR><BR>";
            echo "Job name: {$listItem[I5_JOB_NAME]} user: {$listItem[I5_JOB_USER_NAME]} job number: {$listItem[I5_JOB_NUMBER]}<BR><BR>";
        }
        i5_job_list_close($list);
    }
    if ($doSpooledFiles) {
        echo h2('Spooled Files');
        $splUser = '******';
        echo "Get up to 5 spooled files for user {$splUser}<BR>";
        $list = i5_spool_list(array(I5_USERNAME => $splUser), $conn);
        if (!$list) {
            echo 'Error getting spool list: ' . printArray(i5_error()) . '<BR>';
        } else {
            $spoolCount = 0;
            while (($listItem = i5_spool_list_read($list)) && ++$spoolCount <= 5) {
                echo "<BR>list item: " . printArray($listItem) . "<BR>";
                echo '<BR>Output data for this spool file: <BR>';
                $data = i5_spool_get_data($listItem['SPLFNAME'], $listItem['JOBNAME'], $listItem['USERNAME'], $listItem['JOBNBR'], $listItem['SPLFNBR']);
                if (!$data) {
                    echo '<BR>No spool data. Error info: ' . printArray(i5_error()) . '<BR>';
                } else {
                    echo "<PRE>{$data}</PRE><BR>";
                }
            }
        }
        i5_spool_list_close($list);
        $outq = 'QGPL/QPRINT';
        echo "<BR>Get up to 5 spooled files for outq {$outq} (may get permissions message if user's authority is insufficient)<BR>";
        $list = i5_spool_list(array(I5_OUTQ => $outq), $conn);
        if (!$list) {
            echo 'Error getting spool list: ' . printArray(i5_error()) . '<BR>';
        } else {
            $spoolCount = 0;
            while (($listItem = i5_spool_list_read($list)) && ++$spoolCount <= 5) {
                echo "<BR>list item: " . printArray($listItem) . "<BR>";
                echo '<BR>Output data for this spool file: <BR>';
                $data = i5_spool_get_data($listItem['SPLFNAME'], $listItem['JOBNAME'], $listItem['USERNAME'], $listItem['JOBNBR'], $listItem['SPLFNBR']);
                if (!$data) {
                    echo '<BR>No spool data. Error info: ' . printArray(i5_error()) . '<BR>';
                } else {
                    echo "<PRE>{$data}</PRE><BR>";
                }
            }
        }
        i5_spool_list_close($list);
    }
    // job log.
    if ($doJobLogs) {
        echo h2('Job logs');
        // Try current job. Good, it works, except for not enough data coming back from PHP wrapper.
        echo "About to get joblog (partial data) for current job<BR>";
        $list = i5_jobLog_list();
        if (!$list) {
            echo 'No joblogs found<BR>';
        } else {
            while ($listItem = i5_jobLog_list_read($list)) {
                echo printArray($listItem);
            }
            echo '<BR>End of list.<BR><BR>';
        }
        i5_jobLog_list_close($list);
    }
    if ($doAdoptAuthority) {
        echo h2('Adopt authority');
        // Note: only works if you've defined $user and $testPw, and created the user profile.
        echo "About to adopt authority to user {$user}<BR>";
        $start = microtime(true);
        $success = i5_adopt_authority($user, $testPw);
        $end = microtime(true);
        $elapsed = $end - $start;
        if (!$success) {
            echo "Error adopting authority: " . printArray(i5_error()) . "<BR>";
        } else {
            echo "Success adopting authority in {$elapsed} seconds<BR>";
            echo "About to check current user and other variables after adopting authority.<BR>";
            $cmdString = 'RTVJOBA';
            $input = array();
            $output = array('ccsid' => array('ccsid', 'dec(5 0)'), 'dftccsid' => array('defaultCcsid', 'dec(5 0)'), 'curuser' => 'currentUser', 'nbr' => 'jobNumber', 'job' => 'jobName', 'user' => 'jobUser', 'usrlibl' => 'userLibl');
            $commandSuccessful = i5_command($cmdString, $input, $output, $conn);
            if (function_exists('i5_output')) {
                extract(i5_output());
            }
            // i5_output() required if called in a function
            echo "Ran command {$cmdString}. Return: " . OkBad($commandSuccessful) . " with original job user '{$jobUser}', current user '{$currentUser}', CCSID '{$ccsid}', default CCSID '{$defaultCcsid}', job name '{$jobName}', job number '{$jobNumber}', with user liblist '{$userLibl}'.<BR><BR>";
        }
    }
    $ret = i5_close($conn);
    //$conn optional
    echo h2('Connection close');
    echo "Closed i5 connection. return status: " . OkBad($ret) . ".";
    echo h1('End of script');
    ?>
    </html>
<?php 
}