Overview

Namespaces

  • Neodynamic
    • SDK
      • Web
  • PHP

Classes

  • ClientPrinter
  • ClientPrintJob
  • ClientPrintJobGroup
  • DefaultPrinter
  • InstalledPrinter
  • NetworkPrinter
  • ParallelPortPrinter
  • PrintFile
  • SerialPortHandshake
  • SerialPortParity
  • SerialPortPrinter
  • SerialPortStopBits
  • UserSelectedPrinter
  • Utils
  • WebClientPrint
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: namespace Neodynamic\SDK\Web;
  4: use Exception;
  5: use ZipArchive;
  6: 
  7: // Setting WebClientPrint
  8: WebClientPrint::$licenseOwner = '';
  9: WebClientPrint::$licenseKey = '';
 10: 
 11: 
 12: /**
 13:  * WebClientPrint provides functions for registering the "WebClientPrint for PHP" solution 
 14:  * script code in PHP web pages as well as for processing client requests and managing the
 15:  * internal cache.
 16:  * 
 17:  * @author Neodynamic <http://neodynamic.com/support>
 18:  * @copyright (c) 2016, Neodynamic SRL
 19:  * @license http://neodynamic.com/eula Neodynamic EULA
 20:  */
 21: class WebClientPrint {
 22:    
 23:     const VERSION = '3.0.2016.0';
 24:     const CLIENT_PRINT_JOB = 'clientPrint';
 25:     const WCP = 'WEB_CLIENT_PRINT';
 26:     const WCP_SCRIPT_AXD_GET_PRINTERS = 'getPrinters';
 27:     const WCPP_SET_PRINTERS = 'printers';
 28:     const WCP_SCRIPT_AXD_GET_WCPPVERSION = 'getWcppVersion';
 29:     const WCPP_SET_VERSION = 'wcppVer';
 30:     const GEN_WCP_SCRIPT_URL = 'u';
 31:     const GEN_DETECT_WCPP_SCRIPT = 'd';
 32:     const SID = 'sid';
 33:     const PING = 'wcppping';
 34:     
 35:     const WCP_CACHE_WCPP_INSTALLED = 'WCPP_INSTALLED';
 36:     const WCP_CACHE_WCPP_VER = 'WCPP_VER';
 37:     const WCP_CACHE_PRINTERS = 'PRINTERS';
 38:     
 39:     
 40:     /**
 41:      * Gets or sets the License Owner
 42:      * @var string 
 43:      */
 44:     static $licenseOwner = '';
 45:     /**
 46:      * Gets or sets the License Key
 47:      * @var string
 48:      */
 49:     static $licenseKey = '';
 50:     /**
 51:      * Gets or sets the ABSOLUTE URL to WebClientPrint.php file
 52:      * @var string
 53:      */
 54:     static $webClientPrintAbsoluteUrl = '';
 55:     /**
 56:      * Gets or sets the wcpcache folder URL RELATIVE to WebClientPrint.php file. 
 57:      * FILE WRITE permission on this folder is required!!!
 58:      * @var string
 59:      */
 60:     static $wcpCacheFolder = '';
 61:     
 62:     /**
 63:      * Adds a new entry to the built-in file system cache. 
 64:      * @param string $sid The user's session id
 65:      * @param string $key The cache entry key
 66:      * @param string $val The data value to put in the cache
 67:      * @throws Exception
 68:      */
 69:     public static function cacheAdd($sid, $key, $val){
 70:         if (Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
 71:             throw new Exception('WebClientPrint wcpCacheFolder is missing, please specify it.');
 72:         }
 73:         if (Utils::isNullOrEmptyString($sid)){
 74:             throw new Exception('WebClientPrint FileName cache is missing, please specify it.');
 75:         }
 76:         $cacheFileName = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/').$sid.'.wcpcache';
 77:         $dataWCPP_VER = '';
 78:         $dataPRINTERS = '';
 79:             
 80:         if(file_exists($cacheFileName)){
 81:             $cache_info = parse_ini_file($cacheFileName);
 82:             
 83:             $dataWCPP_VER = $cache_info[self::WCP_CACHE_WCPP_VER];
 84:             $dataPRINTERS = $cache_info[self::WCP_CACHE_PRINTERS];
 85:         }
 86:         
 87:         if ($key === self::WCP_CACHE_WCPP_VER){
 88:             $dataWCPP_VER = self::WCP_CACHE_WCPP_VER.'='.'"'.$val.'"';
 89:             $dataPRINTERS = self::WCP_CACHE_PRINTERS.'='.'"'.$dataPRINTERS.'"';
 90:         } else if ($key === self::WCP_CACHE_PRINTERS){
 91:             $dataWCPP_VER = self::WCP_CACHE_WCPP_VER.'='.'"'.$dataWCPP_VER.'"';
 92:             $dataPRINTERS = self::WCP_CACHE_PRINTERS.'='.'"'.$val.'"';
 93:         }
 94: 
 95:         $data = $dataWCPP_VER.chr(13).chr(10).$dataPRINTERS;
 96:         $handle = fopen($cacheFileName, 'w') or die('Cannot open file:  '.$cacheFileName);  
 97:         fwrite($handle, $data);
 98:         fclose($handle);
 99:         
100:     }
101:     
102:     /**
103:      * Gets a value from the built-in file system cache based on the specified sid & key 
104:      * @param string $sid The user's session id
105:      * @param string $key The cache entry key
106:      * @return string Returns the value from the cache for the specified sid & key if it's found; or an empty string otherwise.
107:      * @throws Exception
108:      */
109:     public static function cacheGet($sid, $key){
110:         if (Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
111:             throw new Exception('WebClientPrint wcpCacheFolder is missing, please specify it.');
112:         }
113:         if (Utils::isNullOrEmptyString($sid)){
114:             throw new Exception('WebClientPrint FileName cache is missing, please specify it.');
115:         }
116:         $cacheFileName = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/').$sid.'.wcpcache';
117:         if(file_exists($cacheFileName)){
118:             $cache_info = parse_ini_file($cacheFileName, FALSE, INI_SCANNER_RAW);
119:                 
120:             if($key===self::WCP_CACHE_WCPP_VER || $key===self::WCP_CACHE_WCPP_INSTALLED){
121:                 return $cache_info[self::WCP_CACHE_WCPP_VER];
122:             }else if($key===self::WCP_CACHE_PRINTERS){
123:                 return $cache_info[self::WCP_CACHE_PRINTERS];
124:             }else{
125:                 return '';
126:             }
127:         }else{
128:             return '';
129:         }
130:     }
131:     
132:     /**
133:      * Cleans the built-in file system cache
134:      * @param integer $minutes The number of minutes after any files on the cache will be removed.
135:      */
136:     public static function cacheClean($minutes){
137:         if (!Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
138:             $cacheDir = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/');
139:             if ($handle = opendir($cacheDir)) {
140:                  while (false !== ($file = readdir($handle))) {
141:                     if ($file!='.' && $file!='..' && (time()-filectime($cacheDir.$file)) > (60*$minutes)) {
142:                         unlink($cacheDir.$file);
143:                     }
144:                  }
145:                  closedir($handle);
146:             }
147:         }
148:     }
149:     
150:     /**
151:      * Returns script code for detecting whether WCPP is installed at the client machine.
152:      *
153:      * The WCPP-detection script code ends with a 'success' or 'failure' status.
154:      * You can handle both situation by creating two javascript functions which names 
155:      * must be wcppDetectOnSuccess() and wcppDetectOnFailure(). 
156:      * These two functions will be automatically invoked by the WCPP-detection script code.
157:      * 
158:      * The WCPP-detection script uses a delay time variable which by default is 10000 ms (10 sec). 
159:      * You can change it by creating a javascript global variable which name must be wcppPingDelay_ms. 
160:      * For example, to use 5 sec instead of 10, you should add this to your script: 
161:      *   
162:      * var wcppPingDelay_ms = 5000;
163:      *    
164:      * @param string $webClientPrintControllerAbsoluteUrl The Absolute URL to the WebClientPrintController file.
165:      * @param string $sessionID The current Session ID.
166:      * @return string A [script] tag linking to the WCPP-detection script code.
167:      * @throws Exception
168:      */
169:     public static function createWcppDetectionScript($webClientPrintControllerAbsoluteUrl, $sessionID){
170:         
171:         if (Utils::isNullOrEmptyString($webClientPrintControllerAbsoluteUrl) || 
172:             !Utils::strStartsWith($webClientPrintControllerAbsoluteUrl, 'http')){
173:             throw new Exception('WebClientPrintController absolute URL is missing, please specify it.');
174:         }
175:         if (Utils::isNullOrEmptyString($sessionID)){
176:             throw new Exception('Session ID is missing, please specify it.');
177:         }
178:         
179:         $url = $webClientPrintControllerAbsoluteUrl.'?'.self::GEN_DETECT_WCPP_SCRIPT.'='.$sessionID;
180:         return '<script src="'.$url.'" type="text/javascript"></script>';
181:          
182:     }
183:     
184:     
185:     /**
186:      * Returns a [script] tag linking to the WebClientPrint script code by using 
187:      * the specified URL for the client print job generation.
188:      * 
189:      * @param string $webClientPrintControllerAbsoluteUrl The Absolute URL to the WebClientPrintController file.
190:      * @param string $clientPrintJobAbsoluteUrl The Absolute URL to the PHP file that creates ClientPrintJob objects.
191:      * @paran string $sessionID The current Session ID.
192:      * @return string A [script] tag linking to the WebClientPrint script code by using the specified URL for the client print job generation.
193:      * @throws Exception
194:      */
195:     public static function createScript($webClientPrintControllerAbsoluteUrl, $clientPrintJobAbsoluteUrl, $sessionID){
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($clientPrintJobAbsoluteUrl) || 
201:             !Utils::strStartsWith($clientPrintJobAbsoluteUrl, 'http')){
202:             throw new Exception('ClientPrintJob absolute URL is missing, please specify it.');
203:         }
204:         if (Utils::isNullOrEmptyString($sessionID)){
205:             throw new Exception('Session ID is missing, please specify it.');
206:         }
207:         
208:         
209:         $wcpHandler = $webClientPrintControllerAbsoluteUrl.'?';
210:         $wcpHandler .= self::VERSION;
211:         $wcpHandler .= '&';
212:         $wcpHandler .= microtime(true);
213:         $wcpHandler .= '&sid=';
214:         $wcpHandler .= $sessionID;
215:         $wcpHandler .= '&'.self::GEN_WCP_SCRIPT_URL.'=';
216:         $wcpHandler .= base64_encode($clientPrintJobAbsoluteUrl);
217:         return '<script src="'.$wcpHandler.'" type="text/javascript"></script>';
218:     }
219:     
220:     
221:     /**
222:      * Generates the WebClientPrint scripts based on the specified query string. Result is stored in the HTTP Response Content
223:      * 
224:      * @param type $webClientPrintControllerAbsoluteUrl The Absolute URL to the WebClientPrintController file.
225:      * @param type $queryString The Query String from current HTTP Request.
226:      */
227:     public static function generateScript($webClientPrintControllerAbsoluteUrl, $queryString)
228:     {
229:         if (Utils::isNullOrEmptyString($webClientPrintControllerAbsoluteUrl) || 
230:             !Utils::strStartsWith($webClientPrintControllerAbsoluteUrl, 'http')){
231:             throw new Exception('WebClientPrintController absolute URL is missing, please specify it.');
232:         }
233:         
234:         parse_str($queryString, $qs);
235:     
236:         if(isset($qs[self::GEN_DETECT_WCPP_SCRIPT])){
237:             
238:             $curSID = $qs[self::GEN_DETECT_WCPP_SCRIPT];
239:             $onSuccessScript = 'wcppDetectOnSuccess(data);';
240:             $onFailureScript = 'wcppDetectOnFailure();';
241:             $dynamicIframeId = 'i'.substr(uniqid(), 0, 3);
242:             $absoluteWcpAxd = $webClientPrintControllerAbsoluteUrl.'?'.self::SID.'='.$curSID;
243:             
244:             $s1 = 'dmFyIGpzV0NQUD0oZnVuY3Rpb24oKXt2YXIgc2V0PDw8LU5FTy1IVE1MLUlELT4+Pj1mdW5jdGlvbigpe2lmKHdpbmRvdy5jaHJvbWUpeyQoJyM8PDwtTkVPLUhUTUwtSUQtPj4+JykuYXR0cignaHJlZicsJ3dlYmNsaWVudHByaW50OicrYXJndW1lbnRzWzBdKTt2YXIgYT0kKCdhIzw8PC1ORU8tSFRNTC1JRC0+Pj4nKVswXTt2YXIgZXZPYmo9ZG9jdW1lbnQuY3JlYXRlRXZlbnQoJ01vdXNlRXZlbnRzJyk7ZXZPYmouaW5pdEV2ZW50KCdjbGljaycsdHJ1ZSx0cnVlKTthLmRpc3BhdGNoRXZlbnQoZXZPYmopfWVsc2V7JCgnIzw8PC1ORU8tSFRNTC1JRC0+Pj4nKS5hdHRyKCdzcmMnLCd3ZWJjbGllbnRwcmludDonK2FyZ3VtZW50c1swXSl9fTtyZXR1cm57aW5pdDpmdW5jdGlvbigpe2lmKHdpbmRvdy5jaHJvbWUpeyQoJzxhIC8+Jyx7aWQ6Jzw8PC1ORU8tSFRNTC1JRC0+Pj4nfSkuYXBwZW5kVG8oJ2JvZHknKX1lbHNleyQoJzxpZnJhbWUgLz4nLHtuYW1lOic8PDwtTkVPLUhUTUwtSUQtPj4+JyxpZDonPDw8LU5FTy1IVE1MLUlELT4+Picsd2lkdGg6JzEnLGhlaWdodDonMScsc3R5bGU6J3Zpc2liaWxpdHk6aGlkZGVuO3Bvc2l0aW9uOmFic29sdXRlJ30pLmFwcGVuZFRvKCdib2R5Jyl9fSxwaW5nOmZ1bmN0aW9uKCl7c2V0PDw8LU5FTy1IVE1MLUlELT4+PignPDw8LU5FTy1QSU5HLVVSTC0+Pj4nKyhhcmd1bWVudHMubGVuZ3RoPT0xPycmJythcmd1bWVudHNbMF06JycpKTt2YXIgZGVsYXlfbXM9KHR5cGVvZiB3Y3BwUGluZ0RlbGF5X21zPT09J3VuZGVmaW5lZCcpPzEwMDAwOndjcHBQaW5nRGVsYXlfbXM7c2V0VGltZW91dChmdW5jdGlvbigpeyQuZ2V0KCc8PDwtTkVPLVVTRVItSEFTLVdDUFAtPj4+JyxmdW5jdGlvbihkYXRhKXtpZihkYXRhLmxlbmd0aCA+IDApezw8PC1ORU8tT04tU1VDQ0VTUy1TQ1JJUFQtPj4+fWVsc2V7PDw8LU5FTy1PTi1GQUlMVVJFLVNDUklQVC0+Pj59fSl9LGRlbGF5X21zKX19fSkoKTsgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtqc1dDUFAuaW5pdCgpO2pzV0NQUC5waW5nKCk7fSk7';
245:     
246:             $s2 = base64_decode($s1);
247:             $s2 = str_replace('<<<-NEO-HTML-ID->>>', $dynamicIframeId, $s2);
248:             $s2 = str_replace('<<<-NEO-PING-URL->>>', $absoluteWcpAxd.'&'.self::PING, $s2);
249:             $s2 = str_replace('<<<-NEO-USER-HAS-WCPP->>>', $absoluteWcpAxd, $s2);
250:             $s2 = str_replace('<<<-NEO-ON-SUCCESS-SCRIPT->>>', $onSuccessScript, $s2);
251:             $s2 = str_replace('<<<-NEO-ON-FAILURE-SCRIPT->>>', $onFailureScript, $s2);
252:             
253:             return $s2;
254:             
255:         }else if(isset($qs[self::GEN_WCP_SCRIPT_URL])){
256:             
257:             $clientPrintJobUrl = base64_decode($qs[self::GEN_WCP_SCRIPT_URL]);
258:             if (strpos($clientPrintJobUrl, '?')>0){
259:                 $clientPrintJobUrl .= '&';
260:             }else{
261:                 $clientPrintJobUrl .= '?';
262:             }
263:             $clientPrintJobUrl .= self::CLIENT_PRINT_JOB;
264:             $absoluteWcpAxd = $webClientPrintControllerAbsoluteUrl;
265:             $wcppGetPrintersParam = '-getPrinters:'.$absoluteWcpAxd.'?'.self::WCP.'&'.self::SID.'=';
266:             $wcpHandlerGetPrinters = $absoluteWcpAxd.'?'.self::WCP.'&'.self::WCP_SCRIPT_AXD_GET_PRINTERS.'&'.self::SID.'=';
267:             $wcppGetWcppVerParam = '-getWcppVersion:'.$absoluteWcpAxd.'?'.self::WCP.'&'.self::SID.'=';
268:             $wcpHandlerGetWcppVer = $absoluteWcpAxd.'?'.self::WCP.'&'.self::WCP_SCRIPT_AXD_GET_WCPPVERSION.'&'.self::SID.'=';
269:             $sessionIDVal = $qs[self::SID];
270:         
271:             $s1 = 'dmFyIGpzV2ViQ2xpZW50UHJpbnQ9KGZ1bmN0aW9uKCl7dmFyIHNldEE9ZnVuY3Rpb24oKXt2YXIgZV9pZD0naWRfJytuZXcgRGF0ZSgpLmdldFRpbWUoKTtpZih3aW5kb3cuY2hyb21lKXskKCdib2R5JykuYXBwZW5kKCc8YSBpZD1cIicrZV9pZCsnXCI+PC9hPicpOyQoJyMnK2VfaWQpLmF0dHIoJ2hyZWYnLCd3ZWJjbGllbnRwcmludDonK2FyZ3VtZW50c1swXSk7dmFyIGE9JCgnYSMnK2VfaWQpWzBdO3ZhciBldk9iaj1kb2N1bWVudC5jcmVhdGVFdmVudCgnTW91c2VFdmVudHMnKTtldk9iai5pbml0RXZlbnQoJ2NsaWNrJyx0cnVlLHRydWUpO2EuZGlzcGF0Y2hFdmVudChldk9iail9ZWxzZXskKCdib2R5JykuYXBwZW5kKCc8aWZyYW1lIG5hbWU9XCInK2VfaWQrJ1wiIGlkPVwiJytlX2lkKydcIiB3aWR0aD1cIjFcIiBoZWlnaHQ9XCIxXCIgc3R5bGU9XCJ2aXNpYmlsaXR5OmhpZGRlbjtwb3NpdGlvbjphYnNvbHV0ZVwiIC8+Jyk7JCgnIycrZV9pZCkuYXR0cignc3JjJywnd2ViY2xpZW50cHJpbnQ6Jythcmd1bWVudHNbMF0pfXNldFRpbWVvdXQoZnVuY3Rpb24oKXskKCcjJytlX2lkKS5yZW1vdmUoKX0sNTAwMCl9O3JldHVybntwcmludDpmdW5jdGlvbigpe3NldEEoJ1VSTF9QUklOVF9KT0InKyhhcmd1bWVudHMubGVuZ3RoPT0xPycmJythcmd1bWVudHNbMF06JycpKX0sZ2V0UHJpbnRlcnM6ZnVuY3Rpb24oKXtzZXRBKCdVUkxfV0NQX0FYRF9XSVRIX0dFVF9QUklOVEVSU19DT01NQU5EJysnPDw8LU5FTy1TRVNTSU9OLUlELT4+PicpO3ZhciBkZWxheV9tcz0odHlwZW9mIHdjcHBHZXRQcmludGVyc0RlbGF5X21zPT09J3VuZGVmaW5lZCcpPzEwMDAwOndjcHBHZXRQcmludGVyc0RlbGF5X21zO3NldFRpbWVvdXQoZnVuY3Rpb24oKXskLmdldCgnVVJMX1dDUF9BWERfR0VUX1BSSU5URVJTJysnPDw8LU5FTy1TRVNTSU9OLUlELT4+PicsZnVuY3Rpb24oZGF0YSl7aWYoZGF0YS5sZW5ndGg+MCl7d2NwR2V0UHJpbnRlcnNPblN1Y2Nlc3MoZGF0YSl9ZWxzZXt3Y3BHZXRQcmludGVyc09uRmFpbHVyZSgpfX0pfSxkZWxheV9tcyl9LGdldFdjcHBWZXI6ZnVuY3Rpb24oKXtzZXRBKCdVUkxfV0NQX0FYRF9XSVRIX0dFVF9XQ1BQVkVSU0lPTl9DT01NQU5EJysnPDw8LU5FTy1TRVNTSU9OLUlELT4+PicpO3ZhciBkZWxheV9tcz0odHlwZW9mIHdjcHBHZXRWZXJEZWxheV9tcz09PSd1bmRlZmluZWQnKT8xMDAwMDp3Y3BwR2V0VmVyRGVsYXlfbXM7c2V0VGltZW91dChmdW5jdGlvbigpeyQuZ2V0KCdVUkxfV0NQX0FYRF9HRVRfV0NQUFZFUlNJT04nKyc8PDwtTkVPLVNFU1NJT04tSUQtPj4+JyxmdW5jdGlvbihkYXRhKXtpZihkYXRhLmxlbmd0aD4wKXt3Y3BHZXRXY3BwVmVyT25TdWNjZXNzKGRhdGEpfWVsc2V7d2NwR2V0V2NwcFZlck9uRmFpbHVyZSgpfX0pfSxkZWxheV9tcyl9LHNlbmQ6ZnVuY3Rpb24oKXtzZXRBLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19fSkoKTs=';
272:     
273:             $s2 = base64_decode($s1);
274:             $s2 = str_replace('URL_PRINT_JOB', $clientPrintJobUrl, $s2);
275:             $s2 = str_replace('URL_WCP_AXD_WITH_GET_PRINTERS_COMMAND', $wcppGetPrintersParam, $s2);
276:             $s2 = str_replace('URL_WCP_AXD_GET_PRINTERS', $wcpHandlerGetPrinters, $s2);
277:             $s2 = str_replace('URL_WCP_AXD_WITH_GET_WCPPVERSION_COMMAND', $wcppGetWcppVerParam, $s2);
278:             $s2 = str_replace('URL_WCP_AXD_GET_WCPPVERSION', $wcpHandlerGetWcppVer, $s2);
279:             $s2 = str_replace('<<<-NEO-SESSION-ID->>>', $sessionIDVal, $s2);
280:             
281:             return $s2;
282:         }
283:         
284:     }
285:     
286:        
287:     /**
288:      * Generates printing script.
289:      */
290:     const GenPrintScript = 0;
291:     /**
292:      * Generates WebClientPrint Processor (WCPP) detection script.
293:      */ 
294:     const GenWcppDetectScript = 1;
295:     /**
296:      * Sets the installed printers list in the website cache.
297:      */        
298:     const ClientSetInstalledPrinters = 2;
299:     /**
300:      * Gets the installed printers list from the website cache.
301:      */
302:     const ClientGetInstalledPrinters = 3;
303:     /**
304:      * Sets the WebClientPrint Processor (WCPP) Version in the website cache.
305:      */
306:     const ClientSetWcppVersion = 4;
307:     /**
308:      * Gets the WebClientPrint Processor (WCPP) Version from the website cache.
309:      */
310:     const ClientGetWcppVersion = 5;
311:     
312:     /**
313:      * Determines the type of process request based on the Query String value. 
314:      * 
315:      * @param string $queryString The query string of the current request.
316:      * @return integer A valid type of process request. In case of an invalid value, an Exception is thrown.
317:      * @throws Exception 
318:      */
319:     public static function GetProcessRequestType($queryString){
320:         parse_str($queryString, $qs);
321:     
322:         if(isset($qs[self::SID])){
323:             if(isset($qs[self::PING])){
324:                 return self::ClientSetWcppVersion;
325:             } else if(isset($qs[self::WCPP_SET_VERSION])){
326:                 return self::ClientSetWcppVersion;
327:             } else if(isset($qs[self::WCPP_SET_PRINTERS])){
328:                 return self::ClientSetInstalledPrinters;
329:             } else if(isset($qs[self::WCP_SCRIPT_AXD_GET_WCPPVERSION])){
330:                 return self::ClientGetWcppVersion;
331:             } else if(isset($qs[self::WCP_SCRIPT_AXD_GET_PRINTERS])){
332:                 return self::ClientGetInstalledPrinters;
333:             } else if(isset($qs[self::GEN_WCP_SCRIPT_URL])){
334:                 return self::GenPrintScript;
335:             } else {
336:                 return self::ClientGetWcppVersion;
337:             }
338:         } else if(isset($qs[self::GEN_DETECT_WCPP_SCRIPT])){
339:             return self::GenWcppDetectScript;
340:         } else {
341:             throw new Exception('No valid ProcessRequestType was found in the specified QueryString.');
342:         }
343:     }
344:     
345: }
346: 
347: /**
348:  * The base class for all kind of printers supported at the client side.
349:  */
350: abstract class ClientPrinter{
351:     
352:     public $printerId;
353:     public function serialize(){
354:         
355:     }
356: }
357: 
358: /**
359:  * It represents the default printer installed in the client machine.
360:  */
361: class DefaultPrinter extends ClientPrinter{
362:     public function __construct() {
363:         $this->printerId = chr(0);
364:     }
365:     
366:     public function serialize() {
367:         return $this->printerId;
368:     }
369: }
370: 
371: /**
372:  * It represents a printer installed in the client machine with an associated OS driver.
373:  */
374: class InstalledPrinter extends ClientPrinter{
375:     
376:     /**
377:      * Gets or sets the name of the printer installed in the client machine. Default value is an empty string.
378:      * @var string 
379:      */
380:     public $printerName = '';
381: 
382:     /**
383:      * Gets or sets whether to print to Default printer in case of the specified one is not found or missing. Default is False.
384:      * @var boolean 
385:      */
386:     public $printToDefaultIfNotFound = false;
387:     
388:     /**
389:      * Creates an instance of the InstalledPrinter class with the specified printer name.
390:      * @param string $printerName The name of the printer installed in the client machine.
391:      */
392:     public function __construct($printerName) {
393:         $this->printerId = chr(1);
394:         $this->printerName = $printerName;
395:     }
396:     
397:     public function serialize() {
398:         
399:         if (Utils::isNullOrEmptyString($this->printerName)){
400:              throw new Exception("The specified printer name is null or empty.");
401:         }
402:         
403:         if ($this->printToDefaultIfNotFound){
404:             return $this->printerId.$this->printerName.Utils::SER_SEP.'1';     
405:         }  else {
406:             return $this->printerId.$this->printerName;    
407:         }      
408:         
409:     }
410: }
411: 
412: /**
413:  * It represents a printer which is connected through a parallel port in the client machine.
414:  */
415: class ParallelPortPrinter extends ClientPrinter{
416:     
417:     /**
418:      * Gets or sets the parallel port name, for example LPT1. Default value is "LPT1"
419:      * @var string 
420:      */
421:     public $portName = "LPT1";
422: 
423:     /**
424:      * Creates an instance of the ParallelPortPrinter class with the specified port name.
425:      * @param string $portName The parallel port name, for example LPT1.
426:      */
427:     public function __construct($portName) {
428:         $this->printerId = chr(2);
429:         $this->portName = $portName;
430:     }
431:     
432:     public function serialize() {
433:         
434:         if (Utils::isNullOrEmptyString($this->portName)){
435:              throw new Exception("The specified parallel port name is null or empty.");
436:         }
437:         
438:         return $this->printerId.$this->portName;
439:     }
440: }
441: 
442: /**
443:  * It represents a printer which is connected through a serial port in the client machine.
444:  */
445: class SerialPortPrinter extends ClientPrinter{
446:     
447:     /**
448:      * Gets or sets the serial port name, for example COM1. Default value is "COM1"
449:      * @var string 
450:      */
451:     public $portName = "COM1";
452:     /**
453:      * Gets or sets the serial port baud rate in bits per second. Default value is 9600
454:      * @var integer 
455:      */
456:     public $baudRate = 9600;
457:     /**
458:      * Gets or sets the serial port parity-checking protocol. Default value is NONE = 0
459:      * NONE = 0, ODD = 1, EVEN = 2, MARK = 3, SPACE = 4
460:      * @var integer 
461:      */
462:     public $parity = SerialPortParity::NONE;
463:     /**
464:      * Gets or sets the serial port standard number of stopbits per byte. Default value is ONE = 1
465:      * ONE = 1, TWO = 2, ONE_POINT_FIVE = 3
466:      * @var integer
467:      */
468:     public $stopBits = SerialPortStopBits::ONE;
469:     /**
470:      * Gets or sets the serial port standard length of data bits per byte. Default value is 8
471:      * @var integer
472:      */
473:     public $dataBits = 8;
474:     /**
475:      * Gets or sets the handshaking protocol for serial port transmission of data. Default value is XON_XOFF = 1
476:      * NONE = 0, REQUEST_TO_SEND = 2, REQUEST_TO_SEND_XON_XOFF = 3, XON_XOFF = 1
477:      * @var integer
478:      */
479:     public $flowControl = SerialPortHandshake::XON_XOFF;
480:     
481:     /**
482:      * Creates an instance of the SerialPortPrinter class wiht the specified information.
483:      * @param string $portName The serial port name, for example COM1.
484:      * @param integer $baudRate The serial port baud rate in bits per second.
485:      * @param integer $parity The serial port parity-checking protocol.
486:      * @param integer $stopBits The serial port standard number of stopbits per byte.
487:      * @param integer $dataBits The serial port standard length of data bits per byte.
488:      * @param integer $flowControl The handshaking protocol for serial port transmission of data.
489:      */
490:     public function __construct($portName, $baudRate, $parity, $stopBits, $dataBits, $flowControl) {
491:         $this->printerId = chr(3);
492:         $this->portName = $portName;
493:         $this->baudRate = $baudRate;
494:         $this->parity = $parity;
495:         $this->stopBits = $stopBits;
496:         $this->dataBits = $dataBits;
497:         $this->flowControl = $flowControl;
498:     }
499:     
500:     public function serialize() {
501:         
502:         if (Utils::isNullOrEmptyString($this->portName)){
503:              throw new Exception("The specified serial port name is null or empty.");
504:         }
505:         
506:         return $this->printerId.$this->portName.Utils::SER_SEP.$this->baudRate.Utils::SER_SEP.$this->dataBits.Utils::SER_SEP.$this->flowControl.Utils::SER_SEP.$this->parity.Utils::SER_SEP.$this->stopBits;
507:     }
508: }
509: 
510: /**
511:  * It represents a Network IP/Ethernet printer which can be reached from the client machine.
512:  */
513: class NetworkPrinter extends ClientPrinter{
514:     
515:     /**
516:      * Gets or sets the DNS name assigned to the printer. Default is an empty string
517:      * @var string 
518:      */
519:     public $dnsName = "";
520:     /**
521:      * Gets or sets the Internet Protocol (IP) address assigned to the printer. Default value is an empty string
522:      * @var string 
523:      */
524:     public $ipAddress = "";
525:     /**
526:      * Gets or sets the port number assigned to the printer. Default value is 0
527:      * @var integer 
528:      */
529:     public $port = 0;
530:     
531:     /**
532:      * Creates an instance of the NetworkPrinter class with the specified DNS name or IP Address, and port number.
533:      * @param string $dnsName The DNS name assigned to the printer.
534:      * @param string $ipAddress The Internet Protocol (IP) address assigned to the printer.
535:      * @param integer $port The port number assigned to the printer.
536:      */
537:     public function __construct($dnsName, $ipAddress, $port) {
538:         $this->printerId = chr(4);
539:         $this->dnsName = $dnsName;
540:         $this->ipAddress = $ipAddress;
541:         $this->port = $port;
542:     }
543:     
544:     public function serialize() {
545:         
546:         if (Utils::isNullOrEmptyString($this->dnsName) && Utils::isNullOrEmptyString($this->ipAddress)){
547:              throw new Exception("The specified network printer settings is not valid. You must specify the DNS Printer Name or its IP address.");
548:         }
549:         
550:         return $this->printerId.$this->dnsName.Utils::SER_SEP.$this->ipAddress.Utils::SER_SEP.$this->port;
551:     }
552: }
553: 
554: /**
555:  *  It represents a printer which will be selected by the user in the client machine. The user will be prompted with a print dialog.
556:  */
557: class UserSelectedPrinter extends ClientPrinter{
558:     public function __construct() {
559:         $this->printerId = chr(5);
560:     }
561:     
562:     public function serialize() {
563:         return $this->printerId;
564:     }
565: }
566: 
567: /**
568:  * Specifies the parity bit for Serial Port settings. 
569:  */
570: class SerialPortParity{
571:     const NONE = 0;
572:     const ODD = 1;
573:     const EVEN = 2;
574:     const MARK = 3;
575:     const SPACE = 4;
576: }
577: 
578: /**
579:  * Specifies the number of stop bits used for Serial Port settings.
580:  */
581: class SerialPortStopBits{
582:     const NONE = 0;
583:     const ONE = 1;
584:     const TWO = 2;
585:     const ONE_POINT_FIVE = 3;
586: }
587: 
588: /**
589:  * Specifies the control protocol used in establishing a serial port communication.
590:  */
591: class SerialPortHandshake{
592:     const NONE = 0;
593:     const REQUEST_TO_SEND = 2;
594:     const REQUEST_TO_SEND_XON_XOFF = 3;
595:     const XON_XOFF = 1;
596: }
597: 
598: /**
599:  * It represents a file in the server that will be printed at the client side.
600:  */
601: class PrintFile{
602:     
603:     /**
604:      * Gets or sets the path of the file at the server side that will be printed at the client side.
605:      * @var string 
606:      */
607:     public $filePath = '';
608:     /**
609:      * Gets or sets the file name that will be created at the client side. 
610:      * It must include the file extension like .pdf, .txt, .doc, .xls, etc.
611:      * @var string 
612:      */
613:     public $fileName = '';
614:     /**
615:      * Gets or sets the binary content of the file at the server side that will be printed at the client side.
616:      * @var string 
617:      */
618:     public $fileBinaryContent = '';
619:     
620:     /**
621:      * Gets or sets the num of copies for printing this file. Default is 1.
622:      * @var integer
623:      */
624:     public $copies = 1;
625:     
626:     const PREFIX = 'wcpPF:';
627:     const SEP = '|';
628:         
629:     /**
630:      * 
631:      * @param string $filePath The path of the file at the server side that will be printed at the client side.
632:      * @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.
633:      * @param string $fileBinaryContent The binary content of the file at the server side that will be printed at the client side.
634:      */
635:     public function __construct($filePath, $fileName, $fileBinaryContent) {
636:         $this->filePath = $filePath;
637:         $this->fileName = $fileName;
638:         $this->fileBinaryContent = $fileBinaryContent;
639:         
640:     }
641:     
642:     public function serialize() {
643:         $file = str_replace('\\', 'BACKSLASHCHAR',$this->fileName );
644:         if($this->copies > 1){
645:              $pfc = 'PFC='.$this->copies;
646:              $file = substr($file, 0, strrpos($file, '.')).$pfc.substr($file, strrpos($file, '.'));
647:         }
648:         return self::PREFIX.$file.self::SEP.$this->getFileContent();
649:     }
650:     
651:     public function getFileContent(){
652:         $content = $this->fileBinaryContent;
653:         if(!Utils::isNullOrEmptyString($this->filePath)){
654:             $handle = fopen($this->filePath, 'rb');
655:             $content = fread($handle, filesize($this->filePath));
656:             fclose($handle);
657:         }
658:         return $content;
659:     }
660: }
661: 
662: /**
663:  * Some utility functions used by WebClientPrint for PHP solution.
664:  */
665: class Utils{
666:     const SER_SEP = "|";
667:     
668:     static function isNullOrEmptyString($s){
669:         return (!isset($s) || trim($s)==='');
670:     }
671:     
672:     static function formatHexValues($s){
673:         
674:         $buffer = '';
675:             
676:         $l = strlen($s);
677:         $i = 0;
678: 
679:         while ($i < $l)
680:         {
681:             if ($s[$i] == '0')
682:             {
683:                 if ($i + 1 < $l && ($s[$i] == '0' && $s[$i + 1] == 'x'))
684:                 {
685:                     if ($i + 2 < $l &&
686:                         (($s[$i + 2] >= '0' && $s[$i + 2] <= '9') || ($s[$i + 2] >= 'a' && $s[$i + 2] <= 'f') || ($s[$i + 2] >= 'A' && $s[$i + 2] <= 'F')))
687:                     {
688:                         if ($i + 3 < $l &&
689:                            (($s[$i + 3] >= '0' && $s[$i + 3] <= '9') || ($s[$i + 3] >= 'a' && $s[$i + 3] <= 'f') || ($s[$i + 3] >= 'A' && $s[$i + 3] <= 'F')))
690:                         {
691:                             try{
692:                                 $buffer .= chr(substr($s, $i, 4));
693:                                 $i += 4;
694:                                 continue;
695:                                 
696:                             } catch (Exception $ex) {
697:                                 throw new Exception("Invalid hex notation in the specified printer commands at index: ".$i);
698:                             }
699:                                 
700:                             
701:                         }
702:                         else
703:                         {
704:                             try{
705:                                 
706:                                 $buffer .= chr(substr($s, $i, 3));
707:                                 $i += 3;
708:                                 continue;
709:                                 
710:                             } catch (Exception $ex) {
711:                                 throw new ArgumentException("Invalid hex notation in the specified printer commands at index: ".$i);
712:                             }
713:                         }
714:                     }
715:                 }
716:             }
717: 
718:             $buffer .= substr($s, $i, 1);
719:             
720:             $i++;
721:         }
722: 
723:         return $buffer;
724:         
725:     }
726:     
727:     public static function intToArray($i){
728:         return pack("L", $i);
729:     }
730:         
731:     public static function strleft($s1, $s2) {
732:     return substr($s1, 0, strpos($s1, $s2));
733:     }
734:     
735:     public static function strContains($s1, $s2){
736:         return (strpos($s1, $s2) !== false);
737:     }
738:     
739:     public static function strEndsWith($s1, $s2)
740:     {
741:         return substr($s1, -strlen($s2)) === $s2;
742:     }
743:     
744:     public static function strStartsWith($s1, $s2)
745:     {
746:         return substr($s1, 0, strlen($s2)) === $s2;
747:     }
748:     
749: }
750: 
751: /**
752:  * Specifies information about the print job to be processed at the client side.
753:  */
754: class ClientPrintJob{
755:     
756:     /**
757:      * Gets or sets the ClientPrinter object. Default is NULL.
758:      * The ClientPrinter object refers to the kind of printer that the client machine has attached or can reach.
759:      * - Use a DefaultPrinter object for using the default printer installed in the client machine.
760:      * - Use a InstalledPrinter object for using a printer installed in the client machine with an associated Windows driver.
761:      * - Use a ParallelPortPrinter object for using a printer which is connected through a parallel port in the client machine.
762:      * - Use a SerialPortPrinter object for using a printer which is connected through a serial port in the client machine.
763:      * - Use a NetworkPrinter object for using a Network IP/Ethernet printer which can be reached from the client machine.
764:      * @var ClientPrinter 
765:      */
766:     public $clientPrinter = null;
767:     /**
768:      * Gets or sets the printer's commands in text plain format. Default is an empty string.
769:      * @var string 
770:      */
771:     public $printerCommands = '';
772:     /**
773:      * Gets or sets the num of copies for Printer Commands. Default is 1.
774:      * Most Printer Command Languages already provide commands for printing copies. 
775:      * Always use that command instead of this property. 
776:      * Refer to the printer command language manual or specification for further details.
777:      * @var integer 
778:      */
779:     public $printerCommandsCopies = 1;
780:     /**
781:      * Gets or sets whether the printer commands have chars expressed in hexadecimal notation. Default is false.
782:      * The string set to the $printerCommands property can contain chars expressed in hexadecimal notation.
783:      * Many printer languages have commands which are represented by non-printable chars and to express these commands 
784:      * in a string could require many concatenations and hence be not so readable.
785:      * By using hex notation, you can make it simple and elegant. Here is an example: if you need to encode ASCII 27 (escape), 
786:      * then you can represent it as 0x27.        
787:      * @var boolean 
788:      */
789:     public $formatHexValues = false;
790:     /**
791:      * Gets or sets the PrintFile object to be printed at the client side. Default is NULL.
792:      * @var PrintFile 
793:      */
794:     public $printFile = null;
795:     /**
796:      * Gets or sets an array of PrintFile objects to be printed at the client side. Default is NULL.
797:      * @var array 
798:      */
799:     public $printFileGroup = null;
800:     
801:     
802:     /**
803:      * Sends this ClientPrintJob object to the client for further processing.
804:      * The ClientPrintJob object will be processed by the WCPP installed at the client machine.
805:      * @return string A string representing a ClientPrintJob object.
806:      */
807:     public function sendToClient(){
808:         
809:         $cpjHeader = chr(99).chr(112).chr(106).chr(2);
810:         
811:         $buffer = '';
812:         
813:         if (!Utils::isNullOrEmptyString($this->printerCommands)){
814:             if ($this->printerCommandsCopies > 1){
815:                 $buffer .= 'PCC='.$this->printerCommandsCopies.Utils::SER_SEP;
816:             }
817:             if($this->formatHexValues){
818:                 $buffer .= Utils::formatHexValues ($this->printerCommands);
819:             } else {
820:                 $buffer .= $this->printerCommands;
821:             }
822:         } else if (isset ($this->printFile)){
823:             $buffer = $this->printFile->serialize();
824:         } else if (isset ($this->printFileGroup)){
825:             $buffer = 'wcpPFG:';
826:             $zip = new ZipArchive;
827:             $cacheFileName = (Utils::strEndsWith(WebClientPrint::$wcpCacheFolder, '/')?WebClientPrint::$wcpCacheFolder:WebClientPrint::$wcpCacheFolder.'/').'PFG'.uniqid().'.zip';
828:             $res = $zip->open($cacheFileName, ZipArchive::CREATE);
829:             if ($res === TRUE) {
830:                 foreach ($this->printFileGroup as $printFile) {
831:                     $file = $printFile->fileName;
832:                     if($printFile->copies > 1){
833:                         $pfc = 'PFC='.$printFile->copies;
834:                         $file = substr($file, 0, strrpos($file, '.')).$pfc.substr($file, strrpos($file, '.'));
835:                     }   
836:                     $zip->addFromString($file, $printFile->getFileContent());
837:                 }
838:                 $zip->close();
839:                 $handle = fopen($cacheFileName, 'rb');
840:                 $buffer .= fread($handle, filesize($cacheFileName));
841:                 fclose($handle);
842:                 unlink($cacheFileName);
843:             } else {
844:                 $buffer='Creating PrintFileGroup failed. Cannot create zip file.';
845:             }
846:         }
847:         
848:         $arrIdx1 = Utils::intToArray(strlen($buffer));
849:         
850:         if (!isset($this->clientPrinter)){
851:             $this->clientPrinter = new UserSelectedPrinter();
852:         }    
853:         
854:         $buffer .= $this->clientPrinter->serialize();
855:         
856:         $arrIdx2 = Utils::intToArray(strlen($buffer));
857:         
858:         $lo = '';
859:         if(Utils::isNullOrEmptyString(WebClientPrint::$licenseOwner)){
860:             $lo = substr(uniqid(), 0, 8);
861:         }  else {
862:             $lo = 'php>'.base64_encode(WebClientPrint::$licenseOwner);
863:         }
864:         $lk = '';
865:         if(Utils::isNullOrEmptyString(WebClientPrint::$licenseKey)){
866:             $lk = substr(uniqid(), 0, 8);
867:         }  else {
868:             $lk = WebClientPrint::$licenseKey;
869:         }
870:         $buffer .= $lo.chr(124).$lk;
871:         
872:         return $cpjHeader.$arrIdx1.$arrIdx2.$buffer;
873:     }
874:     
875: }
876: 
877: /**
878:  * Specifies information about a group of ClientPrintJob objects to be processed at the client side.
879:  */
880: class ClientPrintJobGroup{
881:     
882:     /**
883:      * Gets or sets an array of ClientPrintJob objects to be processed at the client side. Default is NULL.
884:      * @var array 
885:      */
886:     public $clientPrintJobGroup = null;
887:     
888:     /**
889:      * Sends this ClientPrintJobGroup object to the client for further processing.
890:      * The ClientPrintJobGroup object will be processed by the WCPP installed at the client machine.
891:      * @return string A string representing a ClientPrintJobGroup object.
892:      */
893:     public function sendToClient(){
894:         
895:         if (isset ($this->clientPrintJobGroup)){
896:             $groups = count($this->clientPrintJobGroup);
897:             
898:             $dataPartIndexes = Utils::intToArray(strlen($groups));
899:             
900:             $cpjgHeader = chr(99).chr(112).chr(106).chr(103).chr(2);
901:         
902:             $buffer = '';
903:             
904:             $cpjBytesCount = 0;
905:             
906:             foreach ($this->clientPrintJobGroup as $cpj) {
907:                 $cpjBuffer = '';
908:                 
909:                 if (!Utils::isNullOrEmptyString($cpj->printerCommands)){
910:                     if ($cpj->printerCommandsCopies > 1){
911:                         $cpjBuffer .= 'PCC='.$cpj->printerCommandsCopies.Utils::SER_SEP;
912:                     }
913:                     if($cpj->formatHexValues){
914:                         $cpjBuffer .= Utils::formatHexValues ($cpj->printerCommands);
915:                     } else {
916:                         $cpjBuffer .= $cpj->printerCommands;
917:                     }
918:                 } else if (isset ($cpj->printFile)){
919:                     $cpjBuffer = $cpj->printFile->serialize();
920:                 } else if (isset ($cpj->printFileGroup)){
921:                     $cpjBuffer = 'wcpPFG:';
922:                     $zip = new ZipArchive;
923:                     $cacheFileName = (Utils::strEndsWith(WebClientPrint::$wcpCacheFolder, '/')?WebClientPrint::$wcpCacheFolder:WebClientPrint::$wcpCacheFolder.'/').'PFG'.uniqid().'.zip';
924:                     $res = $zip->open($cacheFileName, ZipArchive::CREATE);
925:                     if ($res === TRUE) {
926:                         foreach ($cpj->printFileGroup as $printFile) {
927:                             $file = $printFile->fileName;
928:                             if($printFile->copies > 1){
929:                                 $pfc = 'PFC='.$printFile->copies;
930:                                 $file = substr($file, 0, strrpos($file, '.')).$pfc.substr($file, strrpos($file, '.'));
931:                             }   
932:                             $zip->addFromString($file, $printFile->getFileContent());
933:                         }
934:                         $zip->close();
935:                         $handle = fopen($cacheFileName, 'rb');
936:                         $cpjBuffer .= fread($handle, filesize($cacheFileName));
937:                         fclose($handle);
938:                         unlink($cacheFileName);
939:                     } else {
940:                         $cpjBuffer='Creating PrintFileGroup failed. Cannot create zip file.';
941:                     }
942:                 }
943: 
944:                 $arrIdx1 = Utils::intToArray(strlen($cpjBuffer));
945: 
946:                 if (!isset($cpj->clientPrinter)){
947:                     $cpj->clientPrinter = new UserSelectedPrinter();
948:                 }    
949: 
950:                 $cpjBuffer .= $cpj->clientPrinter->serialize();
951: 
952:                 $cpjBytesCount += strlen($cpjBuffer);
953:                     
954:                 $dataPartIndexes .= Utils::intToArray(strlen($cpjBytesCount));
955:  
956:                 $buffer .= $arrIdx1.$cpjBuffer;
957:             }
958:                     
959:             
960:             $lo = '';
961:             if(Utils::isNullOrEmptyString(WebClientPrint::$licenseOwner)){
962:                 $lo = substr(uniqid(), 0, 8);
963:             }  else {
964:                 $lo = 'php>'.base64_encode(WebClientPrint::$licenseOwner);
965:             }
966:             $lk = '';
967:             if(Utils::isNullOrEmptyString(WebClientPrint::$licenseKey)){
968:                 $lk = substr(uniqid(), 0, 8);
969:             }  else {
970:                 $lk = WebClientPrint::$licenseKey;
971:             }
972:             $buffer .= $lo.chr(124).$lk;
973: 
974:             return $cpjgHeader.$dataPartIndexes.$buffer;    
975:         
976:         
977:         } else {
978:             
979:             return NULL;
980:         }
981:             
982:         
983:     }
984: }
985: 
986: return '';
WebClientPrintPHP API documentation generated by ApiGen 2.8.0