Overview

Namespaces

  • Neodynamic
    • SDK
      • Web
  • None
  • PHP
  • phpseclib
    • Crypt
    • File
      • ASN1
    • Math

Classes

  • ClientPrinter
  • ClientPrintJob
  • ClientPrintJobGroup
  • DefaultPrinter
  • Duplex
  • EncryptMetadata
  • InstalledPrinter
  • NetworkPrinter
  • ParallelPortPrinter
  • PrintFile
  • PrintFileDOC
  • PrintFilePDF
  • PrintFileTIF
  • PrintFileTXT
  • PrintFileXLS
  • PrintOrientation
  • PrintRotation
  • SecUtils
  • SerialPortHandshake
  • SerialPortParity
  • SerialPortPrinter
  • SerialPortStopBits
  • Sizing
  • TextAlignment
  • UserSelectedPrinter
  • Utils
  • WebClientPrint
  • Overview
  • Namespace
  • Class
  • Tree
   1: <?php
   2: 
   3: namespace Neodynamic\SDK\Web;
   4: use Exception;
   5: use ZipArchive;
   6: 
   7: //phpseclib is required for Encryption and Password Protected file printing feature
   8: include 'phpseclib/Math/BigInteger.php';
   9: include 'phpseclib/Crypt/Hash.php';
  10: include 'phpseclib/Crypt/Random.php';
  11: include 'phpseclib/Crypt/Base.php';
  12: include 'phpseclib/Crypt/RSA.php';
  13: include 'phpseclib/Crypt/Rijndael.php';
  14: include 'phpseclib/Crypt/AES.php';
  15: 
  16: // Setting WebClientPrint
  17: WebClientPrint::$licenseOwner = '';
  18: WebClientPrint::$licenseKey = '';
  19: 
  20: //Set wcpcache folder RELATIVE to WebClientPrint.php file
  21: //FILE WRITE permission on this folder is required!!!
  22: WebClientPrint::$wcpCacheFolder = 'wcpcache/';
  23: 
  24: /**
  25:  * WebClientPrint provides functions for registering the "WebClientPrint for PHP" solution 
  26:  * script code in PHP web pages as well as for processing client requests and managing the
  27:  * internal cache.
  28:  * 
  29:  * @author Neodynamic <http://neodynamic.com/support>
  30:  * @copyright (c) 2021, Neodynamic SRL
  31:  * @license http://neodynamic.com/eula Neodynamic EULA
  32:  */
  33: class WebClientPrint {
  34:    
  35:     const VERSION = '6.0.0.0';
  36:     const CLIENT_PRINT_JOB = 'clientPrint';
  37:     const WCP = 'WEB_CLIENT_PRINT';
  38:     const WCP_SCRIPT_AXD_GET_PRINTERS = 'getPrinters';
  39:     const WCP_SCRIPT_AXD_GET_PRINTERSINFO = 'getPrintersInfo';
  40:     const WCPP_SET_PRINTERS = 'printers';
  41:     const WCPP_SET_PRINTERSINFO = 'printersInfo';
  42:     const WCP_SCRIPT_AXD_GET_WCPPVERSION = 'getWcppVersion';
  43:     const WCPP_SET_VERSION = 'wcppVer';
  44:     const GEN_WCP_SCRIPT_URL = 'u';
  45:     const GEN_DETECT_WCPP_SCRIPT = 'd';
  46:     const SID = 'sid';
  47:     const PING = 'wcppping';
  48:     
  49:     const WCP_CACHE_WCPP_INSTALLED = 'WCPP_INSTALLED';
  50:     const WCP_CACHE_WCPP_VER = 'WCPP_VER';
  51:     const WCP_CACHE_PRINTERS = 'PRINTERS';
  52:     const WCP_CACHE_PRINTERSINFO = 'PRINTERSINFO';
  53:     
  54:     
  55:     /**
  56:      * Gets or sets the License Owner
  57:      * @var string 
  58:      */
  59:     static $licenseOwner = '';
  60:     /**
  61:      * Gets or sets the License Key
  62:      * @var string
  63:      */
  64:     static $licenseKey = '';
  65:     /**
  66:      * Gets or sets the ABSOLUTE URL to WebClientPrint.php file
  67:      * @var string
  68:      */
  69:     static $webClientPrintAbsoluteUrl = '';
  70:     /**
  71:      * Gets or sets the wcpcache folder URL RELATIVE to WebClientPrint.php file. 
  72:      * FILE WRITE permission on this folder is required!!!
  73:      * @var string
  74:      */
  75:     static $wcpCacheFolder = '';
  76:     
  77:     /**
  78:      * Adds a new entry to the built-in file system cache. 
  79:      * @param string $sid The user's session id
  80:      * @param string $key The cache entry key
  81:      * @param string $val The data value to put in the cache
  82:      * @throws Exception
  83:      */
  84:     public static function cacheAdd($sid, $key, $val){
  85:         if (Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
  86:             throw new Exception('WebClientPrint wcpCacheFolder is missing, please specify it.');
  87:         }
  88:         if (Utils::isNullOrEmptyString($sid)){
  89:             throw new Exception('WebClientPrint FileName cache is missing, please specify it.');
  90:         }
  91:         $cacheFileName = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/').$sid.'.wcpcache';
  92:         $dataWCPP_VER = '';
  93:         $dataPRINTERS = '';
  94:         $dataPRINTERSINFO = '';
  95:             
  96:         if(file_exists($cacheFileName)){
  97:             $cache_info = parse_ini_file($cacheFileName);
  98:             
  99:             $dataWCPP_VER = $cache_info[self::WCP_CACHE_WCPP_VER];
 100:             $dataPRINTERS = $cache_info[self::WCP_CACHE_PRINTERS];
 101:             $dataPRINTERSINFO = $cache_info[self::WCP_CACHE_PRINTERSINFO];
 102:         }
 103:         
 104:         if ($key === self::WCP_CACHE_WCPP_VER){
 105:             $dataWCPP_VER = self::WCP_CACHE_WCPP_VER.'='.'"'.$val.'"';
 106:             $dataPRINTERS = self::WCP_CACHE_PRINTERS.'='.'"'.$dataPRINTERS.'"';
 107:             $dataPRINTERSINFO = self::WCP_CACHE_PRINTERSINFO.'='.'"'.$dataPRINTERSINFO.'"';
 108:         } else if ($key === self::WCP_CACHE_PRINTERS){
 109:             $dataWCPP_VER = self::WCP_CACHE_WCPP_VER.'='.'"'.$dataWCPP_VER.'"';
 110:             $dataPRINTERS = self::WCP_CACHE_PRINTERS.'='.'"'.$val.'"';
 111:             $dataPRINTERSINFO = self::WCP_CACHE_PRINTERSINFO.'='.'"'.$dataPRINTERSINFO.'"';
 112:         } else if ($key === self::WCP_CACHE_PRINTERSINFO){
 113:             $dataWCPP_VER = self::WCP_CACHE_WCPP_VER.'='.'"'.$dataWCPP_VER.'"';
 114:             $dataPRINTERS = self::WCP_CACHE_PRINTERS.'='.'"'.$dataPRINTERS.'"';
 115:             $dataPRINTERSINFO = self::WCP_CACHE_PRINTERSINFO.'='.'"'.$val.'"';
 116:         }
 117: 
 118:         $data = $dataWCPP_VER.chr(13).chr(10).$dataPRINTERS.chr(13).chr(10).$dataPRINTERSINFO;
 119:         $handle = fopen($cacheFileName, 'w') or die('Cannot open file:  '.$cacheFileName);  
 120:         fwrite($handle, $data);
 121:         fclose($handle);
 122:         
 123:     }
 124:     
 125:     /**
 126:      * Gets a value from the built-in file system cache based on the specified sid & key 
 127:      * @param string $sid The user's session id
 128:      * @param string $key The cache entry key
 129:      * @return string Returns the value from the cache for the specified sid & key if it's found; or an empty string otherwise.
 130:      * @throws Exception
 131:      */
 132:     public static function cacheGet($sid, $key){
 133:         if (Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
 134:             throw new Exception('WebClientPrint wcpCacheFolder is missing, please specify it.');
 135:         }
 136:         if (Utils::isNullOrEmptyString($sid)){
 137:             throw new Exception('WebClientPrint FileName cache is missing, please specify it.');
 138:         }
 139:         $cacheFileName = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/').$sid.'.wcpcache';
 140:         if(file_exists($cacheFileName)){
 141:             $cache_info = parse_ini_file($cacheFileName, FALSE, INI_SCANNER_RAW);
 142:                 
 143:             if($key===self::WCP_CACHE_WCPP_VER || $key===self::WCP_CACHE_WCPP_INSTALLED){
 144:                 return $cache_info[self::WCP_CACHE_WCPP_VER];
 145:             }else if($key===self::WCP_CACHE_PRINTERS){
 146:                 return $cache_info[self::WCP_CACHE_PRINTERS];
 147:             }else if($key===self::WCP_CACHE_PRINTERSINFO){
 148:                 return $cache_info[self::WCP_CACHE_PRINTERSINFO];
 149:             }else{
 150:                 return '';
 151:             }
 152:         }else{
 153:             return '';
 154:         }
 155:     }
 156:     
 157:     /**
 158:      * Cleans the built-in file system cache
 159:      * @param integer $minutes The number of minutes after any files on the cache will be removed.
 160:      */
 161:     public static function cacheClean($minutes){
 162:         if (!Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
 163:             $cacheDir = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/');
 164:             if ($handle = opendir($cacheDir)) {
 165:                  while (false !== ($file = readdir($handle))) {
 166:                     if ($file!='.' && $file!='..' && (time()-filectime($cacheDir.$file)) > (60*$minutes)) {
 167:                         unlink($cacheDir.$file);
 168:                     }
 169:                  }
 170:                  closedir($handle);
 171:             }
 172:         }
 173:     }
 174:     
 175:     /**
 176:      * Returns script code for detecting whether WCPP is installed at the client machine.
 177:      *
 178:      * The WCPP-detection script code ends with a 'success' or 'failure' status.
 179:      * You can handle both situation by creating two javascript functions which names 
 180:      * must be wcppDetectOnSuccess() and wcppDetectOnFailure(). 
 181:      * These two functions will be automatically invoked by the WCPP-detection script code.
 182:      * 
 183:      * The WCPP-detection script uses a delay time variable which by default is 10000 ms (10 sec). 
 184:      * You can change it by creating a javascript global variable which name must be wcppPingDelay_ms. 
 185:      * For example, to use 5 sec instead of 10, you should add this to your script: 
 186:      *   
 187:      * var wcppPingDelay_ms = 5000;
 188:      *    
 189:      * @param string $webClientPrintControllerAbsoluteUrl The Absolute URL to the WebClientPrintController file.
 190:      * @param string $sessionID The current Session ID.
 191:      * @return string A [script] tag linking to the WCPP-detection script code.
 192:      * @throws Exception
 193:      */
 194:     public static function createWcppDetectionScript($webClientPrintControllerAbsoluteUrl, $sessionID){
 195:         
 196:         if (Utils::isNullOrEmptyString($webClientPrintControllerAbsoluteUrl) || 
 197:             !Utils::strStartsWith($webClientPrintControllerAbsoluteUrl, 'http')){
 198:             throw new Exception('WebClientPrintController absolute URL is missing, please specify it.');
 199:         }
 200:         if (Utils::isNullOrEmptyString($sessionID)){
 201:             throw new Exception('Session ID is missing, please specify it.');
 202:         }
 203:         
 204:         $url = $webClientPrintControllerAbsoluteUrl.'?'.self::GEN_DETECT_WCPP_SCRIPT.'='.$sessionID;
 205:         return '<script src="'.$url.'" type="text/javascript"></script>';
 206:          
 207:     }
 208:     
 209:     
 210:     /**
 211:      * Returns a [script] tag linking to the WebClientPrint script code by using 
 212:      * the specified URL for the client print job generation.
 213:      * 
 214:      * @param string $webClientPrintControllerAbsoluteUrl The Absolute URL to the WebClientPrintController file.
 215:      * @param string $clientPrintJobAbsoluteUrl The Absolute URL to the PHP file that creates ClientPrintJob objects.
 216:      * @paran string $sessionID The current Session ID.
 217:      * @return string A [script] tag linking to the WebClientPrint script code by using the specified URL for the client print job generation.
 218:      * @throws Exception
 219:      */
 220:     public static function createScript($webClientPrintControllerAbsoluteUrl, $clientPrintJobAbsoluteUrl, $sessionID){
 221:         if (Utils::isNullOrEmptyString($webClientPrintControllerAbsoluteUrl) || 
 222:             !Utils::strStartsWith($webClientPrintControllerAbsoluteUrl, 'http')){
 223:             throw new Exception('WebClientPrintController absolute URL is missing, please specify it.');
 224:         }
 225:         if (Utils::isNullOrEmptyString($clientPrintJobAbsoluteUrl) || 
 226:             !Utils::strStartsWith($clientPrintJobAbsoluteUrl, 'http')){
 227:             throw new Exception('ClientPrintJob absolute URL is missing, please specify it.');
 228:         }
 229:         if (Utils::isNullOrEmptyString($sessionID)){
 230:             throw new Exception('Session ID is missing, please specify it.');
 231:         }
 232:         
 233:         
 234:         $wcpHandler = $webClientPrintControllerAbsoluteUrl.'?';
 235:         $wcpHandler .= self::VERSION;
 236:         $wcpHandler .= '&';
 237:         $wcpHandler .= microtime(true);
 238:         $wcpHandler .= '&sid=';
 239:         $wcpHandler .= $sessionID;
 240:         $wcpHandler .= '&'.self::GEN_WCP_SCRIPT_URL.'=';
 241:         $wcpHandler .= base64_encode($clientPrintJobAbsoluteUrl);
 242:         return '<script src="'.$wcpHandler.'" type="text/javascript"></script>';
 243:     }
 244:     
 245:     
 246:     /**
 247:      * Generates the WebClientPrint scripts based on the specified query string. Result is stored in the HTTP Response Content
 248:      * 
 249:      * @param type $webClientPrintControllerAbsoluteUrl The Absolute URL to the WebClientPrintController file.
 250:      * @param type $queryString The Query String from current HTTP Request.
 251:      */
 252:     public static function generateScript($webClientPrintControllerAbsoluteUrl, $queryString)
 253:     {
 254:         if (Utils::isNullOrEmptyString($webClientPrintControllerAbsoluteUrl) || 
 255:             !Utils::strStartsWith($webClientPrintControllerAbsoluteUrl, 'http')){
 256:             throw new Exception('WebClientPrintController absolute URL is missing, please specify it.');
 257:         }
 258:         
 259:         parse_str($queryString, $qs);
 260:     
 261:         if(isset($qs[self::GEN_DETECT_WCPP_SCRIPT])){
 262:             
 263:             $curSID = $qs[self::GEN_DETECT_WCPP_SCRIPT];
 264:             $dynamicIframeId = 'i'.substr(uniqid(), 0, 3);
 265:             $absoluteWcpAxd = $webClientPrintControllerAbsoluteUrl.'?'.self::SID.'='.$curSID;
 266:             
 267:             $s1 = 'dmFyIGpzV0NQUD0oZnVuY3Rpb24oKXt2YXIgc2V0PDw8LU5FTy1IVE1MLUlELT4+Pj1mdW5jdGlvbigpe3ZhciBlbD1kb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnPDw8LU5FTy1IVE1MLUlELT4+PicpO2lmKHdpbmRvdy5jaHJvbWUpe2VsLmhyZWY9J3dlYmNsaWVudHByaW50dmk6Jythcmd1bWVudHNbMF07dmFyIGV2T2JqPWRvY3VtZW50LmNyZWF0ZUV2ZW50KCdNb3VzZUV2ZW50cycpO2V2T2JqLmluaXRFdmVudCgnY2xpY2snLHRydWUsdHJ1ZSk7ZWwuZGlzcGF0Y2hFdmVudChldk9iail9ZWxzZXtlbC5zcmM9J3dlYmNsaWVudHByaW50dmk6Jythcmd1bWVudHNbMF19fTtyZXR1cm57aW5pdDpmdW5jdGlvbigpe2lmKHdpbmRvdy5jaHJvbWUpe3ZhciBhRWw9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO2FFbC5pZD0nPDw8LU5FTy1IVE1MLUlELT4+Pic7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChhRWwpfWVsc2V7dmFyIGlmRWw9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaWZyYW1lJyk7aWZFbC5pZD0nPDw8LU5FTy1IVE1MLUlELT4+Pic7aWZFbC5uYW1lPSc8PDwtTkVPLUhUTUwtSUQtPj4+JztpZkVsLndpZHRoPTE7aWZFbC5oZWlnaHQ9MTtpZkVsLnN0eWxlLnZpc2liaWxpdHk9J2hpZGRlbic7aWZFbC5zdHlsZS5wb3NpdGlvbj0nYWJzb2x1dGUnO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoaWZFbCl9fSxwaW5nOmZ1bmN0aW9uKCl7c2V0PDw8LU5FTy1IVE1MLUlELT4+PignPDw8LU5FTy1QSU5HLVVSTC0+Pj4nKyhhcmd1bWVudHMubGVuZ3RoPT0xPycmJythcmd1bWVudHNbMF06JycpKTt2YXIgZGVsYXlfbXM9KHR5cGVvZiB3Y3BwUGluZ0RlbGF5X21zPT09J3VuZGVmaW5lZCcpPzA6d2NwcFBpbmdEZWxheV9tcztpZihkZWxheV9tcz4wKXtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7dmFyIHhocj1uZXcgWE1MSHR0cFJlcXVlc3QoKTt4aHIub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7aWYoeGhyLnJlYWR5U3RhdGU9PTQmJnhoci5zdGF0dXM9PTIwMCl7dmFyIGRhdGE9eGhyLnJlc3BvbnNlVGV4dDtpZihkYXRhLmxlbmd0aD4wKXt3Y3BwRGV0ZWN0T25TdWNjZXNzKGRhdGEpfWVsc2V7d2NwcERldGVjdE9uRmFpbHVyZSgpfX19O3hoci5vcGVuKCdHRVQnLCc8PDwtTkVPLVVTRVItSEFTLVdDUFAtPj4+Jyk7eGhyLnNlbmQoKX0sZGVsYXlfbXMpfWVsc2V7dmFyIGZuY1dDUFA9c2V0SW50ZXJ2YWwoZ2V0V0NQUFZlcix3Y3BwUGluZ1RpbWVvdXRTdGVwX21zKTt2YXIgd2NwcF9jb3VudD0wO2Z1bmN0aW9uIGdldFdDUFBWZXIoKXtpZih3Y3BwX2NvdW50PD13Y3BwUGluZ1RpbWVvdXRfbXMpe3ZhciB4aHI9bmV3IFhNTEh0dHBSZXF1ZXN0KCk7eGhyLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpe2lmKHhoci5yZWFkeVN0YXRlPT00JiZ4aHIuc3RhdHVzPT0yMDApe3ZhciBkYXRhPXhoci5yZXNwb25zZVRleHQ7aWYoZGF0YS5sZW5ndGg+MCl7Y2xlYXJJbnRlcnZhbChmbmNXQ1BQKTt3Y3BwRGV0ZWN0T25TdWNjZXNzKGRhdGEpfX19O3hoci5vcGVuKCdHRVQnLCc8PDwtTkVPLVVTRVItSEFTLVdDUFAtPj4+Jyk7eGhyLnNlbmQoeydfJzoobmV3IERhdGUoKS5nZXRUaW1lKCkpfSk7d2NwcF9jb3VudCs9d2NwcFBpbmdUaW1lb3V0U3RlcF9tc31lbHNle2NsZWFySW50ZXJ2YWwoZm5jV0NQUCk7d2NwcERldGVjdE9uRmFpbHVyZSgpfX19fX19KSgpO2RvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLGZ1bmN0aW9uKCl7anNXQ1BQLmluaXQoKTtqc1dDUFAucGluZygpfSk7';
 268:                     
 269:             $s2 = base64_decode($s1);
 270:             $s2 = str_replace('<<<-NEO-HTML-ID->>>', $dynamicIframeId, $s2);
 271:             $s2 = str_replace('<<<-NEO-PING-URL->>>', $absoluteWcpAxd.'&'.self::PING, $s2);
 272:             $s2 = str_replace('<<<-NEO-USER-HAS-WCPP->>>', $absoluteWcpAxd, $s2);
 273:             
 274:             return $s2;
 275:             
 276:         }else if(isset($qs[self::GEN_WCP_SCRIPT_URL])){
 277:             
 278:             $clientPrintJobUrl = base64_decode($qs[self::GEN_WCP_SCRIPT_URL]);
 279:             if (strpos($clientPrintJobUrl, '?')>0){
 280:                 $clientPrintJobUrl .= '&';
 281:             }else{
 282:                 $clientPrintJobUrl .= '?';
 283:             }
 284:             $clientPrintJobUrl .= self::CLIENT_PRINT_JOB;
 285:             $absoluteWcpAxd = $webClientPrintControllerAbsoluteUrl;
 286:             $wcppGetPrintersParam = '-getPrinters:'.$absoluteWcpAxd.'?'.self::WCP.'&'.self::SID.'=';
 287:             $wcpHandlerGetPrinters = $absoluteWcpAxd.'?'.self::WCP.'&'.self::WCP_SCRIPT_AXD_GET_PRINTERS.'&'.self::SID.'=';
 288:             $wcppGetPrintersInfoParam = '-getPrintersInfo:'.$absoluteWcpAxd.'?'.self::WCP.'&'.self::SID.'=';
 289:             $wcpHandlerGetPrintersInfo = $absoluteWcpAxd.'?'.self::WCP.'&'.self::WCP_SCRIPT_AXD_GET_PRINTERSINFO.'&'.self::SID.'=';
 290:             $wcppGetWcppVerParam = '-getWcppVersion:'.$absoluteWcpAxd.'?'.self::WCP.'&'.self::SID.'=';
 291:             $wcpHandlerGetWcppVer = $absoluteWcpAxd.'?'.self::WCP.'&'.self::WCP_SCRIPT_AXD_GET_WCPPVERSION.'&'.self::SID.'=';
 292:             $sessionIDVal = $qs[self::SID];
 293:         
 294:             $s1 = 'dmFyIGpzV2ViQ2xpZW50UHJpbnQ9KGZ1bmN0aW9uKCl7dmFyIGdldFJlcT1mdW5jdGlvbih1cmwsb25TdWNjZXNzLG9uRmFpbHVyZSxvbkNsZWFuKXt2YXIgeGhyPW5ldyBYTUxIdHRwUmVxdWVzdCgpO3hoci5vbnJlYWR5c3RhdGVjaGFuZ2U9ZnVuY3Rpb24oKXtpZih4aHIucmVhZHlTdGF0ZT09NCYmeGhyLnN0YXR1cz09MjAwKXt2YXIgZGF0YT14aHIucmVzcG9uc2VUZXh0O2lmKGRhdGEubGVuZ3RoPjApe2lmKG9uQ2xlYW4pY2xlYXJJbnRlcnZhbChvbkNsZWFuKTtpZihvblN1Y2Nlc3Mpb25TdWNjZXNzKGRhdGEpfWVsc2V7aWYob25GYWlsdXJlKW9uRmFpbHVyZSgpfX19O3hoci5vcGVuKCdHRVQnLHVybCk7eGhyLnNlbmQoeydfJzoobmV3IERhdGUoKS5nZXRUaW1lKCkpfSl9O3ZhciBzZXRBPWZ1bmN0aW9uKCl7dmFyIGVfaWQ9J2lkXycrbmV3IERhdGUoKS5nZXRUaW1lKCk7aWYod2luZG93LmNocm9tZSl7dmFyIGFFbD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7YUVsLmlkPWVfaWQ7YUVsLmhyZWY9J3dlYmNsaWVudHByaW50dmk6Jythcmd1bWVudHNbMF07dmFyIGV2T2JqPWRvY3VtZW50LmNyZWF0ZUV2ZW50KCdNb3VzZUV2ZW50cycpO2V2T2JqLmluaXRFdmVudCgnY2xpY2snLHRydWUsdHJ1ZSk7YUVsLmRpc3BhdGNoRXZlbnQoZXZPYmopO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoYUVsKX1lbHNle3ZhciBpZkVsPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lmcmFtZScpO2lmRWwuaWQ9ZV9pZDtpZkVsLm5hbWU9ZV9pZDtpZkVsLndpZHRoPTE7aWZFbC5oZWlnaHQ9MTtpZkVsLnN0eWxlLnZpc2liaWxpdHk9J2hpZGRlbic7aWZFbC5zdHlsZS5wb3NpdGlvbj0nYWJzb2x1dGUnO2lmRWwuc3JjPSd3ZWJjbGllbnRwcmludHZpOicrYXJndW1lbnRzWzBdO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoaWZFbCl9c2V0VGltZW91dChmdW5jdGlvbigpe2RvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoZV9pZCkpfSw1MDAwKX07cmV0dXJue3ByaW50OmZ1bmN0aW9uKCl7c2V0QSgnVVJMX1BSSU5UX0pPQicrKGFyZ3VtZW50cy5sZW5ndGg9PTE/JyYnK2FyZ3VtZW50c1swXTonJykpfSxnZXRQcmludGVyczpmdW5jdGlvbigpe3NldEEoJ1VSTF9XQ1BfQVhEX1dJVEhfR0VUX1BSSU5URVJTX0NPTU1BTkQnKyc8PDwtTkVPLVNFU1NJT04tSUQtPj4+Jyk7dmFyIGRlbGF5X21zPSh0eXBlb2Ygd2NwcEdldFByaW50ZXJzRGVsYXlfbXM9PT0ndW5kZWZpbmVkJyk/MDp3Y3BwR2V0UHJpbnRlcnNEZWxheV9tcztpZihkZWxheV9tcz4wKXtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7Z2V0UmVxKCdVUkxfV0NQX0FYRF9HRVRfUFJJTlRFUlMnKyc8PDwtTkVPLVNFU1NJT04tSUQtPj4+Jyx3Y3BHZXRQcmludGVyc09uU3VjY2Vzcyx3Y3BHZXRQcmludGVyc09uRmFpbHVyZSl9LGRlbGF5X21zKX1lbHNle3ZhciBmbmNHZXRQcmludGVycz1zZXRJbnRlcnZhbChnZXRDbGllbnRQcmludGVycyx3Y3BwR2V0UHJpbnRlcnNUaW1lb3V0U3RlcF9tcyk7dmFyIHdjcHBfY291bnQ9MDtmdW5jdGlvbiBnZXRDbGllbnRQcmludGVycygpe2lmKHdjcHBfY291bnQ8PXdjcHBHZXRQcmludGVyc1RpbWVvdXRfbXMpe2dldFJlcSgnVVJMX1dDUF9BWERfR0VUX1BSSU5URVJTJysnPDw8LU5FTy1TRVNTSU9OLUlELT4+Picsd2NwR2V0UHJpbnRlcnNPblN1Y2Nlc3MsbnVsbCxmbmNHZXRQcmludGVycyk7d2NwcF9jb3VudCs9d2NwcEdldFByaW50ZXJzVGltZW91dFN0ZXBfbXN9ZWxzZXtjbGVhckludGVydmFsKGZuY0dldFByaW50ZXJzKTt3Y3BHZXRQcmludGVyc09uRmFpbHVyZSgpfX19fSxnZXRQcmludGVyc0luZm86ZnVuY3Rpb24oKXtzZXRBKCdVUkxfV0NQX0FYRF9XSVRIX0dFVF9QUklOVEVSU0lORk9fQ09NTUFORCcrJzw8PC1ORU8tU0VTU0lPTi1JRC0+Pj4nKTt2YXIgZGVsYXlfbXM9KHR5cGVvZiB3Y3BwR2V0UHJpbnRlcnNEZWxheV9tcz09PSd1bmRlZmluZWQnKT8wOndjcHBHZXRQcmludGVyc0RlbGF5X21zO2lmKGRlbGF5X21zPjApe3NldFRpbWVvdXQoZnVuY3Rpb24oKXtnZXRSZXEoJ1VSTF9XQ1BfQVhEX0dFVF9QUklOVEVSU0lORk8nKyc8PDwtTkVPLVNFU1NJT04tSUQtPj4+Jyx3Y3BHZXRQcmludGVyc09uU3VjY2Vzcyx3Y3BHZXRQcmludGVyc09uRmFpbHVyZSl9LGRlbGF5X21zKX1lbHNle3ZhciBmbmNHZXRQcmludGVyc0luZm89c2V0SW50ZXJ2YWwoZ2V0Q2xpZW50UHJpbnRlcnNJbmZvLHdjcHBHZXRQcmludGVyc1RpbWVvdXRTdGVwX21zKTt2YXIgd2NwcF9jb3VudD0wO2Z1bmN0aW9uIGdldENsaWVudFByaW50ZXJzSW5mbygpe2lmKHdjcHBfY291bnQ8PXdjcHBHZXRQcmludGVyc1RpbWVvdXRfbXMpe2dldFJlcSgnVVJMX1dDUF9BWERfR0VUX1BSSU5URVJTSU5GTycrJzw8PC1ORU8tU0VTU0lPTi1JRC0+Pj4nLHdjcEdldFByaW50ZXJzT25TdWNjZXNzLG51bGwsZm5jR2V0UHJpbnRlcnNJbmZvKTt3Y3BwX2NvdW50Kz13Y3BwR2V0UHJpbnRlcnNUaW1lb3V0U3RlcF9tc31lbHNle2NsZWFySW50ZXJ2YWwoZm5jR2V0UHJpbnRlcnNJbmZvKTt3Y3BHZXRQcmludGVyc09uRmFpbHVyZSgpfX19fSxnZXRXY3BwVmVyOmZ1bmN0aW9uKCl7c2V0QSgnVVJMX1dDUF9BWERfV0lUSF9HRVRfV0NQUFZFUlNJT05fQ09NTUFORCcrJzw8PC1ORU8tU0VTU0lPTi1JRC0+Pj4nKTt2YXIgZGVsYXlfbXM9KHR5cGVvZiB3Y3BwR2V0VmVyRGVsYXlfbXM9PT0ndW5kZWZpbmVkJyk/MDp3Y3BwR2V0VmVyRGVsYXlfbXM7aWYoZGVsYXlfbXM+MCl7c2V0VGltZW91dChmdW5jdGlvbigpe2dldFJlcSgnVVJMX1dDUF9BWERfR0VUX1dDUFBWRVJTSU9OJysnPDw8LU5FTy1TRVNTSU9OLUlELT4+Picsd2NwR2V0V2NwcFZlck9uU3VjY2Vzcyx3Y3BHZXRXY3BwVmVyT25GYWlsdXJlKX0sZGVsYXlfbXMpfWVsc2V7dmFyIGZuY1dDUFA9c2V0SW50ZXJ2YWwoZ2V0Q2xpZW50VmVyLHdjcHBHZXRWZXJUaW1lb3V0U3RlcF9tcyk7dmFyIHdjcHBfY291bnQ9MDtmdW5jdGlvbiBnZXRDbGllbnRWZXIoKXtpZih3Y3BwX2NvdW50PD13Y3BwR2V0VmVyVGltZW91dF9tcyl7Z2V0UmVxKCdVUkxfV0NQX0FYRF9HRVRfV0NQUFZFUlNJT04nKyc8PDwtTkVPLVNFU1NJT04tSUQtPj4+Jyx3Y3BHZXRXY3BwVmVyT25TdWNjZXNzLG51bGwsZm5jV0NQUCk7d2NwcF9jb3VudCs9d2NwcEdldFZlclRpbWVvdXRTdGVwX21zfWVsc2V7Y2xlYXJJbnRlcnZhbChmbmNXQ1BQKTt3Y3BHZXRXY3BwVmVyT25GYWlsdXJlKCl9fX19LHNlbmQ6ZnVuY3Rpb24oKXtzZXRBLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19fSkoKTs=';
 295:     
 296:             $s2 = base64_decode($s1);
 297:             $s2 = str_replace('URL_PRINT_JOB', $clientPrintJobUrl, $s2);
 298:             $s2 = str_replace('URL_WCP_AXD_WITH_GET_PRINTERSINFO_COMMAND', $wcppGetPrintersInfoParam, $s2);
 299:             $s2 = str_replace('URL_WCP_AXD_GET_PRINTERSINFO', $wcpHandlerGetPrintersInfo, $s2);
 300:             $s2 = str_replace('URL_WCP_AXD_WITH_GET_PRINTERS_COMMAND', $wcppGetPrintersParam, $s2);
 301:             $s2 = str_replace('URL_WCP_AXD_GET_PRINTERS', $wcpHandlerGetPrinters, $s2);
 302:             $s2 = str_replace('URL_WCP_AXD_WITH_GET_WCPPVERSION_COMMAND', $wcppGetWcppVerParam, $s2);
 303:             $s2 = str_replace('URL_WCP_AXD_GET_WCPPVERSION', $wcpHandlerGetWcppVer, $s2);
 304:             $s2 = str_replace('<<<-NEO-SESSION-ID->>>', $sessionIDVal, $s2);
 305:             
 306:             return $s2;
 307:         }
 308:         
 309:     }
 310:     
 311:        
 312:     /**
 313:      * Generates printing script.
 314:      */
 315:     const GenPrintScript = 0;
 316:     /**
 317:      * Generates WebClientPrint Processor (WCPP) detection script.
 318:      */ 
 319:     const GenWcppDetectScript = 1;
 320:     /**
 321:      * Sets the installed printers list in the website cache.
 322:      */        
 323:     const ClientSetInstalledPrinters = 2;
 324:     /**
 325:      * Gets the installed printers list from the website cache.
 326:      */
 327:     const ClientGetInstalledPrinters = 3;
 328:     /**
 329:      * Sets the WebClientPrint Processor (WCPP) Version in the website cache.
 330:      */
 331:     const ClientSetWcppVersion = 4;
 332:     /**
 333:      * Gets the WebClientPrint Processor (WCPP) Version from the website cache.
 334:      */
 335:     const ClientGetWcppVersion = 5;
 336:     /**
 337:      * Sets the installed printers list with detailed info in the website cache.
 338:      */
 339:     const ClientSetInstalledPrintersInfo = 6;
 340:     /**
 341:      * Gets the installed printers list with detailed info from the website cache.
 342:      */
 343:     const ClientGetInstalledPrintersInfo = 7;
 344:        
 345:     
 346:     /**
 347:      * Determines the type of process request based on the Query String value. 
 348:      * 
 349:      * @param string $queryString The query string of the current request.
 350:      * @return integer A valid type of process request. In case of an invalid value, an Exception is thrown.
 351:      * @throws Exception 
 352:      */
 353:     public static function GetProcessRequestType($queryString){
 354:         parse_str($queryString, $qs);
 355:     
 356:         if(isset($qs[self::SID])){
 357:             if(isset($qs[self::PING])){
 358:                 return self::ClientSetWcppVersion;
 359:             } else if(isset($qs[self::WCPP_SET_VERSION])){
 360:                 return self::ClientSetWcppVersion;
 361:             } else if(isset($qs[self::WCPP_SET_PRINTERS])){
 362:                 return self::ClientSetInstalledPrinters;
 363:             } else if(isset($qs[self::WCPP_SET_PRINTERSINFO])){
 364:                 return self::ClientSetInstalledPrintersInfo;
 365:             } else if(isset($qs[self::WCP_SCRIPT_AXD_GET_WCPPVERSION])){
 366:                 return self::ClientGetWcppVersion;
 367:             } else if(isset($qs[self::WCP_SCRIPT_AXD_GET_PRINTERS])){
 368:                 return self::ClientGetInstalledPrinters;
 369:             } else if(isset($qs[self::WCP_SCRIPT_AXD_GET_PRINTERSINFO])){
 370:                 return self::ClientGetInstalledPrintersInfo;
 371:             } else if(isset($qs[self::GEN_WCP_SCRIPT_URL])){
 372:                 return self::GenPrintScript;
 373:             } else {
 374:                 return self::ClientGetWcppVersion;
 375:             }
 376:         } else if(isset($qs[self::GEN_DETECT_WCPP_SCRIPT])){
 377:             return self::GenWcppDetectScript;
 378:         } else {
 379:             throw new Exception('No valid ProcessRequestType was found in the specified QueryString.');
 380:         }
 381:     }
 382:     
 383: }
 384: 
 385: /**
 386:  * Specifies the printer's double-sided (duplex) printing capability.
 387:  */
 388: class Duplex
 389: {
 390:     /**
 391:      * Use default value from driver.
 392:      */
 393:     const DEF = 0;
 394:     /**
 395:      * Use single-sided printing.
 396:      */
 397:     const SIMPLEX = 1;
 398:     /**
 399:      * Use double-sided printing with vertical page turning.
 400:      */
 401:     const VERTICAL = 2;
 402:     /**
 403:      * Use double-sided printing with horizontal page turning.
 404:      */
 405:     const HORIZONTAL = 3;
 406:     
 407:     public static function parse($val){
 408:         if($val === 'DEF') return 0;
 409:         if($val === 'SIMPLEX') return 1;
 410:         if($val === 'VERTICAL') return 2;
 411:         if($val === 'HORIZONTAL') return 3;
 412:         return 0;
 413:     }
 414: }
 415: 
 416: 
 417: /**
 418:  * The base class for all kind of printers supported at the client side.
 419:  */
 420: abstract class ClientPrinter{
 421:     
 422:     public $printerId;
 423:     public function serialize(){
 424:         
 425:     }
 426: }
 427: 
 428: /**
 429:  * It represents the default printer installed in the client machine.
 430:  */
 431: class DefaultPrinter extends ClientPrinter{
 432:     public function __construct() {
 433:         $this->printerId = chr(0);
 434:     }
 435:     
 436:     public function serialize() {
 437:         return $this->printerId;
 438:     }
 439: }
 440: 
 441: /**
 442:  * It represents a printer installed in the client machine with an associated OS driver.
 443:  */
 444: class InstalledPrinter extends ClientPrinter{
 445:     
 446:     /**
 447:      * Gets or sets the name of the printer installed in the client machine. Default value is an empty string.
 448:      * @var string 
 449:      */
 450:     public $printerName = '';
 451: 
 452:     /**
 453:      * Gets or sets whether to print to Default printer in case of the specified one is not found or missing. Default is False.
 454:      * @var boolean 
 455:      */
 456:     public $printToDefaultIfNotFound = false;
 457:     
 458:     
 459:     /**
 460:      * Gets or sets the name of the tray supported by the client printer. Default value is an empty string.
 461:      * @var string 
 462:      */
 463:     public $trayName = '';
 464:     
 465:     /**
 466:      * Gets or sets the name of the Paper supported by the client printer. Default value is an empty string.
 467:      * @var string 
 468:      */
 469:     public $paperName = '';
 470:     
 471:     /**
 472:      * Gets or sets the printer's double-sided (duplex) printing capability. Default is the current printer's driver setting.
 473:      * DEF = 0, SIMPLEX = 1, VERTICAL = 2, HORIZONTAL = 3
 474:      * @var integer 
 475:      */
 476:     public $duplex = Duplex::DEF;
 477:     
 478:     
 479:     /**
 480:      * Creates an instance of the InstalledPrinter class with the specified printer name.
 481:      * @param string $printerName The name of the printer installed in the client machine.
 482:      */
 483:     public function __construct($printerName) {
 484:         $this->printerId = chr(1);
 485:         $this->printerName = $printerName;
 486:     }
 487:     
 488:     public function serialize() {
 489:         
 490:         if (Utils::isNullOrEmptyString($this->printerName)){
 491:              throw new Exception("The specified printer name is null or empty.");
 492:         }
 493:         
 494:         $serData = $this->printerId.$this->printerName;
 495:         
 496:         if ($this->printToDefaultIfNotFound){
 497:             $serData .= Utils::SER_SEP.'1';     
 498:         } else {
 499:             $serData .= Utils::SER_SEP.'0';    
 500:         }      
 501:         
 502:         if ($this->trayName){
 503:             $serData .= Utils::SER_SEP.$this->trayName;     
 504:         } else {
 505:             $serData .= Utils::SER_SEP.'def';    
 506:         }
 507:         
 508:         if ($this->paperName){
 509:             $serData .= Utils::SER_SEP.$this->paperName;     
 510:         } else {
 511:             $serData .= Utils::SER_SEP.'def';    
 512:         }
 513:         
 514:         $serData .= Utils::SER_SEP.((int)$this->duplex);
 515:         
 516:         return $serData;
 517:     }
 518: }
 519: 
 520: /**
 521:  * It represents a printer which is connected through a parallel port in the client machine.
 522:  */
 523: class ParallelPortPrinter extends ClientPrinter{
 524:     
 525:     /**
 526:      * Gets or sets the parallel port name, for example LPT1. Default value is "LPT1"
 527:      * @var string 
 528:      */
 529:     public $portName = "LPT1";
 530: 
 531:     /**
 532:      * Creates an instance of the ParallelPortPrinter class with the specified port name.
 533:      * @param string $portName The parallel port name, for example LPT1.
 534:      */
 535:     public function __construct($portName) {
 536:         $this->printerId = chr(2);
 537:         $this->portName = $portName;
 538:     }
 539:     
 540:     public function serialize() {
 541:         
 542:         if (Utils::isNullOrEmptyString($this->portName)){
 543:              throw new Exception("The specified parallel port name is null or empty.");
 544:         }
 545:         
 546:         return $this->printerId.$this->portName;
 547:     }
 548: }
 549: 
 550: /**
 551:  * It represents a printer which is connected through a serial port in the client machine.
 552:  */
 553: class SerialPortPrinter extends ClientPrinter{
 554:     
 555:     /**
 556:      * Gets or sets the serial port name, for example COM1. Default value is "COM1"
 557:      * @var string 
 558:      */
 559:     public $portName = "COM1";
 560:     /**
 561:      * Gets or sets the serial port baud rate in bits per second. Default value is 9600
 562:      * @var integer 
 563:      */
 564:     public $baudRate = 9600;
 565:     /**
 566:      * Gets or sets the serial port parity-checking protocol. Default value is NONE = 0
 567:      * NONE = 0, ODD = 1, EVEN = 2, MARK = 3, SPACE = 4
 568:      * @var integer 
 569:      */
 570:     public $parity = SerialPortParity::NONE;
 571:     /**
 572:      * Gets or sets the serial port standard number of stopbits per byte. Default value is ONE = 1
 573:      * ONE = 1, TWO = 2, ONE_POINT_FIVE = 3
 574:      * @var integer
 575:      */
 576:     public $stopBits = SerialPortStopBits::ONE;
 577:     /**
 578:      * Gets or sets the serial port standard length of data bits per byte. Default value is 8
 579:      * @var integer
 580:      */
 581:     public $dataBits = 8;
 582:     /**
 583:      * Gets or sets the handshaking protocol for serial port transmission of data. Default value is XON_XOFF = 1
 584:      * NONE = 0, REQUEST_TO_SEND = 2, REQUEST_TO_SEND_XON_XOFF = 3, XON_XOFF = 1
 585:      * @var integer
 586:      */
 587:     public $flowControl = SerialPortHandshake::XON_XOFF;
 588:     
 589:     /**
 590:      * Creates an instance of the SerialPortPrinter class wiht the specified information.
 591:      * @param string $portName The serial port name, for example COM1.
 592:      * @param integer $baudRate The serial port baud rate in bits per second.
 593:      * @param integer $parity The serial port parity-checking protocol.
 594:      * @param integer $stopBits The serial port standard number of stopbits per byte.
 595:      * @param integer $dataBits The serial port standard length of data bits per byte.
 596:      * @param integer $flowControl The handshaking protocol for serial port transmission of data.
 597:      */
 598:     public function __construct($portName, $baudRate, $parity, $stopBits, $dataBits, $flowControl) {
 599:         $this->printerId = chr(3);
 600:         $this->portName = $portName;
 601:         $this->baudRate = $baudRate;
 602:         $this->parity = $parity;
 603:         $this->stopBits = $stopBits;
 604:         $this->dataBits = $dataBits;
 605:         $this->flowControl = $flowControl;
 606:     }
 607:     
 608:     public function serialize() {
 609:         
 610:         if (Utils::isNullOrEmptyString($this->portName)){
 611:              throw new Exception("The specified serial port name is null or empty.");
 612:         }
 613:         
 614:         return $this->printerId.$this->portName.Utils::SER_SEP.$this->baudRate.Utils::SER_SEP.$this->dataBits.Utils::SER_SEP.((int)$this->flowControl).Utils::SER_SEP.((int)$this->parity).Utils::SER_SEP.((int)$this->stopBits);
 615:     }
 616: }
 617: 
 618: /**
 619:  * It represents a Network IP/Ethernet printer which can be reached from the client machine.
 620:  */
 621: class NetworkPrinter extends ClientPrinter{
 622:     
 623:     /**
 624:      * Gets or sets the DNS name assigned to the printer. Default is an empty string
 625:      * @var string 
 626:      */
 627:     public $dnsName = "";
 628:     /**
 629:      * Gets or sets the Internet Protocol (IP) address assigned to the printer. Default value is an empty string
 630:      * @var string 
 631:      */
 632:     public $ipAddress = "";
 633:     /**
 634:      * Gets or sets the port number assigned to the printer. Default value is 0
 635:      * @var integer 
 636:      */
 637:     public $port = 0;
 638:     
 639:     /**
 640:      * Creates an instance of the NetworkPrinter class with the specified DNS name or IP Address, and port number.
 641:      * @param string $dnsName The DNS name assigned to the printer.
 642:      * @param string $ipAddress The Internet Protocol (IP) address assigned to the printer.
 643:      * @param integer $port The port number assigned to the printer.
 644:      */
 645:     public function __construct($dnsName, $ipAddress, $port) {
 646:         $this->printerId = chr(4);
 647:         $this->dnsName = $dnsName;
 648:         $this->ipAddress = $ipAddress;
 649:         $this->port = $port;
 650:     }
 651:     
 652:     public function serialize() {
 653:         
 654:         if (Utils::isNullOrEmptyString($this->dnsName) && Utils::isNullOrEmptyString($this->ipAddress)){
 655:              throw new Exception("The specified network printer settings is not valid. You must specify the DNS Printer Name or its IP address.");
 656:         }
 657:         
 658:         return $this->printerId.$this->dnsName.Utils::SER_SEP.$this->ipAddress.Utils::SER_SEP.$this->port;
 659:     }
 660: }
 661: 
 662: /**
 663:  *  It represents a printer which will be selected by the user in the client machine. The user will be prompted with a print dialog.
 664:  */
 665: class UserSelectedPrinter extends ClientPrinter{
 666:     public function __construct() {
 667:         $this->printerId = chr(5);
 668:     }
 669:     
 670:     public function serialize() {
 671:         return $this->printerId;
 672:     }
 673: }
 674: 
 675: /**
 676:  * Specifies the parity bit for Serial Port settings. 
 677:  */
 678: class SerialPortParity{
 679:     const NONE = 0;
 680:     const ODD = 1;
 681:     const EVEN = 2;
 682:     const MARK = 3;
 683:     const SPACE = 4;
 684:     public static function parse($val){
 685:         if($val === 'NONE') return 0;
 686:         if($val === 'ODD') return 1;
 687:         if($val === 'EVEN') return 2;
 688:         if($val === 'MARK') return 3;
 689:         if($val === 'SPACE') return 4;
 690:         return 0;
 691:     }
 692: }
 693: 
 694: /**
 695:  * Specifies the number of stop bits used for Serial Port settings.
 696:  */
 697: class SerialPortStopBits{
 698:     const NONE = 0;
 699:     const ONE = 1;
 700:     const TWO = 2;
 701:     const ONE_POINT_FIVE = 3;
 702:     public static function parse($val){
 703:         if($val === 'NONE') return 0;
 704:         if($val === 'ONE') return 1;
 705:         if($val === 'TWO') return 2;
 706:         if($val === 'ONE_POINT_FIVE') return 3;
 707:         return 0;
 708:     }
 709: }
 710: 
 711: /**
 712:  * Specifies the control protocol used in establishing a serial port communication.
 713:  */
 714: class SerialPortHandshake{
 715:     const NONE = 0;
 716:     const REQUEST_TO_SEND = 2;
 717:     const REQUEST_TO_SEND_XON_XOFF = 3;
 718:     const XON_XOFF = 1;
 719:     public static function parse($val){
 720:         if($val === 'NONE') return 0;
 721:         if($val === 'XON_XOFF') return 1;
 722:         if($val === 'REQUEST_TO_SEND') return 2;
 723:         if($val === 'REQUEST_TO_SEND_XON_XOFF') return 3;
 724:         return 0;
 725:     }
 726: }
 727: 
 728: /**
 729:  * It specifies encryption metadata.
 730:  */
 731: class EncryptMetadata{
 732:     
 733:     /**
 734:     * Gets the RSA Public Key in Base64 format.
 735:     */
 736:     public $publicKeyBase64 = '';
 737:     /**
 738:     * Gets the RSA Public Key Signature in Base64 format.
 739:     */
 740:     public $publicKeySignatureBase64 = '';
 741:     /**
 742:     * Gets or sets the password used to derive the encryption key. It must be 100 ASCII chars/bytes max.
 743:     */
 744:     public $password = '';
 745:     /**
 746:     * Gets or sets the salt used to derive the key. It must be 100 ASCII chars/bytes max.
 747:     */
 748:     public $salt = '';
 749:     /**
 750:     * Gets or sets the Initialization Vector to be used for the encryption algorithm. It must be 32 ASCII chars/bytes.
 751:     */
 752:     public $iv = '';
 753:     /**
 754:     * Gets or sets the number of iterations to derive the key. Minimum is 1000.
 755:     */
 756:     public $iterations = 1000;
 757:         
 758:         
 759:     /**
 760:      * 
 761:      * @param type $pubKeyBase64 The RSA Public Key in Base64 format sent by WCPP Client Utility.
 762:      * @param type $pubKeySignatureKeyBase64 The RSA Public Key Signature in Base64 format sent by WCPP Client Utility.
 763:      */
 764:     public function __construct($pubKeyBase64, $pubKeySignatureKeyBase64) {
 765:         $this->publicKeyBase64 = $pubKeyBase64;
 766:         $this->publicKeySignatureBase64 = $pubKeySignatureKeyBase64;
 767:     }
 768:     
 769:     public function serialize() {
 770:         
 771:         $this->validateMetadata();
 772: 
 773:         $sep = '|';
 774: 
 775:         $buffer = base64_encode(SecUtils::rsaVerifyAndEncrypt($this->publicKeyBase64, $this->publicKeySignatureBase64, $this->password));
 776:         $buffer .= $sep;
 777:         $buffer .= base64_encode(SecUtils::rsaVerifyAndEncrypt($this->publicKeyBase64, $this->publicKeySignatureBase64, $this->salt));
 778:         $buffer .= $sep;
 779:         $buffer .= base64_encode(SecUtils::rsaVerifyAndEncrypt($this->publicKeyBase64, $this->publicKeySignatureBase64, $this->iv));
 780:         $buffer .= $sep;
 781:         $buffer .= base64_encode(SecUtils::rsaVerifyAndEncrypt($this->publicKeyBase64, $this->publicKeySignatureBase64, strval($this->iterations)));
 782:         
 783:         return $buffer;
 784:     }
 785:     
 786:     public function validateMetadata(){
 787:         if(Utils::isNullOrEmptyString($this->password)){
 788:             $this->password = Utils::genRandomString(33, 126, 32);
 789:         }else if (strlen($this->password) > 100){
 790:             throw new Exception("Password cannot be greater than 100 ASCII chars/bytes.");
 791:         }
 792:         
 793:         if(Utils::isNullOrEmptyString($this->salt)){
 794:             $this->salt = Utils::genRandomString(33, 126, 32);
 795:         }else if (strlen($this->salt) > 100){
 796:             throw new Exception("Salt cannot be greater than 100 ASCII chars/bytes.");
 797:         }
 798: 
 799:         if(Utils::isNullOrEmptyString($this->iv)){
 800:             $this->iv = Utils::genRandomString(33, 126, 16);
 801:         }else if (strlen($this->iv) > 16){
 802:             throw new Exception("IV cannot be greater than 16 ASCII chars/bytes.");
 803:         }
 804: 
 805:         if ($this->iterations < 1000){
 806:             $this->iterations = 1000;
 807:         }
 808:     } 
 809: }
 810: 
 811: 
 812: /**
 813:  * It represents a file in the server that will be printed at the client side.
 814:  */
 815: class PrintFile{
 816:     
 817:     public $fileIsPasswordProtected = false;
 818:     public $fileExtension = '';
 819:     
 820:     /**
 821:      * Gets or sets the path of the file at the server side that will be printed at the client side.
 822:      * @var string 
 823:      */
 824:     public $filePath = '';
 825:     /**
 826:      * Gets or sets the file name that will be created at the client side. 
 827:      * It must include the file extension like .pdf, .txt, .doc, .xls, etc.
 828:      * @var string 
 829:      */
 830:     public $fileName = '';
 831:     /**
 832:      * Gets or sets the binary content of the file at the server side that will be printed at the client side.
 833:      * @var string 
 834:      */
 835:     public $fileBinaryContent = '';
 836:     
 837:     /**
 838:      * Gets or sets the num of copies for printing this file. Default is 1.
 839:      * @var integer
 840:      */
 841:     public $copies = 1;
 842:     /**
 843:      * Gets or sets the Encryption Metadata.
 844:      * @var EncryptMetadata 
 845:      */
 846:     public $encryptMetadata = null;
 847:     
 848:     /**
 849:      * Gets or sets whether to delete this file from the client device after printing it. Default is true.
 850:      * @var boolean 
 851:      */
 852:     public $deleteAfterPrinting = true;
 853:     
 854:     const PREFIX = 'wcpPF:';
 855:     const SEP = '|';
 856:         
 857:     /**
 858:      * 
 859:      * @param string $filePath The path of the file at the server side that will be printed at the client side.
 860:      * @param string $fileName The file name that will be created at the client side. It must include the file extension like .pdf, .txt, .doc, .xls, etc.
 861:      * @param string $fileBinaryContent The binary content of the file at the server side that will be printed at the client side.
 862:      */
 863:     public function __construct($filePath, $fileName, $fileBinaryContent) {
 864:         $this->filePath = $filePath;
 865:         $this->fileName = $fileName;
 866:         $this->fileBinaryContent = $fileBinaryContent;
 867:         
 868:     }
 869:     
 870:     public function serialize() {
 871:         $file = str_replace('\\', 'BACKSLASHCHAR',$this->fileName );
 872:         $pfc = '';
 873:         if($this->copies > 1){
 874:             $pfc = 'PFC='.$this->copies;
 875:         }
 876:         $df = 'DEL=F';
 877:         if($this->deleteAfterPrinting){
 878:             $df = '';
 879:         }
 880:         
 881:         $fn = $file;
 882:         $ext = '';
 883:         if (strrpos($fn, '.') > 0){
 884:             $fn = substr($fn, 0, strrpos($fn, '.'));
 885:             $ext = substr($file, strrpos($file, '.'));
 886:         }
 887:         
 888:         if(Utils::isNullOrEmptyString($this->fileExtension)){
 889:             $file = $fn.$pfc.$df.$ext;
 890:         } else {
 891:             $file = $fn.$pfc.$df.$this->fileExtension;
 892:         }
 893:         
 894:         $fileContent = $this->getFileContent();
 895:         
 896:         if($this->encryptMetadata != null &&
 897:            Utils::isNullOrEmptyString($this->encryptMetadata->publicKeyBase64) == false &&
 898:            $this->fileIsPasswordProtected == false){
 899:                 
 900:             //validate Encrypt Metadata
 901:             $this->encryptMetadata->validateMetadata();
 902:             //Encrypt content
 903:             $fileContent = SecUtils::aesEncrypt($fileContent,
 904:                                                 $this->encryptMetadata->password,
 905:                                                 $this->encryptMetadata->salt,
 906:                                                 $this->encryptMetadata->iv,
 907:                                                 $this->encryptMetadata->iterations);
 908:                 
 909:         }
 910:         
 911:         return self::PREFIX.$file.self::SEP.$fileContent;
 912:     }
 913:     
 914:     public function getFileContent(){
 915:         if(!Utils::isNullOrEmptyString($this->filePath)){
 916:             $handle = fopen($this->filePath, 'rb');
 917:             $content = fread($handle, filesize($this->filePath));
 918:             fclose($handle);
 919:         } else {
 920:             $content = $this->fileBinaryContent;
 921:         }
 922:         return $content;
 923:     }
 924:     
 925: }
 926: 
 927: /**
 928:  * Specifies the print rotation.
 929:  */
 930: class PrintRotation
 931: {
 932:     /**
 933:      * Print page without rotation.
 934:      */
 935:     const None = 0;
 936:     /**
 937:      * Print page rotated by 90 degrees clockwise.
 938:      */
 939:     const Rot90 = 1;
 940:     /**
 941:      * Print page rotated by 180 degrees.
 942:      */
 943:     const Rot180 = 2;
 944:     /**
 945:      * Print page rotated by 270 degrees clockwise.
 946:      */
 947:     const Rot270 = 3;
 948:     
 949:     public static function parse($val){
 950:         if($val === 'None') return 0;
 951:         if($val === 'Rot90') return 1;
 952:         if($val === 'Rot180') return 2;
 953:         if($val === 'Rot270') return 3;
 954:         return 0;
 955:     }
 956: }
 957: 
 958: /**
 959:  * Specifies the print sizing option.
 960:  */
 961: class Sizing
 962: {
 963:     /**
 964:      * The content is printed based on its actual size.
 965:      */
 966:     const None = 0;
 967:     /**
 968:      * The content is printed to fit the printable area.
 969:      */
 970:     const Fit = 1;
 971:     
 972:     public static function parse($val){
 973:         if($val === 'None') return 0;
 974:         if($val === 'Fit') return 1;
 975:         return 0;
 976:     }
 977: }
 978: 
 979: /**
 980:  * It represents a PDF file in the server that will be printed at the client side.
 981:  */
 982: class PrintFilePDF extends PrintFile{
 983:     
 984:     /**
 985:      * Gets or sets whether to print the PDF document with color images, texts, or other objects as shades of gray. Default is False.
 986:      * @var boolean 
 987:      */
 988:     public $printAsGrayscale = false;
 989:  
 990:     /**
 991:      * Gets or sets whether to print any annotations, if any, available in the PDF document. Default is False.
 992:      * @var boolean 
 993:      */
 994:     public $printAnnotations = false;
 995:     
 996:     /**
 997:      * Gets or sets a subset of pages to print. It can be individual page numbers, a range, or a combination. For example: 1, 5-10, 25, 50. Default is an empty string which means print all pages.
 998:      * @var string 
 999:      */
1000:     public $pagesRange = '';
1001:     
1002:     /**
1003:      * Gets or sets whether pages are printed in reverse order. Default is False.
1004:      * @var boolean 
1005:      */
1006:     public $printInReverseOrder = false;
1007:     
1008:     /**
1009:      * Gets or sets the print rotation. Default is None.
1010:      * @var integer 
1011:      */
1012:     public $printRotation = PrintRotation::None;
1013:     
1014:     /**
1015:      * Gets or sets the password for this PDF file.
1016:      * @var string 
1017:      */
1018:     public $password = '';
1019:     
1020:     /**
1021:      * Gets or sets whether to perform manual duplex printing. Default is False. Manual duplex lets you print on both sides of a sheet by ordering the print job so that after the first half of the print job has been printed, the job can be flipped over for the second side printing.
1022:      * @var boolean 
1023:      */
1024:     public $duplexPrinting = false;
1025:     
1026:     /**
1027:      * Gets or sets the dialog message to prompt to the user to flip pages after first half of print job has been printed. Default is an empty string.
1028:      * @var string 
1029:      */
1030:     public $duplexPrintingDialogMessage = '';
1031:     
1032:     /**
1033:      * Gets or sets whether to automatically select the print orientation (Portrait or Landscape) that best matches the content. Default is False.
1034:      * @var boolean 
1035:      */
1036:     public $autoRotate = false;
1037:     
1038:     /**
1039:      * Gets or sets whether to center the content. Default is False.
1040:      * @var boolean 
1041:      */
1042:     public $autoCenter = false;
1043:     
1044:     /**
1045:      * Gets or sets the print sizing option. Default is Fit.
1046:      * @var integer 
1047:      */
1048:     public $sizing = Sizing::Fit;
1049:     
1050:     
1051:     public function serialize() {
1052:         
1053:         $this->fileExtension = '.wpdf';
1054:         
1055:         return parent::serialize();
1056:     }
1057:     
1058:     public function getFileContent(){
1059:  
1060:         $pr = urldecode($this->pagesRange);
1061:         if (!Utils::isNullOrEmptyString($pr)){
1062:             if (preg_match('/^(?!([ \d]*-){2})\d+(?: *[-,] *\d+)*$/', $pr))
1063:             {
1064:                 //validate range
1065:                 $ranges = explode(',',str_replace(' ', '', $pr)); //remove any space chars
1066:                 
1067:                 for ($i = 0; $i < count($ranges); $i++)
1068:                 {
1069:                     if (strpos($ranges[$i], '-') > 0)
1070:                     {
1071:                         $pages = explode('-', $ranges[$i]);
1072:                         if (intval($pages[0]) > intval($pages[1]))
1073:                         {
1074:                             throw new Exception("The specified PageRange is not valid.");
1075:                         }
1076:                     }
1077:                 }
1078:             }
1079:             else{
1080:                 throw new Exception("The specified PageRange is not valid.");
1081:             }
1082:         }
1083:         
1084:         $metadata = ($this->printAsGrayscale ? '1' : '0');
1085:         $metadata .= Utils::SER_SEP.($this->printAnnotations ? '1' : '0');
1086:         $metadata .= Utils::SER_SEP.(Utils::isNullOrEmptyString($pr) ? 'A' : $pr);
1087:         $metadata .= Utils::SER_SEP.($this->printInReverseOrder ? '1' : '0');
1088:         $metadata .= Utils::SER_SEP.$this->printRotation;
1089:         $metadata .= Utils::SER_SEP;
1090:         
1091:         $this->fileIsPasswordProtected = !Utils::isNullOrEmptyString($this->password);
1092: 
1093:         if ($this->fileIsPasswordProtected == false){
1094:             $metadata .= 'N';
1095:         } else {
1096:             if (Utils::isNullOrEmptyString($this->encryptMetadata->publicKeyBase64) == false) {
1097:                 $metadata .= base64_encode(SecUtils::rsaVerifyAndEncrypt($this->encryptMetadata->publicKeyBase64, $this->encryptMetadata->publicKeySignatureBase64, $this->password));
1098:             } else {
1099:                 $metadata .= base64_encode($this->password);
1100:             }
1101:         }
1102:         
1103:         $metadata .= Utils::SER_SEP.($this->duplexPrinting ? '1' : '0');
1104:         $metadata .= Utils::SER_SEP.(Utils::isNullOrEmptyString($this->duplexPrintingDialogMessage) ? 'D' : base64_encode($this->duplexPrintingDialogMessage));
1105:         $metadata .= Utils::SER_SEP.($this->autoRotate ? '1' : '0');
1106:         $metadata .= Utils::SER_SEP.($this->autoCenter ? '1' : '0');
1107:         $metadata .= Utils::SER_SEP.(strval(Sizing::parse($this->sizing)));
1108:         
1109:         $metadataLength = strlen($metadata);
1110:         $metadata .= Utils::SER_SEP;
1111:         $metadataLength++;
1112:         $metadataLength += strlen(strval($metadataLength));
1113:         $metadata .= strval($metadataLength);
1114:         
1115:         if(!Utils::isNullOrEmptyString($this->filePath)){
1116:             $handle = fopen($this->filePath, 'rb');
1117:             $content = fread($handle, filesize($this->filePath));
1118:             fclose($handle);
1119:         } else {
1120:             $content = $this->fileBinaryContent;
1121:         }
1122:         return $content.$metadata;
1123:     }
1124: }
1125: 
1126: /**
1127:  * It represents a TIF file in the server that will be printed at the client side.
1128:  */
1129: class PrintFileTIF extends PrintFile{
1130:     
1131:     /**
1132:      * Gets or sets whether to print the TIF document with color images, texts, or other objects as shades of gray. Default is False.
1133:      * @var boolean 
1134:      */
1135:     public $printAsGrayscale = false;
1136:  
1137:     /**
1138:      * Gets or sets a subset of pages to print. It can be individual page numbers, a range, or a combination. For example: 1, 5-10, 25, 50. Default is an empty string which means print all pages.
1139:      * @var string 
1140:      */
1141:     public $pagesRange = '';
1142:     
1143:     /**
1144:      * Gets or sets whether pages are printed in reverse order. Default is False.
1145:      * @var boolean 
1146:      */
1147:     public $printInReverseOrder = false;
1148:     
1149:     /**
1150:      * Gets or sets the print rotation. Default is None.
1151:      * @var integer 
1152:      */
1153:     public $printRotation = PrintRotation::None;
1154:     
1155:     /**
1156:      * Gets or sets whether to perform manual duplex printing. Default is False. Manual duplex lets you print on both sides of a sheet by ordering the print job so that after the first half of the print job has been printed, the job can be flipped over for the second side printing.
1157:      * @var boolean 
1158:      */
1159:     public $duplexPrinting = false;
1160:     
1161:     /**
1162:      * Gets or sets the dialog message to prompt to the user to flip pages after first half of print job has been printed. Default is an empty string.
1163:      * @var string 
1164:      */
1165:     public $duplexPrintingDialogMessage = '';
1166:     
1167:     /**
1168:      * Gets or sets whether to automatically select the print orientation (Portrait or Landscape) that best matches the content. Default is False.
1169:      * @var boolean 
1170:      */
1171:     public $autoRotate = false;
1172:     
1173:     /**
1174:      * Gets or sets whether to center the content. Default is False.
1175:      * @var boolean 
1176:      */
1177:     public $autoCenter = false;
1178:     
1179:     /**
1180:      * Gets or sets the print sizing option. Default is Fit.
1181:      * @var integer 
1182:      */
1183:     public $sizing = Sizing::Fit;
1184:     
1185:     
1186:     public function serialize() {
1187:         
1188:         $this->fileExtension = '.wtif';
1189:         
1190:         return parent::serialize();
1191:     }
1192:     
1193:     public function getFileContent(){
1194:  
1195:         $pr = urldecode($this->pagesRange);
1196:         if (!Utils::isNullOrEmptyString($pr)){
1197:             if (preg_match('/^(?!([ \d]*-){2})\d+(?: *[-,] *\d+)*$/', $pr))
1198:             {
1199:                 //validate range
1200:                 $ranges = explode(',',str_replace(' ', '', $pr)); //remove any space chars
1201:                 
1202:                 for ($i = 0; $i < count($ranges); $i++)
1203:                 {
1204:                     if (strpos($ranges[$i], '-') > 0)
1205:                     {
1206:                         $pages = explode('-', $ranges[$i]);
1207:                         if (intval($pages[0]) > intval($pages[1]))
1208:                         {
1209:                             throw new Exception("The specified PageRange is not valid.");
1210:                         }
1211:                     }
1212:                 }
1213:             }
1214:             else{
1215:                 throw new Exception("The specified PageRange is not valid.");
1216:             }
1217:         }
1218:         
1219:         $metadata = ($this->printAsGrayscale ? '1' : '0');
1220:         $metadata .= Utils::SER_SEP.(Utils::isNullOrEmptyString($pr) ? 'A' : $pr);
1221:         $metadata .= Utils::SER_SEP.($this->printInReverseOrder ? '1' : '0');
1222:         $metadata .= Utils::SER_SEP.$this->printRotation;
1223:         $metadata .= Utils::SER_SEP.($this->duplexPrinting ? '1' : '0');
1224:         $metadata .= Utils::SER_SEP.(Utils::isNullOrEmptyString($this->duplexPrintingDialogMessage) ? 'D' : base64_encode($this->duplexPrintingDialogMessage));
1225:         $metadata .= Utils::SER_SEP.($this->autoRotate ? '1' : '0');
1226:         $metadata .= Utils::SER_SEP.($this->autoCenter ? '1' : '0');
1227:         $metadata .= Utils::SER_SEP.(strval(Sizing::parse($this->sizing)));
1228:         
1229:         $metadataLength = strlen($metadata);
1230:         $metadata .= Utils::SER_SEP;
1231:         $metadataLength++;
1232:         $metadataLength += strlen(strval($metadataLength));
1233:         $metadata .= strval($metadataLength);
1234:         
1235:         if(!Utils::isNullOrEmptyString($this->filePath)){
1236:             $handle = fopen($this->filePath, 'rb');
1237:             $content = fread($handle, filesize($this->filePath));
1238:             fclose($handle);
1239:         } else {
1240:             $content = $this->fileBinaryContent;
1241:         }
1242:         return $content.$metadata;
1243:     }
1244: }
1245: 
1246: 
1247: /**
1248:  * Specifies the print orientation.
1249:  */
1250: class PrintOrientation
1251: {
1252:     /**
1253:      * Print the document vertically.
1254:      */
1255:     const Portrait = 0;
1256:     /**
1257:      *  Print the document horizontally.
1258:      */
1259:     const Landscape = 1;
1260:     
1261:     public static function parse($val){
1262:         if($val === 'Portrait') return 0;
1263:         if($val === 'Landscape') return 1;
1264:         return 0;
1265:     }
1266: }
1267: 
1268: /**
1269:  * Specifies the text alignment
1270:  */
1271: class TextAlignment
1272: {
1273:     /**
1274:      * Left alignment
1275:      */
1276:     const Left = 0;
1277:     /**
1278:      * Right alignment
1279:      */
1280:     const Right = 2;
1281:     /**
1282:      * Center alignment
1283:      */
1284:     const Center = 1;
1285:     /**
1286:      * Justify alignment
1287:      */
1288:     const Justify = 3;
1289:     /**
1290:      * No alignment
1291:      */
1292:     const None = 4;
1293: 
1294: 
1295:     public static function parse($val){
1296:         if($val === 'Left') return 0;
1297:         if($val === 'Center') return 1;
1298:         if($val === 'Right') return 2;
1299:         if($val === 'Justify') return 3;
1300:         if($val === 'None') return 4;
1301:         return 0;
1302:     }
1303: }
1304:     
1305: /**
1306:  * It represents a plain text file in the server that will be printed at the client side.
1307:  */
1308: class PrintFileTXT extends PrintFile{
1309:     
1310:     /**
1311:      * Gets or sets the Text content to be printed. Default is an empty string.
1312:      * @var string 
1313:      */
1314:      public $textContent = '';
1315:      
1316:      /**
1317:       * Gets or sets the alignment of the text content. Default is Left alignment.
1318:       * @var integer 
1319:       */
1320:      public $textAlignment = TextAlignment::Left;
1321: 
1322:      /**
1323:       * Gets or sets the font name. Default is Arial.
1324:       * @var string 
1325:       */
1326:      public $fontName = 'Arial';
1327:      
1328:      /**
1329:       * Gets or sets whether the text is bold. Default is False.
1330:       * @var boolean 
1331:       */
1332:      public $fontBold = false;
1333:         
1334:      /**
1335:       * Gets or sets whether the text has the italic style applied. Default is False.
1336:       * @var boolean 
1337:       */
1338:      public $fontItalic = false;
1339:       
1340:      /**
1341:       * Gets or sets whether the text is underlined. Default is False.
1342:       * @var boolean 
1343:       */
1344:      public $fontUnderline = false;
1345:         
1346:      /**
1347:       * Gets or sets whether the text is printed with a horizontal line through it. Default is False.
1348:       * @var boolean
1349:       */
1350:      public $fontStrikeThrough = false;
1351:         
1352:      /**
1353:       * Gets or sets the font size in Points unit. Default is 10pt. 
1354:       * @var float 
1355:       */
1356:      public $fontSizeInPoints = 10.0;
1357:         
1358:      /**
1359:       * Gets or sets the Color for the printed text. Color must be specified in Hex notation for RGB channels respectively e.g. #rgb or #rrggbb. Default is #000000.
1360:       * @var string 
1361:       */
1362:      public $textColor = "#000000";
1363:         
1364:      /**
1365:       * Gets or sets the print orientation. Default is Portrait.
1366:       * @var integer 
1367:       */
1368:      public $printOrientation = PrintOrientation::Portrait;
1369:         
1370:      /**
1371:       * Gets or sets the left margin for the printed text. Value must be specified in Inch unit. Default is 0.5in
1372:       * @var float 
1373:       */
1374:      public $marginLeft = 0.5;
1375:         
1376:      /**
1377:       * Gets or sets the right margin for the printed text. Value must be specified in Inch unit. Default is 0.5in
1378:       * @var float 
1379:       */
1380:      public $marginRight = 0.5;
1381:      
1382:      /**
1383:       * Gets or sets the top margin for the printed text. Value must be specified in Inch unit. Default is 0.5in
1384:       * @var float 
1385:       */
1386:      public $marginTop = 0.5;
1387:         
1388:      /**
1389:       * Gets or sets the bottom margin for the printed text. Value must be specified in Inch unit. Default is 0.5in
1390:       * @var float 
1391:       */
1392:      public $marginBottom = 0.5;
1393:      
1394:      
1395:      public function serialize() {
1396:         $this->fileIsPasswordProtected = false;
1397:                 
1398:         $this->fileExtension = '.wtxt';
1399:         
1400:         return parent::serialize();
1401:      }
1402:     
1403:      public function getFileContent(){
1404:         
1405:         $metadata = $this->printOrientation;
1406:         $metadata .= Utils::SER_SEP.$this->textAlignment;
1407:         $metadata .= Utils::SER_SEP.$this->fontName;
1408:         $metadata .= Utils::SER_SEP.strval($this->fontSizeInPoints);
1409:         $metadata .= Utils::SER_SEP.($this->fontBold ? '1' : '0');
1410:         $metadata .= Utils::SER_SEP.($this->fontItalic ? '1' : '0');
1411:         $metadata .= Utils::SER_SEP.($this->fontUnderline ? '1' : '0');
1412:         $metadata .= Utils::SER_SEP.($this->fontStrikeThrough ? '1' : '0');
1413:         $metadata .= Utils::SER_SEP.$this->textColor;
1414:         $metadata .= Utils::SER_SEP.strval($this->marginLeft);
1415:         $metadata .= Utils::SER_SEP.strval($this->marginTop);
1416:         $metadata .= Utils::SER_SEP.strval($this->marginRight);
1417:         $metadata .= Utils::SER_SEP.strval($this->marginBottom);
1418:         
1419:         $content = $this->textContent;
1420:         if (Utils::isNullOrEmptyString($content)){
1421:             if(!Utils::isNullOrEmptyString($this->filePath)){
1422:                 $handle = fopen($this->filePath, 'rb');
1423:                 $content = fread($handle, filesize($this->filePath));
1424:                 fclose($handle);
1425:             } else {
1426:                 $content = $this->fileBinaryContent;
1427:             }
1428:         }
1429:      
1430:         if (Utils::isNullOrEmptyString($content)){
1431:             throw new Exception('The specified Text file is empty and cannot be printed.');
1432:         }
1433:         
1434:         return $metadata.chr(10).$content;
1435:     }
1436: }
1437: 
1438: 
1439: /**
1440:  * It represents a DOC file in the server that will be printed at the client side.
1441:  */
1442: class PrintFileDOC extends PrintFile{
1443:     
1444:     /**
1445:      * Gets or sets a subset of pages to print. It can be individual page numbers, a range, or a combination. For example: 1, 5-10, 25, 50. Default is an empty string which means print all pages.
1446:      * @var string 
1447:      */
1448:     public $pagesRange = '';
1449:     
1450:     /**
1451:      * Gets or sets whether pages are printed in reverse order. Default is False.
1452:      * @var boolean 
1453:      */
1454:     public $printInReverseOrder = false;
1455:     
1456:     /**
1457:      * Gets or sets the password for this PDF file.
1458:      * @var string 
1459:      */
1460:     public $password = '';
1461:     
1462:     /**
1463:      * Gets or sets whether to perform manual duplex printing. Default is False. Manual duplex lets you print on both sides of a sheet by ordering the print job so that after the first half of the print job has been printed, the job can be flipped over for the second side printing.
1464:      * @var boolean 
1465:      */
1466:     public $duplexPrinting = false;
1467:     
1468:     /**
1469:      * Gets or sets the dialog message to prompt to the user to flip pages after first half of print job has been printed. Default is an empty string.
1470:      * @var string 
1471:      */
1472:     public $duplexPrintingDialogMessage = '';
1473:     
1474:     
1475:     public function serialize() {
1476:         $this->fileExtension = '.wdoc';
1477:         
1478:         return parent::serialize();
1479:     }
1480:     
1481:     public function getFileContent(){
1482:  
1483:         $pr = urldecode($this->pagesRange);
1484:         if (!Utils::isNullOrEmptyString($pr)){
1485:             if (preg_match('/^(?!([ \d]*-){2})\d+(?: *[-,] *\d+)*$/', $pr))
1486:             {
1487:                 //validate range
1488:                 $ranges = explode(',',str_replace(' ', '', $pr)); //remove any space chars
1489:                 
1490:                 for ($i = 0; $i < count($ranges); $i++)
1491:                 {
1492:                     if (strpos($ranges[$i], '-') > 0)
1493:                     {
1494:                         $pages = explode('-', $ranges[$i]);
1495:                         if (intval($pages[0]) > intval($pages[1]))
1496:                         {
1497:                             throw new Exception("The specified PageRange is not valid.");
1498:                         }
1499:                     }
1500:                 }
1501:             }
1502:             else
1503:                 throw new Exception("The specified PageRange is not valid.");
1504:             
1505:         }
1506:         
1507:         $metadata = (Utils::isNullOrEmptyString($pr) ? 'A' : $pr);
1508:         $metadata .= Utils::SER_SEP.($this->printInReverseOrder ? '1' : '0');
1509:         $metadata .= Utils::SER_SEP;
1510:         
1511:         $this->fileIsPasswordProtected = !Utils::isNullOrEmptyString($this->password);
1512: 
1513:         if ($this->fileIsPasswordProtected == false){
1514:             $metadata .= 'N';
1515:         } else {
1516:             if (Utils::isNullOrEmptyString($this->encryptMetadata->publicKeyBase64) == false) {
1517:                 $metadata .= base64_encode(SecUtils::rsaVerifyAndEncrypt($this->encryptMetadata->publicKeyBase64, $this->encryptMetadata->publicKeySignatureBase64, $this->password));
1518:             } else {
1519:                 $metadata .= base64_encode($this->password);
1520:             }
1521:         }
1522:         
1523:         $metadata .= Utils::SER_SEP.($this->duplexPrinting ? '1' : '0');
1524:         $metadata .= Utils::SER_SEP.(Utils::isNullOrEmptyString($this->duplexPrintingDialogMessage) ? 'D' : base64_encode($this->duplexPrintingDialogMessage));
1525:         
1526:         $metadataLength = strlen($metadata);
1527:         $metadata .= Utils::SER_SEP;
1528:         $metadataLength++;
1529:         $metadataLength += strlen(strval($metadataLength));
1530:         $metadata .= strval($metadataLength);
1531:         
1532:         
1533:         if(!Utils::isNullOrEmptyString($this->filePath)){
1534:             $handle = fopen($this->filePath, 'rb');
1535:             $content = fread($handle, filesize($this->filePath));
1536:             fclose($handle);
1537:         } else {
1538:             $content = $this->fileBinaryContent;
1539:         }
1540:         
1541:         return $content.$metadata;
1542:     }
1543: }
1544: 
1545: 
1546: /**
1547:  * It represents a XLS file in the server that will be printed at the client side.
1548:  */
1549: class PrintFileXLS extends PrintFile{
1550:     
1551:     /**
1552:      * Gets or sets the number of the page at which to start printing. Default is 0 (zero) which means printing starts at the beginning.
1553:      * @var integer 
1554:      */
1555:     public $pagesFrom = 0;
1556:     
1557:     /**
1558:      * Gets or sets the number of the last page to print. Default is 0 (zero) which means printing ends with the last page.
1559:      * @var integer 
1560:      */
1561:     public $pagesTo = 0;
1562:     
1563:     
1564:     /**
1565:      * Gets or sets the password for this PDF file.
1566:      * @var string 
1567:      */
1568:     public $password = '';
1569:     
1570:     /**
1571:      * Gets or sets whether to perform manual duplex printing. Default is False. Manual duplex lets you print on both sides of a sheet by ordering the print job so that after the first half of the print job has been printed, the job can be flipped over for the second side printing.
1572:      * @var boolean 
1573:      */
1574:     public $duplexPrinting = false;
1575:     
1576:     /**
1577:      * Gets or sets the dialog message to prompt to the user to flip pages after first half of print job has been printed. Default is an empty string.
1578:      * @var string 
1579:      */
1580:     public $duplexPrintingDialogMessage = '';
1581:     
1582:     
1583:     public function serialize() {
1584:         $this->fileExtension = '.wxls';
1585:         
1586:         return parent::serialize();
1587:     }
1588:     
1589:     public function getFileContent(){
1590:  
1591:         $metadata = strval($this->pagesFrom);
1592:         $metadata .= Utils::SER_SEP.strval($this->pagesTo);
1593:         $metadata .= Utils::SER_SEP;
1594:         
1595:         $this->fileIsPasswordProtected = !Utils::isNullOrEmptyString($this->password);
1596: 
1597:         if ($this->fileIsPasswordProtected == false){
1598:             $metadata .= 'N';
1599:         } else {
1600:             if (Utils::isNullOrEmptyString($this->encryptMetadata->publicKeyBase64) == false) {
1601:                 $metadata .= base64_encode(SecUtils::rsaVerifyAndEncrypt($this->encryptMetadata->publicKeyBase64, $this->encryptMetadata->publicKeySignatureBase64, $this->password));
1602:             } else {
1603:                 $metadata .= base64_encode($this->password);
1604:             }
1605:         }
1606:         
1607:         $metadata .= Utils::SER_SEP.($this->duplexPrinting ? '1' : '0');
1608:         $metadata .= Utils::SER_SEP.(Utils::isNullOrEmptyString($this->duplexPrintingDialogMessage) ? 'D' : base64_encode($this->duplexPrintingDialogMessage));
1609:         
1610:         $metadataLength = strlen($metadata);
1611:         $metadata .= Utils::SER_SEP;
1612:         $metadataLength++;
1613:         $metadataLength += strlen(strval($metadataLength));
1614:         $metadata .= strval($metadataLength);
1615:         
1616:         if(!Utils::isNullOrEmptyString($this->filePath)){
1617:             $handle = fopen($this->filePath, 'rb');
1618:             $content = fread($handle, filesize($this->filePath));
1619:             fclose($handle);
1620:         } else {
1621:             $content = $this->fileBinaryContent;
1622:         }
1623:         
1624:         return $content.$metadata;
1625:     }
1626: }
1627: 
1628: /**
1629:  * Utility class for encrypting file content and passwords.
1630:  */
1631: class SecUtils{
1632:    
1633:     private static function getPubKey(){
1634:         return '<RSAKeyValue><Modulus>reXqa092+txbh684R9kUsMMIG2UTEJQChhFkZ3u/kg1OsPAspaWnjRgecq1lTKIbppPXa4NztFNPw5c7W6sN+3GiuRAbOT6E+ynQIyo298znCoeW+W93WZ8imF32HwWn9lUvI6VFJULwjZ16G91ok/YPTuREc8ri7jclC3ie8g0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>';
1635:     }
1636: 
1637:     public static function rsaVerifyAndEncrypt($pubKeyBase64, $pubKeySignatureBase64, $dataToEncrypt){
1638:         $rsa = new \phpseclib\Crypt\RSA();
1639:         $rsa->loadKey(self::getPubKey());
1640:         $rsa->setSignatureMode(2); //SIGNATURE_PKCS1
1641:         if ($rsa->verify(base64_decode($pubKeyBase64), base64_decode($pubKeySignatureBase64))) {
1642:             $rsa->loadKey(base64_decode($pubKeyBase64));
1643:             $rsa->setEncryptionMode(2);//ENCRYPTION_PKCS1
1644:             return $rsa->encrypt($dataToEncrypt);
1645:         }
1646:         else{
1647:             throw new Exception('Cannot verify the provided RSA Public Key.');
1648:         }
1649:     }
1650:     
1651:     public static function aesEncrypt($dataToEncrypt, $password, $salt, $iv, $iterations){
1652:         $aes = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_CBC);
1653:         $aes->setPassword($password, 
1654:                 'pbkdf2' /* key extension algorithm */,
1655:                 'sha1' /* hash algorithm */, 
1656:                 $salt,
1657:                 $iterations,
1658:                 256 / 8
1659:         );
1660:         $aes->setIV($iv);
1661:         return $aes->encrypt($dataToEncrypt);
1662:     }
1663: 
1664: }
1665: 
1666: /**
1667:  * Some utility functions used by WebClientPrint for PHP solution.
1668:  */
1669: class Utils{
1670:     const SER_SEP = '|';
1671:     
1672:     static function isNullOrEmptyString($s){
1673:         return (!isset($s) || trim($s)==='');
1674:     }
1675:     
1676:     static function formatHexValues($s){
1677:         
1678:         $buffer = '';
1679:             
1680:         $l = strlen($s);
1681:         $i = 0;
1682: 
1683:         while ($i < $l)
1684:         {
1685:             if ($s[$i] == '0')
1686:             {
1687:                 if ($i + 1 < $l && ($s[$i] == '0' && $s[$i + 1] == 'x'))
1688:                 {
1689:                     if ($i + 2 < $l &&
1690:                         (($s[$i + 2] >= '0' && $s[$i + 2] <= '9') || ($s[$i + 2] >= 'a' && $s[$i + 2] <= 'f') || ($s[$i + 2] >= 'A' && $s[$i + 2] <= 'F')))
1691:                     {
1692:                         if ($i + 3 < $l &&
1693:                            (($s[$i + 3] >= '0' && $s[$i + 3] <= '9') || ($s[$i + 3] >= 'a' && $s[$i + 3] <= 'f') || ($s[$i + 3] >= 'A' && $s[$i + 3] <= 'F')))
1694:                         {
1695:                             try{
1696:                                 $buffer .= chr(intval(substr($s, $i, 4),16));
1697:                                 $i += 4;
1698:                                 continue;
1699:                                 
1700:                             } catch (Exception $ex) {
1701:                                 throw new Exception("Invalid hex notation in the specified printer commands at index: ".$i);
1702:                             }
1703:                                 
1704:                             
1705:                         }
1706:                         else
1707:                         {
1708:                             try{
1709:                                 
1710:                                 $buffer .= chr(intval(substr($s, $i, 3),16));
1711:                                 $i += 3;
1712:                                 continue;
1713:                                 
1714:                             } catch (Exception $ex) {
1715:                                 throw new ArgumentException("Invalid hex notation in the specified printer commands at index: ".$i);
1716:                             }
1717:                         }
1718:                     }
1719:                 }
1720:             }
1721: 
1722:             $buffer .= substr($s, $i, 1);
1723:             
1724:             $i++;
1725:         }
1726: 
1727:         return $buffer;
1728:         
1729:     }
1730:     
1731:     public static function intToArray($i){
1732:         return pack('C4',
1733:             ($i >>  0) & 0xFF,
1734:             ($i >>  8) & 0xFF,
1735:             ($i >> 16) & 0xFF,
1736:             ($i >> 24) & 0xFF
1737:          );
1738:     }
1739:         
1740:     public static function strleft($s1, $s2) {
1741:     return substr($s1, 0, strpos($s1, $s2));
1742:     }
1743:     
1744:     public static function strContains($s1, $s2){
1745:         return (strpos($s1, $s2) !== false);
1746:     }
1747:     
1748:     public static function strEndsWith($s1, $s2)
1749:     {
1750:         return substr($s1, -strlen($s2)) === $s2;
1751:     }
1752:     
1753:     public static function strStartsWith($s1, $s2)
1754:     {
1755:         return substr($s1, 0, strlen($s2)) === $s2;
1756:     }
1757:     
1758:     public static function genRandomString($asciiCharStart = 33, $asciiCharEnd = 126, $charsCount = 32) {
1759: 
1760:     $allowed_chars = '';
1761:     for($i = $asciiCharStart; $i <= $asciiCharEnd; $i++) {
1762:             $allowed_chars .= chr($i);
1763:         }
1764: 
1765:         $len = strlen($allowed_chars);
1766:         $random_string = '';
1767:         for($i = 0; $i < $charsCount; $i++) {
1768:             $random_string .= $allowed_chars[mt_rand(0, $len - 1)];
1769:         }
1770: 
1771:         return $random_string;
1772:     }
1773:     
1774:     public static function getLicense()
1775:     {
1776:         $lo = WebClientPrint::$licenseOwner;
1777:         $lk = WebClientPrint::$licenseKey;
1778:    
1779:         $uid = substr(uniqid(), 0, 8);
1780: 
1781:         $buffer = 'php>';
1782: 
1783:         if (Utils::isNullOrEmptyString($lo)){
1784:             $buffer .= substr(uniqid(), 0, 8);
1785:         } else {
1786:             $buffer .= $lo;
1787:         }
1788: 
1789:         $buffer .= chr(124); //pipe separator
1790: 
1791:         $license_hash = '';
1792: 
1793:         if (Utils::isNullOrEmptyString($lk)){
1794:             $license_hash = substr(uniqid(), 0, 8);
1795:         } else {
1796:             $license_hash = hash('sha256', $lk . $uid, false);
1797:         }
1798: 
1799:         $buffer .= $license_hash;
1800:         $buffer .= chr(124); //pipe separator
1801:         $buffer .= $uid;    
1802:         
1803:         return $buffer;
1804:     }
1805: }
1806: 
1807: /**
1808:  * Specifies information about the print job to be processed at the client side.
1809:  */
1810: class ClientPrintJob{
1811:     
1812:     /**
1813:      * Gets or sets the ClientPrinter object. Default is NULL.
1814:      * The ClientPrinter object refers to the kind of printer that the client machine has attached or can reach.
1815:      * - Use a DefaultPrinter object for using the default printer installed in the client machine.
1816:      * - Use a InstalledPrinter object for using a printer installed in the client machine with an associated Windows driver.
1817:      * - Use a ParallelPortPrinter object for using a printer which is connected through a parallel port in the client machine.
1818:      * - Use a SerialPortPrinter object for using a printer which is connected through a serial port in the client machine.
1819:      * - Use a NetworkPrinter object for using a Network IP/Ethernet printer which can be reached from the client machine.
1820:      * @var ClientPrinter 
1821:      */
1822:     public $clientPrinter = null;
1823:     /**
1824:      * Gets or sets the printer's commands in text plain format. Default is an empty string.
1825:      * @var string 
1826:      */
1827:     public $printerCommands = '';
1828:     /**
1829:      * Gets or sets the num of copies for Printer Commands. Default is 1.
1830:      * Most Printer Command Languages already provide commands for printing copies. 
1831:      * Always use that command instead of this property. 
1832:      * Refer to the printer command language manual or specification for further details.
1833:      * @var integer 
1834:      */
1835:     public $printerCommandsCopies = 1;
1836:     /**
1837:      * Gets or sets whether the printer commands have chars expressed in hexadecimal notation. Default is false.
1838:      * The string set to the $printerCommands property can contain chars expressed in hexadecimal notation.
1839:      * Many printer languages have commands which are represented by non-printable chars and to express these commands 
1840:      * in a string could require many concatenations and hence be not so readable.
1841:      * By using hex notation, you can make it simple and elegant. Here is an example: if you need to encode ASCII 27 (escape), 
1842:      * then you can represent it as 0x27.        
1843:      * @var boolean 
1844:      */
1845:     public $formatHexValues = false;
1846:     /**
1847:      * Gets or sets the PrintFile object to be printed at the client side. Default is NULL.
1848:      * @var PrintFile 
1849:      */
1850:     public $printFile = null;
1851:     /**
1852:      * Gets or sets an array of PrintFile objects to be printed at the client side. Default is NULL.
1853:      * @var array 
1854:      */
1855:     public $printFileGroup = null;
1856:     
1857:     
1858:     /**
1859:      * Sends this ClientPrintJob object to the client for further processing.
1860:      * The ClientPrintJob object will be processed by the WCPP installed at the client machine.
1861:      * @return string A string representing a ClientPrintJob object.
1862:      */
1863:     public function sendToClient(){
1864:         
1865:         $cpjHeader = chr(99).chr(112).chr(106).chr(2);
1866:         
1867:         $buffer = '';
1868:         
1869:         if (!Utils::isNullOrEmptyString($this->printerCommands)){
1870:             if ($this->printerCommandsCopies > 1){
1871:                 $buffer .= 'PCC='.$this->printerCommandsCopies.Utils::SER_SEP;
1872:             }
1873:             if($this->formatHexValues){
1874:                 $buffer .= Utils::formatHexValues ($this->printerCommands);
1875:             } else {
1876:                 $buffer .= $this->printerCommands;
1877:             }
1878:         } else if (isset ($this->printFile)){
1879:             $buffer = $this->printFile->serialize();
1880:         } else if (isset ($this->printFileGroup)){
1881:             $buffer = 'wcpPFG:';
1882:             $zip = new ZipArchive;
1883:             $cacheFileName = (Utils::strEndsWith(WebClientPrint::$wcpCacheFolder, '/')?WebClientPrint::$wcpCacheFolder:WebClientPrint::$wcpCacheFolder.'/').'PFG'.uniqid().'.zip';
1884:             $res = $zip->open($cacheFileName, ZipArchive::CREATE);
1885:             if ($res === TRUE) {
1886:                 foreach ($this->printFileGroup as $printFile) {
1887:                     $file = $printFile->fileName;
1888:                     if($printFile->copies > 1){
1889:                         $pfc = 'PFC='.$printFile->copies;
1890:                         $file = substr($file, 0, strrpos($file, '.')).$pfc.substr($file, strrpos($file, '.'));
1891:                     }  
1892:                     if(is_a($printFile, 'PrintFilePDF')) $file .= '.wpdf';
1893:                     if(is_a($printFile, 'PrintFileTXT')) $file .= '.wtxt';
1894:                     if(is_a($printFile, 'PrintFileDOC')) $file .= '.wdoc';
1895:                     if(is_a($printFile, 'PrintFileXLS')) $file .= '.wxls';
1896:                     if(is_a($printFile, 'PrintFileTIF')) $file .= '.wtif';
1897:                     
1898:                     $zip->addFromString($file, $printFile->getFileContent());
1899:                 }
1900:                 $zip->close();
1901:                 $handle = fopen($cacheFileName, 'rb');
1902:                 $buffer .= fread($handle, filesize($cacheFileName));
1903:                 fclose($handle);
1904:                 unlink($cacheFileName);
1905:             } else {
1906:                 $buffer='Creating PrintFileGroup failed. Cannot create zip file.';
1907:             }
1908:         }
1909:         
1910:         $arrIdx1 = Utils::intToArray(strlen($buffer));
1911:         
1912:         if (!isset($this->clientPrinter)){
1913:             $this->clientPrinter = new UserSelectedPrinter();
1914:         }    
1915:         
1916:         $buffer .= $this->clientPrinter->serialize();
1917:         
1918:         $arrIdx2 = Utils::intToArray(strlen($buffer));
1919:         
1920:         $buffer .= Utils::getLicense();
1921:         
1922:         return $cpjHeader.$arrIdx1.$arrIdx2.$buffer;
1923:     }
1924:     
1925: }
1926: 
1927: /**
1928:  * Specifies information about a group of ClientPrintJob objects to be processed at the client side.
1929:  */
1930: class ClientPrintJobGroup{
1931:     
1932:     /**
1933:      * Gets or sets an array of ClientPrintJob objects to be processed at the client side. Default is NULL.
1934:      * @var array 
1935:      */
1936:     public $clientPrintJobGroup = null;
1937:     
1938:     /**
1939:      * Sends this ClientPrintJobGroup object to the client for further processing.
1940:      * The ClientPrintJobGroup object will be processed by the WCPP installed at the client machine.
1941:      * @return string A string representing a ClientPrintJobGroup object.
1942:      */
1943:     public function sendToClient(){
1944:         
1945:         if (isset ($this->clientPrintJobGroup)){
1946:             $groups = count($this->clientPrintJobGroup);
1947:             
1948:             $dataPartIndexes = Utils::intToArray($groups);
1949:             
1950:             $cpjgHeader = chr(99).chr(112).chr(106).chr(103).chr(2);
1951:         
1952:             $buffer = '';
1953:             
1954:             $cpjBytesCount = 0;
1955:             
1956:             foreach ($this->clientPrintJobGroup as $cpj) {
1957:                 $cpjBuffer = '';
1958:                 
1959:                 if (!Utils::isNullOrEmptyString($cpj->printerCommands)){
1960:                     if ($cpj->printerCommandsCopies > 1){
1961:                         $cpjBuffer .= 'PCC='.$cpj->printerCommandsCopies.Utils::SER_SEP;
1962:                     }
1963:                     if($cpj->formatHexValues){
1964:                         $cpjBuffer .= Utils::formatHexValues ($cpj->printerCommands);
1965:                     } else {
1966:                         $cpjBuffer .= $cpj->printerCommands;
1967:                     }
1968:                 } else if (isset ($cpj->printFile)){
1969:                     $cpjBuffer = $cpj->printFile->serialize();
1970:                 } else if (isset ($cpj->printFileGroup)){
1971:                     $cpjBuffer = 'wcpPFG:';
1972:                     $zip = new ZipArchive;
1973:                     $cacheFileName = (Utils::strEndsWith(WebClientPrint::$wcpCacheFolder, '/')?WebClientPrint::$wcpCacheFolder:WebClientPrint::$wcpCacheFolder.'/').'PFG'.uniqid().'.zip';
1974:                     $res = $zip->open($cacheFileName, ZipArchive::CREATE);
1975:                     if ($res === TRUE) {
1976:                         foreach ($cpj->printFileGroup as $printFile) {
1977:                             $file = $printFile->fileName;
1978:                             if($printFile->copies > 1){
1979:                                 $pfc = 'PFC='.$printFile->copies;
1980:                                 $file = substr($file, 0, strrpos($file, '.')).$pfc.substr($file, strrpos($file, '.'));
1981:                             }
1982:                             if(is_a($printFile, 'PrintFilePDF')) $file .= '.wpdf';
1983:                             if(is_a($printFile, 'PrintFileTXT')) $file .= '.wtxt';
1984:                             if(is_a($printFile, 'PrintFileDOC')) $file .= '.wdoc';
1985:                             if(is_a($printFile, 'PrintFileXLS')) $file .= '.wxls';
1986:                             if(is_a($printFile, 'PrintFileTIF')) $file .= '.wtif';
1987:                     
1988:                             $zip->addFromString($file, $printFile->getFileContent());
1989:                         }
1990:                         $zip->close();
1991:                         $handle = fopen($cacheFileName, 'rb');
1992:                         $cpjBuffer .= fread($handle, filesize($cacheFileName));
1993:                         fclose($handle);
1994:                         unlink($cacheFileName);
1995:                     } else {
1996:                         $cpjBuffer='Creating PrintFileGroup failed. Cannot create zip file.';
1997:                     }
1998:                 }
1999: 
2000:                 $arrIdx1 = Utils::intToArray(strlen($cpjBuffer));
2001: 
2002:                 if (!isset($cpj->clientPrinter)){
2003:                     $cpj->clientPrinter = new UserSelectedPrinter();
2004:                 }    
2005: 
2006:                 $cpjBuffer .= $cpj->clientPrinter->serialize();
2007:                     
2008:                 $cpjBytesCount += strlen($arrIdx1.$cpjBuffer);
2009:  
2010:                 $dataPartIndexes .= Utils::intToArray($cpjBytesCount);
2011:  
2012:                 $buffer .= $arrIdx1.$cpjBuffer;
2013:             }
2014:                     
2015:             
2016:             $buffer .= Utils::getLicense();
2017: 
2018:             return $cpjgHeader.$dataPartIndexes.$buffer;    
2019:         
2020:         
2021:         } else {
2022:             
2023:             return NULL;
2024:         }
2025:             
2026:         
2027:     }
2028: }
WebClientPrintPHP API documentation generated by ApiGen 2.8.0