1: <?php
  2: 
  3: namespace Neodynamic\SDK\Web;
  4: use Exception;
  5: use ZipArchive;
  6: 
  7: 
  8: WebClientPrint::$licenseOwner = '';
  9: WebClientPrint::$licenseKey = '';
 10: 
 11: 
 12: 
 13: 
 14: WebClientPrint::$webClientPrintAbsoluteUrl = Utils::getRoot().'/wcpdev/source/WebClientPrint.php';
 15: 
 16: 
 17: WebClientPrint::$wcpCacheFolder = 'wcpcache/';
 18: 
 19: 
 20: 
 21: 
 22: WebClientPrint::cacheClean(5); 
 23: 
 24: 
 25: $urlParts = parse_url($_SERVER['REQUEST_URI']);
 26: if (isset($urlParts['query'])){
 27:     if (Utils::strContains($urlParts['query'], WebClientPrint::WCP)){
 28:         WebClientPrint::processRequest($urlParts['query']);
 29:     }
 30: } 
 31: 
 32: 
 33:  34:  35:  36:  37:  38:  39:  40:  41: 
 42: class WebClientPrint {
 43:    
 44:     const VERSION = '2.0.0.0';
 45:     const CLIENT_PRINT_JOB = "clientPrint";
 46:     const WCP = 'WEB_CLIENT_PRINT';
 47:     
 48:     const WCP_CACHE_WCPP_INSTALLED = 'WCPP_INSTALLED';
 49:     const WCP_CACHE_WCPP_VER = 'WCPP_VER';
 50:     const WCP_CACHE_PRINTERS = 'PRINTERS';
 51:     
 52:      53:  54:  55: 
 56:     static $licenseOwner = '';
 57:      58:  59:  60: 
 61:     static $licenseKey = '';
 62:      63:  64:  65: 
 66:     static $webClientPrintAbsoluteUrl = '';
 67:      68:  69:  70:  71: 
 72:     static $wcpCacheFolder = '';
 73:     
 74:      75:  76:  77:  78:  79:  80: 
 81:     public static function cacheAdd($sid, $key, $val){
 82:         if (Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
 83:             throw new Exception('WebClientPrint wcpCacheFolder is missing, please specify it.');
 84:         }
 85:         if (Utils::isNullOrEmptyString($sid)){
 86:             throw new Exception('WebClientPrint FileName cache is missing, please specify it.');
 87:         }
 88:         $cacheFileName = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/').$sid.'.wcpcache';
 89:         $dataWCPP_VER = '';
 90:         $dataPRINTERS = '';
 91:             
 92:         if(file_exists($cacheFileName)){
 93:             $cache_info = parse_ini_file($cacheFileName);
 94:             
 95:             $dataWCPP_VER = $cache_info[self::WCP_CACHE_WCPP_VER];
 96:             $dataPRINTERS = $cache_info[self::WCP_CACHE_PRINTERS];
 97:         }
 98:         
 99:         if ($key === self::WCP_CACHE_WCPP_VER){
100:             $dataWCPP_VER = self::WCP_CACHE_WCPP_VER.'='.'"'.$val.'"';
101:             $dataPRINTERS = self::WCP_CACHE_PRINTERS.'='.'"'.$dataPRINTERS.'"';
102:         } else if ($key === self::WCP_CACHE_PRINTERS){
103:             $dataWCPP_VER = self::WCP_CACHE_WCPP_VER.'='.'"'.$dataWCPP_VER.'"';
104:             $dataPRINTERS = self::WCP_CACHE_PRINTERS.'='.'"'.$val.'"';
105:         }
106: 
107:         $data = $dataWCPP_VER.chr(13).chr(10).$dataPRINTERS;
108:         $handle = fopen($cacheFileName, 'w') or die('Cannot open file:  '.$cacheFileName);  
109:         fwrite($handle, $data);
110:         fclose($handle);
111:         
112:     }
113:     
114:     115: 116: 117: 118: 119: 120: 
121:     public static function cacheGet($sid, $key){
122:         if (Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
123:             throw new Exception('WebClientPrint wcpCacheFolder is missing, please specify it.');
124:         }
125:         if (Utils::isNullOrEmptyString($sid)){
126:             throw new Exception('WebClientPrint FileName cache is missing, please specify it.');
127:         }
128:         $cacheFileName = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/').$sid.'.wcpcache';
129:         if(file_exists($cacheFileName)){
130:             $cache_info = parse_ini_file($cacheFileName);
131:                 
132:             if($key===self::WCP_CACHE_WCPP_VER || $key===self::WCP_CACHE_WCPP_INSTALLED){
133:                 return $cache_info[self::WCP_CACHE_WCPP_VER];
134:             }else if($key===self::WCP_CACHE_PRINTERS){
135:                 return $cache_info[self::WCP_CACHE_PRINTERS];
136:             }else{
137:                 return '';
138:             }
139:         }else{
140:             return '';
141:         }
142:     }
143:     
144:     145: 146: 147: 
148:     public static function cacheClean($minutes){
149:         if (!Utils::isNullOrEmptyString(self::$wcpCacheFolder)){
150:             $cacheDir = (Utils::strEndsWith(self::$wcpCacheFolder, '/')?self::$wcpCacheFolder:self::$wcpCacheFolder.'/');
151:             if ($handle = opendir($cacheDir)) {
152:                  while (false !== ($file = readdir($handle))) {
153:                     if ($file!='.' && $file!='..' && (time()-filectime($cacheDir.$file)) > (60*$minutes)) {
154:                         unlink($cacheDir.$file);
155:                     }
156:                  }
157:                  closedir($handle);
158:             }
159:         }
160:     }
161:     
162:     163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 
179:     public static function createWcppDetectionScript(){
180:         
181:         if (Utils::isNullOrEmptyString(self::$webClientPrintAbsoluteUrl)){
182:             throw new Exception('WebClientPrint absolute URL is missing, please specify it.');
183:         }
184:         
185:         $buffer = '<script type="text/javascript">';
186:         if(Utils::isIE6to9() || Utils::isIE10orGreater()){
187:             $buffer .= 'var wcppPingNow=false;'; 
188:         } else {
189:             $buffer .= 'var wcppPingNow=true;';
190:         }
191:         $buffer .= '</script>';
192:         
193:         $wcpHandler = self::$webClientPrintAbsoluteUrl.'?'.self::WCP.'&d='.session_id();
194:         $buffer .= '<script src="'.$wcpHandler.'" type="text/javascript"></script>';
195:         
196:         if(Utils::isIE6to9() || Utils::isIE10orGreater()){
197:             $crlf = chr(13).chr(10);
198:             $buffer .= $crlf.$crlf;
199:             $buffer .= '<!--[if WCPP]>'.$crlf;
200:             $buffer .= '<script type="text/javascript">'.$crlf;
201:             $buffer .= '$(document).ready(function(){jsWCPP.ping();});'.$crlf;
202:             $buffer .= '</script>'.$crlf;
203:             $buffer .= '<![endif]-->'.$crlf;
204:             $buffer .= '<!--[if !WCPP]>'.$crlf;
205:             $buffer .= '<script type="text/javascript">'.$crlf;
206:             $buffer .= '$(document).ready(function(){wcppDetectOnFailure();});'.$crlf;
207:             $buffer .= '</script>'.$crlf;
208:             $buffer .= '<![endif]-->'.$crlf;
209:          }
210:          
211:          return $buffer;
212:     }
213:     
214:     215: 216: 217: 218: 219: 220: 221: 222: 
223:     public static function getWcppDetectionMetaTag(){
224:          return Utils::isIE10orGreater()?'<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />':'';
225:     }
226:     
227:     228: 229: 230: 231: 232: 233: 234: 
235:     public static function createScript($clientPrintJobUrl){
236:         if (Utils::isNullOrEmptyString(self::$webClientPrintAbsoluteUrl)){
237:             throw new Exception('WebClientPrint absolute URL is missing, please specify it.');
238:         }
239:         $wcpHandler = self::$webClientPrintAbsoluteUrl.'?';
240:         $wcpHandler .= self::WCP;
241:         $wcpHandler .= '&';
242:         $wcpHandler .= self::VERSION;
243:         $wcpHandler .= '&';
244:         $wcpHandler .= microtime(true);
245:         $wcpHandler .= '&u=';
246:         $wcpHandler .= base64_encode($clientPrintJobUrl);
247:         return '<script src="'.$wcpHandler.'" type="text/javascript"></script>';
248:     }
249:     
250:     public static function processRequest($data){
251:         
252:         $PING = 'wcppping';
253:         $SID = 'sid';
254:         $HAS_WCPP = 'wcppInstalled';
255:         
256:         $GEN_WCP_SCRIPT_VERSION = 'v2.0.0.0';
257:         $GEN_WCP_SCRIPT_URL = 'u';
258:         $GEN_DETECT_WCPP_SCRIPT = 'd';
259:         $WCP_SCRIPT_AXD_GET_PRINTERS = 'getPrinters';
260:         $WCPP_SET_PRINTERS = 'printers';
261:         $WCP_SCRIPT_AXD_GET_WCPPVERSION = 'getWcppVersion';
262:         $WCPP_SET_VERSION = 'wcppVer';
263:         
264:         $wcpUrl=Utils::getRoot().$_SERVER['REQUEST_URI'];
265:         $wcpUrl=substr($wcpUrl, 0, strpos($wcpUrl, '.php?')+4);
266:         
267:         parse_str($data, $qs);
268:     
269:         if(isset($qs[$SID])){
270:             if(isset($qs[$PING])){
271:                 if (isset($qs[$WCPP_SET_VERSION])){
272:                     self::cacheAdd($qs[$SID], self::WCP_CACHE_WCPP_VER, $qs[$WCPP_SET_VERSION]);
273:                 }else{
274:                     self::cacheAdd($qs[$SID], self::WCP_CACHE_WCPP_VER,'1.0.0.0');
275:                 }
276:             }else if(isset($qs[$WCPP_SET_PRINTERS])){
277:                 self::cacheAdd($qs[$SID], self::WCP_CACHE_PRINTERS, strlen($qs[$WCPP_SET_PRINTERS]) > 0 ? base64_decode($qs[$WCPP_SET_PRINTERS]) : '');
278:             }else if(strpos($data, $WCP_SCRIPT_AXD_GET_PRINTERS)>0){
279:                 ob_clean();
280:                 header('Content-type: text/plain');
281:                 echo self::cacheGet($qs[$SID], self::WCP_CACHE_PRINTERS);
282:             }else if(isset($qs[$WCPP_SET_VERSION])){
283:                 if(strlen($qs[$WCPP_SET_VERSION]) > 0){
284:                     self::cacheAdd($qs[$SID], self::WCP_CACHE_WCPP_VER, $qs[$WCPP_SET_VERSION]);
285:                 }
286:             }else if(strpos($data, $WCP_SCRIPT_AXD_GET_WCPPVERSION)>0){
287:                 ob_clean();
288:                 header('Content-type: text/plain');
289:                 echo self::cacheGet($qs[$SID], self::WCP_CACHE_WCPP_VER);
290:             }else{
291:                 ob_clean();
292:                 header('Content-type: text/plain');
293:                 echo self::cacheGet($qs[$SID], self::WCP_CACHE_WCPP_INSTALLED);
294:             }
295:         }else if(isset($qs[$GEN_DETECT_WCPP_SCRIPT])){
296:             
297:             $curSID = $qs[$GEN_DETECT_WCPP_SCRIPT];
298:             $onSuccessScript = 'wcppDetectOnSuccess(data);';
299:             $onFailureScript = 'wcppDetectOnFailure();';
300:             $dynamicIframeId = 'i'.substr(uniqid(), 0, 3);
301:             $absoluteWcpAxd = $wcpUrl.'?'.self::WCP.'&'.$SID.'='.$curSID;
302:             
303:             $s1 = 'dmFyIGpzV0NQUD0oZnVuY3Rpb24oKXt2YXIgc2V0WFhYLU5FTy1IVE1MLUlELVhYWD1mdW5jdGlvbigpe2lmKHdpbmRvdy5jaHJvbWUpeyQoJyNYWFgtTkVPLUhUTUwtSUQtWFhYJykuYXR0cignaHJlZicsJ3dlYmNsaWVudHByaW50OicrYXJndW1lbnRzWzBdKTt2YXIgYT0kKCdhI1hYWC1ORU8tSFRNTC1JRC1YWFgnKVswXTt2YXIgZXZPYmo9ZG9jdW1lbnQuY3JlYXRlRXZlbnQoJ01vdXNlRXZlbnRzJyk7ZXZPYmouaW5pdEV2ZW50KCdjbGljaycsdHJ1ZSx0cnVlKTthLmRpc3BhdGNoRXZlbnQoZXZPYmopfWVsc2V7JCgnI1hYWC1ORU8tSFRNTC1JRC1YWFgnKS5hdHRyKCdzcmMnLCd3ZWJjbGllbnRwcmludDonK2FyZ3VtZW50c1swXSl9fTtyZXR1cm57aW5pdDpmdW5jdGlvbigpe2lmKHdpbmRvdy5jaHJvbWUpeyQoJzxhIC8+Jyx7aWQ6J1hYWC1ORU8tSFRNTC1JRC1YWFgnfSkuYXBwZW5kVG8oJ2JvZHknKX1lbHNleyQoJzxpZnJhbWUgLz4nLHtuYW1lOidYWFgtTkVPLUhUTUwtSUQtWFhYJyxpZDonWFhYLU5FTy1IVE1MLUlELVhYWCcsd2lkdGg6JzEnLGhlaWdodDonMScsc3R5bGU6J3Zpc2liaWxpdHk6aGlkZGVuO3Bvc2l0aW9uOmFic29sdXRlJ30pLmFwcGVuZFRvKCdib2R5Jyl9fSxwaW5nOmZ1bmN0aW9uKCl7c2V0WFhYLU5FTy1IVE1MLUlELVhYWCgnWFhYLU5FTy1QSU5HLVVSTC1YWFgnKyhhcmd1bWVudHMubGVuZ3RoPT0xPycmJythcmd1bWVudHNbMF06JycpKTt2YXIgZGVsYXlfbXM9KHR5cGVvZiB3Y3BwUGluZ0RlbGF5X21zPT09J3VuZGVmaW5lZCcpPzEwMDAwOndjcHBQaW5nRGVsYXlfbXM7c2V0VGltZW91dChmdW5jdGlvbigpeyQuZ2V0KCdYWFgtTkVPLVVTRVItSEFTLVdDUFAtWFhYJyxmdW5jdGlvbihkYXRhKXtpZihkYXRhIT0nZicpe1hYWC1ORU8tT04tU1VDQ0VTUy1TQ1JJUFQtWFhYfWVsc2V7WFhYLU5FTy1PTi1GQUlMVVJFLVNDUklQVC1YWFh9fSl9LGRlbGF5X21zKX19fSkoKTsgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtqc1dDUFAuaW5pdCgpO2lmKHdjcHBQaW5nTm93KWpzV0NQUC5waW5nKCk7fSk7';
304:             $s2 = base64_decode($s1);
305:             $s2 = str_replace('XXX-NEO-HTML-ID-XXX', $dynamicIframeId, $s2);
306:             $s2 = str_replace('XXX-NEO-PING-URL-XXX', $absoluteWcpAxd.'&'.$PING, $s2);
307:             $s2 = str_replace('XXX-NEO-USER-HAS-WCPP-XXX', $absoluteWcpAxd, $s2);
308:             $s2 = str_replace('XXX-NEO-ON-SUCCESS-SCRIPT-XXX', $onSuccessScript, $s2);
309:             $s2 = str_replace('XXX-NEO-ON-FAILURE-SCRIPT-XXX', $onFailureScript, $s2);
310:             
311:             ob_clean();
312:             header('Content-type: application/javascript');
313:             echo $s2;
314:             
315:         }else if(isset($qs[$GEN_WCP_SCRIPT_URL])){
316:             
317:             $clientPrintJobUrl = base64_decode($qs[$GEN_WCP_SCRIPT_URL]);
318:             if (strpos($clientPrintJobUrl, '?')>0){
319:                 $clientPrintJobUrl .= '&';
320:             }else{
321:                 $clientPrintJobUrl .= '?';
322:             }
323:             $clientPrintJobUrl .= self::CLIENT_PRINT_JOB;
324:             $absoluteWcpAxd = $wcpUrl;
325:             $wcppGetPrintersParam = '-getPrinters:'.$absoluteWcpAxd.'?'.self::WCP.'&'.$SID.'=';
326:             $wcpHandlerGetPrinters = $absoluteWcpAxd.'?'.self::WCP.'&'.$WCP_SCRIPT_AXD_GET_PRINTERS.'&'.$SID.'=';
327:             $wcppGetWcppVerParam = '-getWcppVersion:'.$absoluteWcpAxd.'?'.self::WCP.'&'.$SID.'=';
328:             $wcpHandlerGetWcppVer = $absoluteWcpAxd.'?'.self::WCP.'&'.$WCP_SCRIPT_AXD_GET_WCPPVERSION.'&'.$SID.'=';
329: 
330:             $s1 = 'dmFyIGpzV2ViQ2xpZW50UHJpbnQ9KGZ1bmN0aW9uKCl7dmFyIHNldEE9ZnVuY3Rpb24oKXt2YXIgZV9pZD0naWRfJytuZXcgRGF0ZSgpLmdldFRpbWUoKTtpZih3aW5kb3cuY2hyb21lKXskKCdib2R5JykuYXBwZW5kKCc8YSBpZD0iJytlX2lkKyciPjwvYT4nKTskKCcjJytlX2lkKS5hdHRyKCdocmVmJywnd2ViY2xpZW50cHJpbnQ6Jythcmd1bWVudHNbMF0pO3ZhciBhPSQoJ2EjJytlX2lkKVswXTt2YXIgZXZPYmo9ZG9jdW1lbnQuY3JlYXRlRXZlbnQoJ01vdXNlRXZlbnRzJyk7ZXZPYmouaW5pdEV2ZW50KCdjbGljaycsdHJ1ZSx0cnVlKTthLmRpc3BhdGNoRXZlbnQoZXZPYmopfWVsc2V7JCgnYm9keScpLmFwcGVuZCgnPGlmcmFtZSBuYW1lPSInK2VfaWQrJyIgaWQ9IicrZV9pZCsnIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBzdHlsZT0idmlzaWJpbGl0eTpoaWRkZW47cG9zaXRpb246YWJzb2x1dGUiIC8+Jyk7JCgnIycrZV9pZCkuYXR0cignc3JjJywnd2ViY2xpZW50cHJpbnQ6Jythcmd1bWVudHNbMF0pfXNldFRpbWVvdXQoZnVuY3Rpb24oKXskKCcjJytlX2lkKS5yZW1vdmUoKX0sNTAwMCl9O3JldHVybntwcmludDpmdW5jdGlvbigpe3NldEEoJ1VSTF9QUklOVF9KT0InKyhhcmd1bWVudHMubGVuZ3RoPT0xPycmJythcmd1bWVudHNbMF06JycpKX0sZ2V0UHJpbnRlcnM6ZnVuY3Rpb24oKXtzZXRBKCdVUkxfV0NQX0FYRF9XSVRIX0dFVF9QUklOVEVSU19DT01NQU5EJyskKCcjc2lkJykudmFsKCkpO3ZhciBkZWxheV9tcz0odHlwZW9mIHdjcHBHZXRQcmludGVyc0RlbGF5X21zPT09J3VuZGVmaW5lZCcpPzEwMDAwOndjcHBHZXRQcmludGVyc0RlbGF5X21zO3NldFRpbWVvdXQoZnVuY3Rpb24oKXskLmdldCgnVVJMX1dDUF9BWERfR0VUX1BSSU5URVJTJyskKCcjc2lkJykudmFsKCksZnVuY3Rpb24oZGF0YSl7aWYoZGF0YS5sZW5ndGg+MCl7d2NwR2V0UHJpbnRlcnNPblN1Y2Nlc3MoZGF0YSl9ZWxzZXt3Y3BHZXRQcmludGVyc09uRmFpbHVyZSgpfX0pfSxkZWxheV9tcyl9LGdldFdjcHBWZXI6ZnVuY3Rpb24oKXtzZXRBKCdVUkxfV0NQX0FYRF9XSVRIX0dFVF9XQ1BQVkVSU0lPTl9DT01NQU5EJyskKCcjc2lkJykudmFsKCkpO3ZhciBkZWxheV9tcz0odHlwZW9mIHdjcHBHZXRWZXJEZWxheV9tcz09PSd1bmRlZmluZWQnKT8xMDAwMDp3Y3BwR2V0VmVyRGVsYXlfbXM7c2V0VGltZW91dChmdW5jdGlvbigpeyQuZ2V0KCdVUkxfV0NQX0FYRF9HRVRfV0NQUFZFUlNJT04nKyQoJyNzaWQnKS52YWwoKSxmdW5jdGlvbihkYXRhKXtpZihkYXRhLmxlbmd0aD4wKXt3Y3BHZXRXY3BwVmVyT25TdWNjZXNzKGRhdGEpfWVsc2V7d2NwR2V0V2NwcFZlck9uRmFpbHVyZSgpfX0pfSxkZWxheV9tcyl9LHNlbmQ6ZnVuY3Rpb24oKXtzZXRBLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19fSkoKTs=';
331:             $s2 = base64_decode($s1);
332:             $s2 = str_replace('URL_PRINT_JOB', $clientPrintJobUrl, $s2);
333:             $s2 = str_replace('URL_WCP_AXD_WITH_GET_PRINTERS_COMMAND', $wcppGetPrintersParam, $s2);
334:             $s2 = str_replace('URL_WCP_AXD_GET_PRINTERS', $wcpHandlerGetPrinters, $s2);
335:             $s2 = str_replace('URL_WCP_AXD_WITH_GET_WCPPVERSION_COMMAND', $wcppGetWcppVerParam, $s2);
336:             $s2 = str_replace('URL_WCP_AXD_GET_WCPPVERSION', $wcpHandlerGetWcppVer, $s2);
337:             
338:             ob_clean();
339:             header('Content-type: application/javascript');
340:             echo $s2;
341:         }
342:         
343:     }
344:     
345: }
346: 
347: 348: 349: 
350: abstract class ClientPrinter{
351:     
352:     public $printerId;
353:     public function serialize(){
354:         
355:     }
356: }
357: 
358: 359: 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: 373: 
374: class InstalledPrinter extends ClientPrinter{
375:     
376:     377: 378: 379: 
380:     public $printerName = '';
381: 
382:     383: 384: 385: 
386:     public function __construct($printerName) {
387:         $this->printerId = chr(1);
388:         $this->printerName = $printerName;
389:     }
390:     
391:     
392:     public function serialize() {
393:         
394:         if (Utils::isNullOrEmptyString($this->printerName)){
395:              throw new Exception("The specified printer name is null or empty.");
396:         }
397:         
398:         return $this->printerId.$this->printerName;
399:     }
400: }
401: 
402: 403: 404: 
405: class ParallelPortPrinter extends ClientPrinter{
406:     
407:     408: 409: 410: 
411:     public $portName = "LPT1";
412: 
413:     414: 415: 416: 
417:     public function __construct($portName) {
418:         $this->printerId = chr(2);
419:         $this->portName = $portName;
420:     }
421:     
422:     public function serialize() {
423:         
424:         if (Utils::isNullOrEmptyString($this->portName)){
425:              throw new Exception("The specified parallel port name is null or empty.");
426:         }
427:         
428:         return $this->printerId.$this->portName;
429:     }
430: }
431: 
432: 433: 434: 
435: class SerialPortPrinter extends ClientPrinter{
436:     
437:     438: 439: 440: 
441:     public $portName = "COM1";
442:     443: 444: 445: 
446:     public $baudRate = 9600;
447:     448: 449: 450: 451: 
452:     public $parity = SerialPortParity::NONE;
453:     454: 455: 456: 457: 
458:     public $stopBits = SerialPortStopBits::ONE;
459:     460: 461: 462: 
463:     public $dataBits = 8;
464:     465: 466: 467: 468: 
469:     public $flowControl = SerialPortHandshake::XON_XOFF;
470:     
471:     472: 473: 474: 475: 476: 477: 478: 479: 
480:     public function __construct($portName, $baudRate, $parity, $stopBits, $dataBits, $flowControl) {
481:         $this->printerId = chr(3);
482:         $this->portName = $portName;
483:         $this->baudRate = $baudRate;
484:         $this->parity = $parity;
485:         $this->stopBits = $stopBits;
486:         $this->dataBits = $dataBits;
487:         $this->flowControl = $flowControl;
488:     }
489:     
490:     public function serialize() {
491:         
492:         if (Utils::isNullOrEmptyString($this->portName)){
493:              throw new Exception("The specified serial port name is null or empty.");
494:         }
495:         
496:         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;
497:     }
498: }
499: 
500: 501: 502: 
503: class NetworkPrinter extends ClientPrinter{
504:     
505:     506: 507: 508: 
509:     public $dnsName = "";
510:     511: 512: 513: 
514:     public $ipAddress = "";
515:     516: 517: 518: 
519:     public $port = 0;
520:     
521:     522: 523: 524: 525: 526: 
527:     public function __construct($dnsName, $ipAddress, $port) {
528:         $this->printerId = chr(4);
529:         $this->dnsName = $dnsName;
530:         $this->ipAddress = $ipAddress;
531:         $this->port = $port;
532:     }
533:     
534:     public function serialize() {
535:         
536:         if (Utils::isNullOrEmptyString($this->dnsName) && Utils::isNullOrEmptyString($this->ipAddress)){
537:              throw new Exception("The specified network printer settings is not valid. You must specify the DNS Printer Name or its IP address.");
538:         }
539:         
540:         return $this->printerId.$this->dnsName.Utils::SER_SEP.$this->ipAddress.Utils::SER_SEP.$this->port;
541:     }
542: }
543: 
544: 545: 546: 
547: class UserSelectedPrinter extends ClientPrinter{
548:     public function __construct() {
549:         $this->printerId = chr(5);
550:     }
551:     
552:     public function serialize() {
553:         return $this->printerId;
554:     }
555: }
556: 
557: 558: 559: 
560: class SerialPortParity{
561:     const NONE = 0;
562:     const ODD = 1;
563:     const EVEN = 2;
564:     const MARK = 3;
565:     const SPACE = 4;
566: }
567: 
568: 569: 570: 
571: class SerialPortStopBits{
572:     const NONE = 0;
573:     const ONE = 1;
574:     const TWO = 2;
575:     const ONE_POINT_FIVE = 3;
576: }
577: 
578: 579: 580: 
581: class SerialPortHandshake{
582:     const NONE = 0;
583:     const REQUEST_TO_SEND = 2;
584:     const REQUEST_TO_SEND_XON_XOFF = 3;
585:     const XON_XOFF = 1;
586: }
587: 
588: 589: 590: 
591: class PrintFile{
592:     
593:     594: 595: 596: 
597:     public $filePath = '';
598:     599: 600: 601: 602: 
603:     public $fileName = '';
604:     605: 606: 607: 
608:     public $fileBinaryContent = '';
609:     
610:     const PREFIX = 'wcpPF:';
611:     const SEP = '|';
612:         
613:     614: 615: 616: 617: 618: 
619:     public function __construct($filePath, $fileName, $fileBinaryContent) {
620:         $this->filePath = $filePath;
621:         $this->fileName = $fileName;
622:         $this->fileBinaryContent = $fileBinaryContent;
623:         
624:     }
625:     
626:     public function serialize() {
627:         return self::PREFIX.$this->fileName.self::SEP.$this->getFileContent();
628:     }
629:     
630:     public function getFileContent(){
631:         $content = $this->fileBinaryContent;
632:         if(!Utils::isNullOrEmptyString($this->filePath)){
633:             $handle = fopen($this->filePath, 'rb');
634:             $content = fread($handle, filesize($this->filePath));
635:             fclose($handle);
636:         }
637:         return $content;
638:     }
639: }
640: 
641: 642: 643: 
644: class Utils{
645:     const SER_SEP = "|";
646:     
647:     static function isNullOrEmptyString($s){
648:         return (!isset($s) || trim($s)==='');
649:     }
650:     
651:     static function formatHexValues($s){
652:         
653:         $buffer = '';
654:             
655:         $l = strlen($s);
656:         $i = 0;
657: 
658:         while ($i < $l)
659:         {
660:             if ($s[$i] == '0')
661:             {
662:                 if ($i + 1 < $l && ($s[$i] == '0' && $s[$i + 1] == 'x'))
663:                 {
664:                     if ($i + 2 < $l &&
665:                         (($s[$i + 2] >= '0' && $s[$i + 2] <= '9') || ($s[$i + 2] >= 'a' && $s[$i + 2] <= 'f') || ($s[$i + 2] >= 'A' && $s[$i + 2] <= 'F')))
666:                     {
667:                         if ($i + 3 < $l &&
668:                            (($s[$i + 3] >= '0' && $s[$i + 3] <= '9') || ($s[$i + 3] >= 'a' && $s[$i + 3] <= 'f') || ($s[$i + 3] >= 'A' && $s[$i + 3] <= 'F')))
669:                         {
670:                             try{
671:                                 $buffer .= chr(substr($s, $i, 4));
672:                                 $i += 4;
673:                                 continue;
674:                                 
675:                             } catch (Exception $ex) {
676:                                 throw new Exception("Invalid hex notation in the specified printer commands at index: ".$i);
677:                             }
678:                                 
679:                             
680:                         }
681:                         else
682:                         {
683:                             try{
684:                                 
685:                                 $buffer .= chr(substr($s, $i, 3));
686:                                 $i += 3;
687:                                 continue;
688:                                 
689:                             } catch (Exception $ex) {
690:                                 throw new ArgumentException("Invalid hex notation in the specified printer commands at index: ".$i);
691:                             }
692:                         }
693:                     }
694:                 }
695:             }
696: 
697:             $buffer .= substr($s, $i, 1);
698:             
699:             $i++;
700:         }
701: 
702:         return $buffer;
703:         
704:     }
705:     
706:     public static function intToArray($i){
707:         return pack("L", $i);
708:     }
709:         
710:     public static function getRoot(){
711:         $s = empty($_SERVER["HTTPS"]) ? '' : ($_SERVER["HTTPS"] == "on") ? "s" : "";
712:         $protocol = static::strleft(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s;
713:         $port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]);
714:         return $protocol."://".$_SERVER['SERVER_NAME'].$port;    
715:     }
716:    
717:     public static function strleft($s1, $s2) {
718:     return substr($s1, 0, strpos($s1, $s2));
719:     }
720:     
721:     public static function strContains($s1, $s2){
722:         return (strpos($s1, $s2) !== false);
723:     }
724:     
725:     public static function strEndsWith($s1, $s2)
726:     {
727:         return substr($s1, -strlen($s2)) === $s2;
728:     }
729:     
730:     public static function getUA(){
731:         return $_SERVER['HTTP_USER_AGENT'];
732:     }
733:     
734:     public static function isIE6to9(){
735:         $ua = static::getUA();
736:         return ((static::strContains($ua,"MSIE 6.") ||
737:                  static::strContains($ua,"MSIE 7.") ||
738:                  static::strContains($ua,"MSIE 8.") ||
739:                  static::strContains($ua,"MSIE 9.")) &&
740:                  static::strContains($ua,"Opera") === false);
741:     }
742: 
743:     public static function isIE5orOlder(){
744:         $ua = static::getUA();
745:         return ((static::strContains($ua,"MSIE 5.") ||
746:                  static::strContains($ua,"MSIE 4.") ||
747:                  static::strContains($ua,"MSIE 3.") ||
748:                  static::strContains($ua,"MSIE 2.")) &&
749:                  static::strContains($ua,"Opera") === false);
750:     }
751:         
752:     public static function isIE10orGreater(){
753:         $ua = static::getUA();
754:         return (static::strContains($ua,"MSIE") || static::strContains($ua,"Trident/")) && static::isIE6to9() === false && static::isIE5orOlder() === false && static::strContains($ua,"Opera") === false;
755:     }
756:     
757: }
758: 
759: 760: 761: 
762: class ClientPrintJob{
763:     
764:     765: 766: 767: 768: 769: 770: 771: 772: 773: 
774:     public $clientPrinter = null;
775:     776: 777: 778: 
779:     public $printerCommands = '';
780:     781: 782: 783: 784: 785: 786: 787: 788: 
789:     public $formatHexValues = false;
790:     791: 792: 793: 
794:     public $printFile = null;
795:     796: 797: 798: 
799:     public $printFileGroup = null;
800:     
801:     
802:     803: 804: 805: 806: 
807:     public function sendToClient(){
808:         
809:         header('Content-type: application/octet-stream');
810:         
811:         $cpjHeader = chr(99).chr(112).chr(106).chr(2);
812:         
813:         $buffer = '';
814:         
815:         if (!Utils::isNullOrEmptyString($this->printerCommands)){
816:             if($this->formatHexValues){
817:                 $buffer = Utils::formatHexValues ($this->printerCommands);
818:             } else {
819:                 $buffer = $this->printerCommands;
820:             }
821:         } else if (isset ($this->printFile)){
822:             $buffer = $this->printFile->serialize();
823:         } else if (isset ($this->printFileGroup)){
824:             $buffer = 'wcpPFG:';
825:             $zip = new ZipArchive;
826:             $cacheFileName = (Utils::strEndsWith(WebClientPrint::$wcpCacheFolder, '/')?WebClientPrint::$wcpCacheFolder:WebClientPrint::$wcpCacheFolder.'/').'PFG'.uniqid().'.zip';
827:             $res = $zip->open($cacheFileName, ZipArchive::CREATE);
828:             if ($res === TRUE) {
829:                 foreach ($this->printFileGroup as $printFile) {
830:                     $zip->addFromString($printFile->fileName, $printFile->getFileContent());
831:                 }
832:                 $zip->close();
833:                 $handle = fopen($cacheFileName, 'rb');
834:                 $buffer .= fread($handle, filesize($cacheFileName));
835:                 fclose($handle);
836:                 unlink($cacheFileName);
837:             } else {
838:                 $buffer='Creating PrintFileGroup failed. Cannot create zip file.';
839:             }
840:         }
841:         
842:         $arrIdx1 = Utils::intToArray(strlen($buffer));
843:         
844:         if (!isset($this->clientPrinter)){
845:             $this->clientPrinter = new UserSelectedPrinter();
846:         }    
847:         
848:         $buffer .= $this->clientPrinter->serialize();
849:         
850:         $arrIdx2 = Utils::intToArray(strlen($buffer));
851:         
852:         $lo = '';
853:         if(Utils::isNullOrEmptyString(WebClientPrint::$licenseOwner)){
854:             $lo = substr(uniqid(), 0, 8);
855:         }  else {
856:             $lo = WebClientPrint::$licenseOwner;
857:         }
858:         $lk = '';
859:         if(Utils::isNullOrEmptyString(WebClientPrint::$licenseKey)){
860:             $lk = substr(uniqid(), 0, 8);
861:         }  else {
862:             $lk = WebClientPrint::$licenseKey;
863:         }
864:         $buffer .= $lo.chr(124).$lk;
865:         
866:         return $cpjHeader.$arrIdx1.$arrIdx2.$buffer;
867:     }
868:     
869: }