1<?php 2 3/* @(#) $Header: /sources/phpprintipp/phpprintipp/php_classes/BasicIPP.php,v 1.7 2012/03/01 17:21:04 harding Exp $ 4 * 5 * Class BasicIPP - Send Basic IPP requests, Get and parses IPP Responses. 6 * 7 * Copyright (C) 2005-2009 Thomas HARDING 8 * Parts Copyright (C) 2005-2006 Manuel Lemos 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Library General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Library General Public License for more details. 19 * 20 * You should have received a copy of the GNU Library General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 * 24 * mailto:thomas.harding@laposte.net 25 * Thomas Harding, 56 rue de la bourie rouge, 45 000 ORLEANS -- FRANCE 26 * 27 */ 28/* 29 30 This class is intended to implement Internet Printing Protocol on client side. 31 32 References needed to debug / add functionnalities: 33 - RFC 2910 34 - RFC 2911 35 - RFC 3380 36 - RFC 3382 37 */ 38 39require_once ("http_class.php"); 40 41class ippException extends \Exception 42{ 43 protected $errno; 44 45 public function __construct($msg, $errno = null) 46 { 47 parent::__construct($msg); 48 $this->errno = $errno; 49 } 50 51 public function getErrorFormatted() 52 { 53 $return = sprintf("[ipp]: %s -- " . _(" file %s, line %s"), 54 $this->getMessage() , $this->getFile() , $this->getLine()); 55 return $return; 56 } 57 58 public function getErrno() 59 { 60 return $this->errno; 61 } 62} 63 64class BasicIPP 65{ 66 public $paths = array( 67 "root" => "/", 68 "admin" => "/admin/", 69 "printers" => "/printers/", 70 "jobs" => "/jobs/" 71 ); 72 public $http_timeout = 30; // timeout at http connection (seconds) 0 => default => 30. 73 public $http_data_timeout = 30; // data reading timeout (milliseconds) 0 => default => 30. 74 public $ssl = false; 75 public $debug_level = 3; // max 3: almost silent 76 public $alert_on_end_tag; // debugging purpose: echo "END tag OK" if (1 and reads while end tag) 77 public $with_exceptions = 1; // compatibility mode for old scripts // DOL_LDR_CHANGE set this to 1 78 public $handle_http_exceptions = 1; 79 80 // readables variables 81 public $jobs = array(); 82 public $jobs_uri = array(); 83 public $status = array(); 84 public $response_completed = array(); 85 public $last_job = ""; 86 public $attributes; // object you can read: attributes after validateJob() 87 public $printer_attributes; // object you can read: printer's attributes after getPrinterAttributes() 88 public $job_attributes; // object you can read: last job attributes 89 public $jobs_attributes; // object you can read: jobs attributes after getJobs() 90 public $available_printers = array(); 91 public $printer_map = array(); 92 public $printers_uri = array(); 93 public $debug = array(); 94 public $response; 95 public $meta; 96 97 // protected variables; 98 protected $log_level = 2; // max 3: very verbose 99 protected $log_type = 3; // 3: file | 1: e-mail | 0: logger 100 protected $log_destination; // e-mail or file 101 protected $serveroutput; 102 protected $setup; 103 protected $stringjob; 104 protected $data; 105 protected $debug_count = 0; 106 protected $username; 107 protected $charset; 108 protected $password; 109 protected $requesring_user; 110 protected $client_hostname = "localhost"; 111 protected $stream; 112 protected $host = "localhost"; 113 protected $port = "631"; 114 protected $requesting_user = ''; 115 protected $printer_uri; 116 protected $timeout = "20"; //20 secs 117 protected $errNo; 118 protected $errStr; 119 protected $datatype; 120 protected $datahead; 121 protected $datatail; 122 protected $operation_id; 123 protected $delay; 124 protected $error_generation; //devel feature 125 protected $debug_http = 0; 126 protected $no_disconnect; 127 protected $job_tags; 128 protected $operation_tags; 129 protected $index; 130 protected $collection; //RFC3382 131 protected $collection_index; //RFC3382 132 protected $collection_key = array(); //RFC3382 133 protected $collection_depth = - 1; //RFC3382 134 protected $end_collection = false; //RFC3382 135 protected $collection_nbr = array(); //RFC3382 136 protected $unix = false; // true -> use unix sockets instead of http 137 protected $output; 138 139 public function __construct() 140 { 141 $tz = getenv("date.timezone"); 142 if (!$tz) 143 { 144 $tz = @date_default_timezone_get(); 145 } 146 147 date_default_timezone_set($tz); 148 $this->meta = new \stdClass(); 149 $this->setup = new \stdClass(); 150 $this->values = new \stdClass(); 151 $this->serveroutput = new \stdClass(); 152 $this->error_generation = new \stdClass(); 153 $this->_parsing = new \stdClass(); 154 self::_initTags(); 155 } 156 157 public function setPort($port = '631') 158 { 159 $this->port = $port; 160 self::_putDebug("Port is " . $this->port, 2); 161 } 162 163 public function setUnix($socket = '/var/run/cups/cups.sock') 164 { 165 $this->host = $socket; 166 $this->unix = true; 167 self::_putDebug("Host is " . $this->host, 2); 168 } 169 170 public function setHost($host = 'localhost') 171 { 172 $this->host = $host; 173 $this->unix = false; 174 self::_putDebug("Host is " . $this->host, 2); 175 } 176 177 public function setTimeout($timeout) 178 { 179 $this->timeout = $timeout; 180 } 181 182 public function setPrinterURI($uri) 183 { 184 $length = strlen($uri); 185 $length = chr($length); 186 while (strlen($length) < 2) $length = chr(0x00) . $length; 187 $this->meta->printer_uri = chr(0x45) // uri type | value-tag 188 . chr(0x00) . chr(0x0B) // name-length 189 . "printer-uri" // printer-uri | name 190 . $length . $uri; 191 $this->printer_uri = $uri; 192 self::_putDebug(sprintf(_("Printer URI: %s") , $uri) , 2); 193 $this->setup->uri = 1; 194 } 195 196 public function setData($data) 197 { 198 $this->data = $data; 199 self::_putDebug("Data set", 2); 200 } 201 202 public function setRawText() 203 { 204 $this->setup->datatype = 'TEXT'; 205 $this->meta->mime_media_type = ""; 206 $this->setup->mime_media_type = 1; 207 $this->datahead = chr(0x16); 208 if (is_readable($this->data)) 209 { 210 //It's a filename. Open and stream. 211 $data = fopen($this->data, "rb"); 212 while (!feof($data)) $output = fread($data, 8192); 213 } 214 else 215 { 216 $output = $this->data; 217 } 218 if (substr($output, -1, 1) != chr(0x0c)) { 219 if (!isset($this->setup->noFormFeed)) 220 { 221 $this->datatail = chr(0x0c); 222 } 223 } 224 self::_putDebug(_("Forcing data to be interpreted as RAW TEXT") , 2); 225 } 226 227 public function unsetRawText() 228 { 229 $this->setup->datatype = 'BINARY'; 230 $this->datahead = ''; 231 $this->datatail = ''; 232 self::_putDebug(_("Unset forcing data to be interpreted as RAW TEXT") , 2); 233 } 234 235 public function setBinary() 236 { 237 self::unsetRawText(); 238 } 239 240 public function setFormFeed() 241 { 242 $this->datatail = "\r\n" . chr(0x0c); 243 unset($this->setup->noFormFeed); 244 } 245 246 public function unsetFormFeed() 247 { 248 $this->datatail = ''; 249 $this->setup->noFormFeed = 1; 250 } 251 252 public function setCharset($charset = 'utf-8') 253 { 254 $charset = strtolower($charset); 255 $this->charset = $charset; 256 $this->meta->charset = chr(0x47) // charset type | value-tag 257 . chr(0x00) . chr(0x12) // name-length 258 . "attributes-charset" // attributes-charset | name 259 . self::_giveMeStringLength($charset) // value-length 260 . $charset; // value 261 self::_putDebug(sprintf(_("Charset: %s") , $charset) , 2); 262 $this->setup->charset = 1; 263 } 264 265 public function setLanguage($language = 'en_us') 266 { 267 $language = strtolower($language); 268 $this->meta->language = chr(0x48) // natural-language type | value-tag 269 . chr(0x00) . chr(0x1B) // name-length 270 . "attributes-natural-language" //attributes-natural-language 271 . self::_giveMeStringLength($language) // value-length 272 . $language; // value 273 self::_putDebug(sprintf(_("Language: %s") , $language) , 2); 274 $this->setup->language = 1; 275 } 276 277 public function setDocumentFormat($mime_media_type = 'application/octet-stream') 278 { 279 self::setBinary(); 280 $length = chr(strlen($mime_media_type)); 281 while (strlen($length) < 2) $length = chr(0x00) . $length; 282 self::_putDebug(sprintf(_("mime type: %s") , $mime_media_type) , 2); 283 $this->meta->mime_media_type = chr(0x49) // document-format tag 284 . self::_giveMeStringLength('document-format') . 'document-format' // 285 . self::_giveMeStringLength($mime_media_type) . $mime_media_type; // value 286 $this->setup->mime_media_type = 1; 287 } 288 289 // setDocumentFormat alias for backward compatibility 290 public function setMimeMediaType($mime_media_type = "application/octet-stream") 291 { 292 self::setDocumentFormat($mime_media_type); 293 } 294 295 public function setCopies($nbrcopies = 1) 296 { 297 $this->meta->copies = ""; 298 299 if ($nbrcopies == 1 || !$nbrcopies) 300 { 301 return true; 302 } 303 304 $copies = self::_integerBuild($nbrcopies); 305 $this->meta->copies = chr(0x21) // integer type | value-tag 306 . chr(0x00) . chr(0x06) // name-length 307 . "copies" // copies | name 308 . self::_giveMeStringLength($copies) // value-length 309 . $copies; 310 self::_putDebug(sprintf(_("Copies: %s") , $nbrcopies) , 2); 311 $this->setup->copies = 1; 312 } 313 314 public function setDocumentName($document_name = "") 315 { 316 $this->meta->document_name = ""; 317 if (!$document_name) { 318 return true; 319 } 320 $document_name = substr($document_name, 0, 1023); 321 $length = strlen($document_name); 322 $length = chr($length); 323 while (strlen($length) < 2) $length = chr(0x00) . $length; 324 self::_putDebug(sprintf(_("document name: %s") , $document_name) , 2); 325 $this->meta->document_name = chr(0x41) // textWithoutLanguage tag 326 . chr(0x00) . chr(0x0d) // name-length 327 . "document-name" // mimeMediaType 328 . self::_giveMeStringLength($document_name) . $document_name; // value 329 330 } 331 332 public function setJobName($jobname = '', $absolute = false) 333 { 334 $this->meta->jobname = ''; 335 if ($jobname == '') 336 { 337 $this->meta->jobname = ''; 338 return true; 339 } 340 $postpend = date('-H:i:s-') . $this->_setJobId(); 341 if ($absolute) { 342 $postpend = ''; 343 } 344 if (isset($this->values->jobname) && $jobname == '(PHP)') 345 { 346 $jobname = $this->values->jobname; 347 } 348 $this->values->jobname = $jobname; 349 $jobname.= $postpend; 350 $this->meta->jobname = chr(0x42) // nameWithoutLanguage type || value-tag 351 . chr(0x00) . chr(0x08) // name-length 352 . "job-name" // job-name || name 353 . self::_giveMeStringLength($jobname) // value-length 354 . $jobname; // value 355 self::_putDebug(sprintf(_("Job name: %s") , $jobname) , 2); 356 $this->setup->jobname = 1; 357 } 358 359 public function setUserName($username = 'PHP-SERVER') 360 { 361 $this->requesting_user = $username; 362 $this->meta->username = ''; 363 if (!$username) { 364 return true; 365 } 366 if ($username == 'PHP-SERVER' && isset($this->meta->username)) { 367 return TRUE; 368 } 369 /* 370 $value_length = 0x00; 371 for ($i = 0; $i < strlen($username); $i++) 372 { 373 $value_length+= 0x01; 374 } 375 $value_length = chr($value_length); 376 while (strlen($value_length) < 2) $value_length = chr(0x00) . $value_length; 377 */ 378 $this->meta->username = chr(0x42) // keyword type || value-tag 379 . chr(0x00) . chr(0x14) // name-length 380 . "requesting-user-name" 381 . self::_giveMeStringLength($username) // value-length 382 . $username; 383 self::_putDebug(sprintf(_("Username: %s") , $username) , 2); 384 $this->setup->username = 1; 385 } 386 387 public function setAuthentification($username, $password) 388 { 389 self::setAuthentication($username, $password); 390 } 391 392 public function setAuthentication($username, $password) 393 { 394 $this->password = $password; 395 $this->username = $username; 396 self::_putDebug(_("Setting password") , 2); 397 $this->setup->password = 1; 398 } 399 400 public function setSides($sides = 2) 401 { 402 $this->meta->sides = ''; 403 if (!$sides) 404 { 405 return true; 406 } 407 408 switch ($sides) 409 { 410 case 1: 411 $sides = "one-sided"; 412 break; 413 414 case 2: 415 $sides = "two-sided-long-edge"; 416 break; 417 418 case "2CE": 419 $sides = "two-sided-short-edge"; 420 break; 421 } 422 423 $this->meta->sides = chr(0x44) // keyword type | value-tag 424 . chr(0x00) . chr(0x05) // name-length 425 . "sides" // sides | name 426 . self::_giveMeStringLength($sides) // value-length 427 . $sides; // one-sided | value 428 self::_putDebug(sprintf(_("Sides value set to %s") , $sides) , 2); 429 } 430 431 public function setFidelity() 432 { 433 // whether the server can't replace any attributes 434 // (eg, 2 sided print is not possible, 435 // so print one sided) and DO NOT THE JOB. 436 $this->meta->fidelity = chr(0x22) // boolean type | value-tag 437 . chr(0x00) . chr(0x16) // name-length 438 . "ipp-attribute-fidelity" // ipp-attribute-fidelity | name 439 . chr(0x00) . chr(0x01) // value-length 440 . chr(0x01); // true | value 441 self::_putDebug(_("Fidelity attribute is set (paranoid mode)") , 3); 442 } 443 444 public function unsetFidelity() 445 { 446 // whether the server can replace any attributes 447 // (eg, 2 sided print is not possible, 448 // so print one sided) and DO THE JOB. 449 $this->meta->fidelity = chr(0x22) // boolean type | value-tag 450 . chr(0x00) . chr(0x16) // name-length 451 . "ipp-attribute-fidelity" // ipp-attribute-fidelity | name 452 . chr(0x00) . chr(0x01) // value-length 453 . chr(0x00); // false | value 454 self::_putDebug(_("Fidelity attribute is unset") , 2); 455 } 456 457 public function setMessage($message = '') 458 { 459 $this->meta->message = ''; 460 if (!$message) { 461 return true; 462 } 463 $this->meta->message = 464 chr(0x41) // attribute type = textWithoutLanguage 465 . chr(0x00) 466 . chr(0x07) 467 . "message" 468 . self::_giveMeStringLength(substr($message, 0, 127)) 469 . substr($message, 0, 127); 470 self::_putDebug(sprintf(_('Setting message to "%s"') , $message) , 2); 471 } 472 473 public function setPageRanges($page_ranges) 474 { 475 // $pages_ranges = string: "1:5 10:25 40:52 ..." 476 // to unset, specify an empty string. 477 $this->meta->page_range = ''; 478 if (!$page_ranges) { 479 return true; 480 } 481 $page_ranges = trim(str_replace("-", ":", $page_ranges)); 482 $first = true; 483 #$page_ranges = split(' ', $page_ranges); 484 $page_ranges = preg_split('# #', $page_ranges); 485 foreach($page_ranges as $page_range) 486 { 487 $value = self::_rangeOfIntegerBuild($page_range); 488 if ($first) 489 { 490 $this->meta->page_ranges .= 491 $this->tags_types['rangeOfInteger']['tag'] 492 . self::_giveMeStringLength('page-ranges') 493 . 'page-ranges' 494 . self::_giveMeStringLength($value) 495 . $value; 496 } 497 else 498 { 499 $this->meta->page_ranges .= 500 $this->tags_types['rangeOfInteger']['tag'] 501 . self::_giveMeStringLength('') 502 . self::_giveMeStringLength($value) 503 . $value; 504 $first = false; 505 } 506 } 507 } 508 509 public function setAttribute($attribute, $values) 510 { 511 $operation_attributes_tags = array_keys($this->operation_tags); 512 $job_attributes_tags = array_keys($this->job_tags); 513 $printer_attributes_tags = array_keys($this->printer_tags); 514 self::unsetAttribute($attribute); 515 if (in_array($attribute, $operation_attributes_tags)) 516 { 517 if (!is_array($values)) 518 { 519 self::_setOperationAttribute($attribute, $values); 520 } 521 else 522 { 523 foreach($values as $value) 524 { 525 self::_setOperationAttribute($attribute, $value); 526 } 527 } 528 } 529 elseif (in_array($attribute, $job_attributes_tags)) 530 { 531 if (!is_array($values)) 532 { 533 self::_setJobAttribute($attribute, $values); 534 } 535 else 536 { 537 foreach($values as $value) 538 { 539 self::_setJobAttribute($attribute, $value); 540 } 541 } 542 } 543 elseif (in_array($attribute, $printer_attributes_tags)) 544 { 545 if (!is_array($values)) 546 { 547 self::_setPrinterAttribute($attribute, $values); 548 } 549 else 550 { 551 foreach($values as $value) 552 { 553 self::_setPrinterAttribute($attribute, $value); 554 } 555 } 556 } 557 else 558 { 559 trigger_error( 560 sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'), 561 $attribute) , E_USER_NOTICE); 562 self::_putDebug( 563 sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'), 564 $attribute) , 3); 565 self::_errorLog( 566 sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'), 567 $attribute) , 2); 568 return FALSE; 569 } 570 } 571 572 public function unsetAttribute($attribute) 573 { 574 $operation_attributes_tags = array_keys($this->operation_tags); 575 $job_attributes_tags = array_keys($this->job_tags); 576 $printer_attributes_tags = array_keys($this->printer_tags); 577 if (in_array($attribute, $operation_attributes_tags)) 578 { 579 unset( 580 $this->operation_tags[$attribute]['value'], 581 $this->operation_tags[$attribute]['systag'] 582 ); 583 } 584 elseif (in_array($attribute, $job_attributes_tags)) 585 { 586 unset( 587 $this->job_tags[$attribute]['value'], 588 $this->job_tags[$attribute]['systag'] 589 ); 590 } 591 elseif (in_array($attribute, $printer_attributes_tags)) 592 { 593 unset( 594 $this->printer_tags[$attribute]['value'], 595 $this->printer_tags[$attribute]['systag'] 596 ); 597 } 598 else 599 { 600 trigger_error( 601 sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'), 602 $attribute) , E_USER_NOTICE); 603 self::_putDebug( 604 sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'), 605 $attribute) , 3); 606 self::_errorLog( 607 sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'), 608 $attribute) , 2); 609 return FALSE; 610 } 611 return true; 612 } 613 614 // 615 // LOGGING / DEBUGGING 616 // 617 /** 618 * Sets log file destination. Creates the file if has permission. 619 * 620 * @param string $log_destination 621 * @param string $destination_type 622 * @param int $level 623 * 624 * @throws ippException 625 */ 626 public function setLog($log_destination, $destination_type = 'file', $level = 2) 627 { 628 if (!file_exists($log_destination) && is_writable(dirname($log_destination))) 629 { 630 touch($log_destination); 631 chmod($log_destination, 0777); 632 } 633 634 switch ($destination_type) 635 { 636 case 'file': 637 case 3: 638 $this->log_destination = $log_destination; 639 $this->log_type = 3; 640 break; 641 642 case 'logger': 643 case 0: 644 $this->log_destination = ''; 645 $this->log_type = 0; 646 break; 647 648 case 'e-mail': 649 case 1: 650 $this->log_destination = $log_destination; 651 $this->log_type = 1; 652 break; 653 } 654 $this->log_level = $level; 655 } 656 657 public function printDebug() 658 { 659 for ($i = 0; $i < $this->debug_count; $i++) 660 { 661 echo $this->debug[$i], "\n"; 662 } 663 $this->debug = array(); 664 $this->debug_count = 0; 665 } 666 667 public function getDebug() 668 { 669 $debug = ''; 670 for ($i = 0; $i < $this->debug_count; $i++) 671 { 672 $debug.= $this->debug[$i]; 673 } 674 $this->debug = array(); 675 $this->debug_count = 0; 676 return $debug; 677 } 678 679 // 680 // OPERATIONS 681 // 682 public function printJob() 683 { 684 // this BASIC version of printJob do not parse server 685 // output for job's attributes 686 self::_putDebug( 687 sprintf( 688 "************** Date: %s ***********", 689 date('Y-m-d H:i:s') 690 ) 691 ); 692 if (!$this->_stringJob()) { 693 return FALSE; 694 } 695 if (is_readable($this->data)) 696 { 697 self::_putDebug(_("Printing a FILE")); 698 $this->output = $this->stringjob; 699 if ($this->setup->datatype == "TEXT") 700 { 701 $this->output.= chr(0x16); 702 } 703 $post_values = array( 704 "Content-Type" => "application/ipp", 705 "Data" => $this->output, 706 "File" => $this->data 707 ); 708 if ($this->setup->datatype == "TEXT" && !isset($this->setup->noFormFeed)) 709 { 710 $post_values = array_merge( 711 $post_values, 712 array( 713 "Filetype" => "TEXT" 714 ) 715 ); 716 } 717 } 718 else 719 { 720 self::_putDebug(_("Printing DATA")); 721 $this->output = 722 $this->stringjob 723 . $this->datahead 724 . $this->data 725 . $this->datatail; 726 $post_values = array( 727 "Content-Type" => "application/ipp", 728 "Data" => $this->output 729 ); 730 } 731 if (self::_sendHttp($post_values, $this->paths["printers"])) 732 { 733 self::_parseServerOutput(); 734 } 735 if (isset($this->serveroutput) && isset($this->serveroutput->status)) 736 { 737 $this->status = array_merge($this->status, array( 738 $this->serveroutput->status 739 )); 740 if ($this->serveroutput->status == "successfull-ok") 741 { 742 self::_errorLog( 743 sprintf("printing job %s: ", $this->last_job) 744 . $this->serveroutput->status, 745 3); 746 } 747 else 748 { 749 self::_errorLog( 750 sprintf("printing job: ", $this->last_job) 751 . $this->serveroutput->status, 752 1); 753 } 754 return $this->serveroutput->status; 755 } 756 757 $this->status = 758 array_merge($this->status, array("OPERATION FAILED")); 759 $this->jobs = 760 array_merge($this->jobs, array("")); 761 $this->jobs_uri = 762 array_merge($this->jobs_uri, array("")); 763 764 self::_errorLog("printing job : OPERATION FAILED", 1); 765 return false; 766 } 767 768 // 769 // HTTP OUTPUT 770 // 771 protected function _sendHttp($post_values, $uri) 772 { 773 /* 774 This function Copyright (C) 2005-2006 Thomas Harding, Manuel Lemos 775 */ 776 $this->response_completed[] = "no"; 777 unset($this->serverouptut); 778 self::_putDebug(_("Processing HTTP request") , 2); 779 $this->serveroutput->headers = array(); 780 $this->serveroutput->body = ""; 781 $http = new http_class; 782 if (!$this->unix) { 783 // DOL_LDR_CHANGE 784 if (empty($this->host)) $this->host='127.0.0.1'; 785 $http->host = $this->host; 786 } 787 else { 788 $http->host = "localhost"; 789 } 790 $http->with_exceptions = $this->with_exceptions; 791 if ($this->debug_http) 792 { 793 $http->debug = 1; 794 $http->html_debug = 0; 795 } 796 else 797 { 798 $http->debug = 0; 799 $http->html_debug = 0; 800 } 801 $url = "http://" . $this->host; 802 if ($this->ssl) { 803 $url = "https://" . $this->host; 804 } 805 if ($this->unix) { 806 $url = "unix://" . $this->host; 807 } 808 $http->port = $this->port; 809 $http->timeout = $this->http_timeout; 810 $http->data_timeout = $this->http_data_timeout; 811 $http->force_multipart_form_post = false; 812 $http->user = $this->username; 813 $http->password = $this->password; 814 $error = $http->GetRequestArguments($url, $arguments); 815 $arguments["RequestMethod"] = "POST"; 816 $arguments["Headers"] = array( 817 "Content-Type" => "application/ipp" 818 ); 819 $arguments["BodyStream"] = array( 820 array( 821 "Data" => $post_values["Data"] 822 ) 823 ); 824 if (isset($post_values["File"])) { 825 $arguments["BodyStream"][] = array( 826 "File" => $post_values["File"] 827 ); 828 } 829 if (isset($post_values["FileType"]) 830 && !strcmp($post_values["FileType"], "TEXT") 831 ) 832 { 833 $arguments["BodyStream"][] = array("Data" => Chr(12)); 834 } 835 $arguments["RequestURI"] = $uri; 836 if ($this->with_exceptions && $this->handle_http_exceptions) 837 { 838 try 839 { 840 $success = $http->Open($arguments); 841 } 842 catch(httpException $e) 843 { 844 throw new ippException( 845 sprintf("http error: %s", $e->getMessage()), 846 $e->getErrno()); 847 } 848 } 849 else 850 { 851 $success = $http->Open($arguments); 852 } 853 if ($success[0] == true) 854 { 855 $success = $http->SendRequest($arguments); 856 if ($success[0] == true) 857 { 858 self::_putDebug("H T T P R E Q U E S T :"); 859 self::_putDebug("Request headers:"); 860 for (Reset($http->request_headers) , $header = 0; $header < count($http->request_headers); Next($http->request_headers) , $header++) 861 { 862 $header_name = Key($http->request_headers); 863 if (GetType($http->request_headers[$header_name]) == "array") 864 { 865 for ($header_value = 0; $header_value < count($http->request_headers[$header_name]); $header_value++) 866 { 867 self::_putDebug($header_name . ": " . $http->request_headers[$header_name][$header_value]); 868 } 869 } 870 else 871 { 872 self::_putDebug($header_name . ": " . $http->request_headers[$header_name]); 873 } 874 } 875 self::_putDebug("Request body:"); 876 self::_putDebug( 877 htmlspecialchars($http->request_body) 878 . "*********** END REQUEST BODY *********" 879 ); 880 $i = 0; 881 $headers = array(); 882 unset($this->serveroutput->headers); 883 $http->ReadReplyHeaders($headers); 884 self::_putDebug("H T T P R E S P O N S E :"); 885 self::_putDebug("Response headers:"); 886 for (Reset($headers) , $header = 0; $header < count($headers); Next($headers) , $header++) 887 { 888 $header_name = Key($headers); 889 if (GetType($headers[$header_name]) == "array") 890 { 891 for ($header_value = 0; $header_value < count($headers[$header_name]); $header_value++) 892 { 893 self::_putDebug($header_name . ": " . $headers[$header_name][$header_value]); 894 $this->serveroutput->headers[$i] = 895 $header_name . ": " 896 . $headers[$header_name][$header_value]; 897 $i++; 898 } 899 } 900 else 901 { 902 self::_putDebug($header_name . ": " . $headers[$header_name]); 903 $this->serveroutput->headers[$i] = 904 $header_name 905 . ": " 906 . $headers[$header_name]; 907 $i++; 908 } 909 } 910 self::_putDebug("\n\nResponse body:\n"); 911 $this->serveroutput->body = ""; 912 for (;;) 913 { 914 $http->ReadReplyBody($body, 1024); 915 if (strlen($body) == 0) { 916 break; 917 } 918 919 self::_putDebug(htmlentities($body)); 920 $this->serveroutput->body.= $body; 921 } 922 self::_putDebug("********* END RESPONSE BODY ********"); 923 } 924 } 925 $http->Close(); 926 return true; 927 } 928 929 // 930 // INIT 931 // 932 protected function _initTags() 933 { 934 $this->tags_types = array( 935 "unsupported" => array( 936 "tag" => chr(0x10) , 937 "build" => "" 938 ) , 939 "reserved" => array( 940 "tag" => chr(0x11) , 941 "build" => "" 942 ) , 943 "unknown" => array( 944 "tag" => chr(0x12) , 945 "build" => "" 946 ) , 947 "no-value" => array( 948 "tag" => chr(0x13) , 949 "build" => "no_value" 950 ) , 951 "integer" => array( 952 "tag" => chr(0x21) , 953 "build" => "integer" 954 ) , 955 "boolean" => array( 956 "tag" => chr(0x22) , 957 "build" => "boolean" 958 ) , 959 "enum" => array( 960 "tag" => chr(0x23) , 961 "build" => "enum" 962 ) , 963 "octetString" => array( 964 "tag" => chr(0x30) , 965 "build" => "octet_string" 966 ) , 967 "datetime" => array( 968 "tag" => chr(0x31) , 969 "build" => "datetime" 970 ) , 971 "resolution" => array( 972 "tag" => chr(0x32) , 973 "build" => "resolution" 974 ) , 975 "rangeOfInteger" => array( 976 "tag" => chr(0x33) , 977 "build" => "range_of_integers" 978 ) , 979 "textWithLanguage" => array( 980 "tag" => chr(0x35) , 981 "build" => "string" 982 ) , 983 "nameWithLanguage" => array( 984 "tag" => chr(0x36) , 985 "build" => "string" 986 ) , 987 /* 988 "text" => array ("tag" => chr(0x40), 989 "build" => "string"), 990 "text string" => array ("tag" => chr(0x40), 991 "build" => "string"), 992 */ 993 "textWithoutLanguage" => array( 994 "tag" => chr(0x41) , 995 "build" => "string" 996 ) , 997 "nameWithoutLanguage" => array( 998 "tag" => chr(0x42) , 999 "buid" => "string" 1000 ) , 1001 "keyword" => array( 1002 "tag" => chr(0x44) , 1003 "build" => "string" 1004 ) , 1005 "uri" => array( 1006 "tag" => chr(0x45) , 1007 "build" => "string" 1008 ) , 1009 "uriScheme" => array( 1010 "tag" => chr(0x46) , 1011 "build" => "string" 1012 ) , 1013 "charset" => array( 1014 "tag" => chr(0x47) , 1015 "build" => "string" 1016 ) , 1017 "naturalLanguage" => array( 1018 "tag" => chr(0x48) , 1019 "build" => "string" 1020 ) , 1021 "mimeMediaType" => array( 1022 "tag" => chr(0x49) , 1023 "build" => "string" 1024 ) , 1025 "extendedAttributes" => array( 1026 "tag" => chr(0x7F) , 1027 "build" => "extended" 1028 ) , 1029 ); 1030 $this->operation_tags = array( 1031 "compression" => array( 1032 "tag" => "keyword" 1033 ) , 1034 "document-natural-language" => array( 1035 "tag" => "naturalLanguage" 1036 ) , 1037 "job-k-octets" => array( 1038 "tag" => "integer" 1039 ) , 1040 "job-impressions" => array( 1041 "tag" => "integer" 1042 ) , 1043 "job-media-sheets" => array( 1044 "tag" => "integer" 1045 ) , 1046 ); 1047 $this->job_tags = array( 1048 "job-priority" => array( 1049 "tag" => "integer" 1050 ) , 1051 "job-hold-until" => array( 1052 "tag" => "keyword" 1053 ) , 1054 "job-sheets" => array( 1055 "tag" => "keyword" 1056 ) , //banner page 1057 "multiple-document-handling" => array( 1058 "tag" => "keyword" 1059 ) , 1060 //"copies" => array("tag" => "integer"), 1061 "finishings" => array( 1062 "tag" => "enum" 1063 ) , 1064 //"page-ranges" => array("tag" => "rangeOfInteger"), // has its own function 1065 //"sides" => array("tag" => "keyword"), // has its own function 1066 "number-up" => array( 1067 "tag" => "integer" 1068 ) , 1069 "orientation-requested" => array( 1070 "tag" => "enum" 1071 ) , 1072 "media" => array( 1073 "tag" => "keyword" 1074 ) , 1075 "printer-resolution" => array( 1076 "tag" => "resolution" 1077 ) , 1078 "print-quality" => array( 1079 "tag" => "enum" 1080 ) , 1081 "job-message-from-operator" => array( 1082 "tag" => "textWithoutLanguage" 1083 ) , 1084 ); 1085 $this->printer_tags = array( 1086 "requested-attributes" => array( 1087 "tag" => "keyword" 1088 ) 1089 ); 1090 } 1091 1092 // 1093 // SETUP 1094 // 1095 protected function _setOperationId() 1096 { 1097 $prepend = ''; 1098 $this->operation_id+= 1; 1099 $this->meta->operation_id = self::_integerBuild($this->operation_id); 1100 self::_putDebug("operation id is: " . $this->operation_id, 2); 1101 } 1102 1103 protected function _setJobId() 1104 { 1105 $this->meta->jobid+= 1; 1106 $prepend = ''; 1107 $prepend_length = 4 - strlen($this->meta->jobid); 1108 for ($i = 0; $i < $prepend_length; $i++) { 1109 $prepend.= '0'; 1110 } 1111 return $prepend . $this->meta->jobid; 1112 } 1113 1114 protected function _setJobUri($job_uri) 1115 { 1116 $this->meta->job_uri = chr(0x45) // type uri 1117 . chr(0x00) . chr(0x07) // name-length 1118 . "job-uri" 1119 //. chr(0x00).chr(strlen($job_uri)) 1120 . self::_giveMeStringLength($job_uri) . $job_uri; 1121 self::_putDebug("job-uri is: " . $job_uri, 2); 1122 } 1123 1124 // 1125 // RESPONSE PARSING 1126 // 1127 protected function _parseServerOutput() 1128 { 1129 $this->serveroutput->response = array(); 1130 if (!self::_parseHttpHeaders()) { 1131 return FALSE; 1132 } 1133 $this->_parsing->offset = 0; 1134 self::_parseIppVersion(); 1135 self::_parseStatusCode(); 1136 self::_parseRequestID(); 1137 $this->_parseResponse(); 1138 //devel 1139 self::_putDebug( 1140 sprintf("***** IPP STATUS: %s ******", $this->serveroutput->status), 1141 4); 1142 self::_putDebug("****** END OF OPERATION ****"); 1143 return true; 1144 } 1145 1146 protected function _parseHttpHeaders() 1147 { 1148 $response = ""; 1149 switch ($this->serveroutput->headers[0]) 1150 { 1151 case "http/1.1 200 ok: ": 1152 $this->serveroutput->httpstatus = "HTTP/1.1 200 OK"; 1153 $response = "OK"; 1154 break; 1155 1156 // primitive http/1.0 for Lexmark printers (from Rick Baril) 1157 case "http/1.0 200 ok: ": 1158 $this->serveroutput->httpstatus = "HTTP/1.0 200 OK"; 1159 $response = "OK"; 1160 break; 1161 1162 case "http/1.1 100 continue: ": 1163 $this->serveroutput->httpstatus = "HTTP/1.1 100 CONTINUE"; 1164 $response = "OK"; 1165 break; 1166 1167 case "": 1168 $this->serveroutput->httpstatus = "HTTP/1.1 000 No Response From Server"; 1169 $this->serveroutput->status = "HTTP-ERROR-000_NO_RESPONSE_FROM_SERVER"; 1170 trigger_error("No Response From Server", E_USER_WARNING); 1171 self::_errorLog("No Response From Server", 1); 1172 $this->disconnected = 1; 1173 return FALSE; 1174 break; 1175 1176 default: 1177 $server_response = preg_replace("/: $/", '', $this->serveroutput->headers[0]); 1178 #$strings = split(' ', $server_response, 3); 1179 $strings = preg_split('# #', $server_response, 3); 1180 $errno = $strings[1]; 1181 $string = strtoupper(str_replace(' ', '_', $strings[2])); 1182 trigger_error( 1183 sprintf(_("server responds %s") , $server_response), 1184 E_USER_WARNING); 1185 self::_errorLog("server responds " . $server_response, 1); 1186 $this->serveroutput->httpstatus = 1187 strtoupper($strings[0]) 1188 . " " 1189 . $errno 1190 . " " 1191 . ucfirst($strings[2]); 1192 1193 $this->serveroutput->status = 1194 "HTTP-ERROR-" 1195 . $errno 1196 . "-" 1197 . $string; 1198 $this->disconnected = 1; 1199 return FALSE; 1200 break; 1201 } 1202 unset($this->serveroutput->headers); 1203 return TRUE; 1204 } 1205 1206 protected function _parseIppVersion() 1207 { 1208 $ippversion = 1209 (ord($this->serveroutput->body[$this->_parsing->offset]) * 256) 1210 + ord($this->serveroutput->body[$this->_parsing->offset + 1]); 1211 switch ($ippversion) 1212 { 1213 case 0x0101: 1214 $this->serveroutput->ipp_version = "1.1"; 1215 break; 1216 1217 default: 1218 $this->serveroutput->ipp_version = 1219 sprintf("%u.%u (Unknown)", 1220 ord($this->serveroutput->body[$this->_parsing->offset]) * 256, 1221 ord($this->serveroutput->body[$this->_parsing->offset + 1])); 1222 break; 1223 } 1224 self::_putDebug("I P P R E S P O N S E :\n\n"); 1225 self::_putDebug( 1226 sprintf("IPP version %s%s: %s", 1227 ord($this->serveroutput->body[$this->_parsing->offset]), 1228 ord($this->serveroutput->body[$this->_parsing->offset + 1]), 1229 $this->serveroutput->ipp_version)); 1230 $this->_parsing->offset+= 2; 1231 return; 1232 } 1233 1234 protected function _parseStatusCode() 1235 { 1236 $status_code = 1237 (ord($this->serveroutput->body[$this->_parsing->offset]) * 256) 1238 + ord($this->serveroutput->body[$this->_parsing->offset + 1]); 1239 $this->serveroutput->status = "NOT PARSED"; 1240 $this->_parsing->offset+= 2; 1241 if (strlen($this->serveroutput->body) < $this->_parsing->offset) 1242 { 1243 return false; 1244 } 1245 if ($status_code < 0x00FF) 1246 { 1247 $this->serveroutput->status = "successfull"; 1248 } 1249 elseif ($status_code < 0x01FF) 1250 { 1251 $this->serveroutput->status = "informational"; 1252 } 1253 elseif ($status_code < 0x02FF) 1254 { 1255 $this->serveroutput->status = "redirection"; 1256 } 1257 elseif ($status_code < 0x04FF) 1258 { 1259 $this->serveroutput->status = "client-error"; 1260 } 1261 elseif ($status_code < 0x05FF) 1262 { 1263 $this->serveroutput->status = "server-error"; 1264 } 1265 switch ($status_code) 1266 { 1267 case 0x0000: 1268 $this->serveroutput->status = "successfull-ok"; 1269 break; 1270 1271 case 0x0001: 1272 $this->serveroutput->status = "successful-ok-ignored-or-substituted-attributes"; 1273 break; 1274 1275 case 0x002: 1276 $this->serveroutput->status = "successful-ok-conflicting-attributes"; 1277 break; 1278 1279 case 0x0400: 1280 $this->serveroutput->status = "client-error-bad-request"; 1281 break; 1282 1283 case 0x0401: 1284 $this->serveroutput->status = "client-error-forbidden"; 1285 break; 1286 1287 case 0x0402: 1288 $this->serveroutput->status = "client-error-not-authenticated"; 1289 break; 1290 1291 case 0x0403: 1292 $this->serveroutput->status = "client-error-not-authorized"; 1293 break; 1294 1295 case 0x0404: 1296 $this->serveroutput->status = "client-error-not-possible"; 1297 break; 1298 1299 case 0x0405: 1300 $this->serveroutput->status = "client-error-timeout"; 1301 break; 1302 1303 case 0x0406: 1304 $this->serveroutput->status = "client-error-not-found"; 1305 break; 1306 1307 case 0x0407: 1308 $this->serveroutput->status = "client-error-gone"; 1309 break; 1310 1311 case 0x0408: 1312 $this->serveroutput->status = "client-error-request-entity-too-large"; 1313 break; 1314 1315 case 0x0409: 1316 $this->serveroutput->status = "client-error-request-value-too-long"; 1317 break; 1318 1319 case 0x040A: 1320 $this->serveroutput->status = "client-error-document-format-not-supported"; 1321 break; 1322 1323 case 0x040B: 1324 $this->serveroutput->status = "client-error-attributes-or-values-not-supported"; 1325 break; 1326 1327 case 0x040C: 1328 $this->serveroutput->status = "client-error-uri-scheme-not-supported"; 1329 break; 1330 1331 case 0x040D: 1332 $this->serveroutput->status = "client-error-charset-not-supported"; 1333 break; 1334 1335 case 0x040E: 1336 $this->serveroutput->status = "client-error-conflicting-attributes"; 1337 break; 1338 1339 case 0x040F: 1340 $this->serveroutput->status = "client-error-compression-not-supported"; 1341 break; 1342 1343 case 0x0410: 1344 $this->serveroutput->status = "client-error-compression-error"; 1345 break; 1346 1347 case 0x0411: 1348 $this->serveroutput->status = "client-error-document-format-error"; 1349 break; 1350 1351 case 0x0412: 1352 $this->serveroutput->status = "client-error-document-access-error"; 1353 break; 1354 1355 case 0x0413: // RFC3380 1356 $this->serveroutput->status = "client-error-attributes-not-settable"; 1357 break; 1358 1359 case 0x0500: 1360 $this->serveroutput->status = "server-error-internal-error"; 1361 break; 1362 1363 case 0x0501: 1364 $this->serveroutput->status = "server-error-operation-not-supported"; 1365 break; 1366 1367 case 0x0502: 1368 $this->serveroutput->status = "server-error-service-unavailable"; 1369 break; 1370 1371 case 0x0503: 1372 $this->serveroutput->status = "server-error-version-not-supported"; 1373 break; 1374 1375 case 0x0504: 1376 $this->serveroutput->status = "server-error-device-error"; 1377 break; 1378 1379 case 0x0505: 1380 $this->serveroutput->status = "server-error-temporary-error"; 1381 break; 1382 1383 case 0x0506: 1384 $this->serveroutput->status = "server-error-not-accepting-jobs"; 1385 break; 1386 1387 case 0x0507: 1388 $this->serveroutput->status = "server-error-busy"; 1389 break; 1390 1391 case 0x0508: 1392 $this->serveroutput->status = "server-error-job-canceled"; 1393 break; 1394 1395 case 0x0509: 1396 $this->serveroutput->status = "server-error-multiple-document-jobs-not-supported"; 1397 break; 1398 1399 default: 1400 break; 1401 } 1402 self::_putDebug( 1403 sprintf( 1404 "status-code: %s%s: %s ", 1405 $this->serveroutput->body[$this->_parsing->offset], 1406 $this->serveroutput->body[$this->_parsing->offset + 1], 1407 $this->serveroutput->status), 1408 4); 1409 return; 1410 } 1411 1412 protected function _parseRequestID() 1413 { 1414 $this->serveroutput->request_id = 1415 self::_interpretInteger( 1416 substr($this->serveroutput->body, $this->_parsing->offset, 4) 1417 ); 1418 self::_putDebug("request-id " . $this->serveroutput->request_id, 2); 1419 $this->_parsing->offset+= 4; 1420 return; 1421 } 1422 1423 protected function _interpretInteger($value) 1424 { 1425 // they are _signed_ integers 1426 $value_parsed = 0; 1427 for ($i = strlen($value); $i > 0; $i --) 1428 { 1429 $value_parsed += 1430 ( 1431 (1 << (($i - 1) * 8)) 1432 * 1433 ord($value[strlen($value) - $i]) 1434 ); 1435 } 1436 if ($value_parsed >= 2147483648) 1437 { 1438 $value_parsed -= 4294967296; 1439 } 1440 return $value_parsed; 1441 } 1442 1443 protected function _parseResponse() 1444 { 1445 } 1446 1447 // 1448 // REQUEST BUILDING 1449 // 1450 protected function _stringJob() 1451 { 1452 if (!isset($this->setup->charset)) { 1453 self::setCharset(); 1454 } 1455 if (!isset($this->setup->datatype)) { 1456 self::setBinary(); 1457 } 1458 if (!isset($this->setup->uri)) 1459 { 1460 $this->getPrinters(); 1461 unset($this->jobs[count($this->jobs) - 1]); 1462 unset($this->jobs_uri[count($this->jobs_uri) - 1]); 1463 unset($this->status[count($this->status) - 1]); 1464 if (array_key_exists(0, $this->available_printers)) 1465 { 1466 self::setPrinterURI($this->available_printers[0]); 1467 } 1468 else 1469 { 1470 trigger_error( 1471 _("_stringJob: Printer URI is not set: die"), 1472 E_USER_WARNING); 1473 self::_putDebug(_("_stringJob: Printer URI is not set: die") , 4); 1474 self::_errorLog(" Printer URI is not set, die", 2); 1475 return FALSE; 1476 } 1477 } 1478 if (!isset($this->setup->copies)) { 1479 self::setCopies(1); 1480 } 1481 if (!isset($this->setup->language)) { 1482 self::setLanguage('en_us'); 1483 } 1484 if (!isset($this->setup->mime_media_type)) { 1485 self::setMimeMediaType(); 1486 } 1487 if (!isset($this->setup->jobname)) { 1488 self::setJobName(); 1489 } 1490 unset($this->setup->jobname); 1491 if (!isset($this->meta->username)) { 1492 self::setUserName(); 1493 } 1494 if (!isset($this->meta->fidelity)) { 1495 $this->meta->fidelity = ''; 1496 } 1497 if (!isset($this->meta->document_name)) { 1498 $this->meta->document_name = ''; 1499 } 1500 if (!isset($this->meta->sides)) { 1501 $this->meta->sides = ''; 1502 } 1503 if (!isset($this->meta->page_ranges)) { 1504 $this->meta->page_ranges = ''; 1505 } 1506 $jobattributes = ''; 1507 $operationattributes = ''; 1508 $printerattributes = ''; 1509 $this->_buildValues($operationattributes, $jobattributes, $printerattributes); 1510 self::_setOperationId(); 1511 if (!isset($this->error_generation->request_body_malformed)) 1512 { 1513 $this->error_generation->request_body_malformed = ""; 1514 } 1515 $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number 1516 . chr(0x00) . chr(0x02) // Print-Job | operation-id 1517 . $this->meta->operation_id // request-id 1518 . chr(0x01) // start operation-attributes | operation-attributes-tag 1519 . $this->meta->charset 1520 . $this->meta->language 1521 . $this->meta->printer_uri 1522 . $this->meta->username 1523 . $this->meta->jobname 1524 . $this->meta->fidelity 1525 . $this->meta->document_name 1526 . $this->meta->mime_media_type 1527 . $operationattributes; 1528 if ($this->meta->copies || $this->meta->sides || $this->meta->page_ranges || !empty($jobattributes)) 1529 { 1530 $this->stringjob .= 1531 chr(0x02) // start job-attributes | job-attributes-tag 1532 . $this->meta->copies 1533 . $this->meta->sides 1534 . $this->meta->page_ranges 1535 . $jobattributes; 1536 } 1537 $this->stringjob.= chr(0x03); // end-of-attributes | end-of-attributes-tag 1538 self::_putDebug( 1539 sprintf(_("String sent to the server is: %s"), 1540 $this->stringjob) 1541 ); 1542 return TRUE; 1543 } 1544 1545 protected function _buildValues(&$operationattributes, &$jobattributes, &$printerattributes) 1546 { 1547 $operationattributes = ''; 1548 foreach($this->operation_tags as $key => $values) 1549 { 1550 $item = 0; 1551 if (array_key_exists('value', $values)) 1552 { 1553 foreach($values['value'] as $item_value) 1554 { 1555 if ($item == 0) 1556 { 1557 $operationattributes .= 1558 $values['systag'] 1559 . self::_giveMeStringLength($key) 1560 . $key 1561 . self::_giveMeStringLength($item_value) 1562 . $item_value; 1563 } 1564 else 1565 { 1566 $operationattributes .= 1567 $values['systag'] 1568 . self::_giveMeStringLength('') 1569 . self::_giveMeStringLength($item_value) 1570 . $item_value; 1571 } 1572 $item++; 1573 } 1574 } 1575 } 1576 $jobattributes = ''; 1577 foreach($this->job_tags as $key => $values) 1578 { 1579 $item = 0; 1580 if (array_key_exists('value', $values)) 1581 { 1582 foreach($values['value'] as $item_value) 1583 { 1584 if ($item == 0) 1585 { 1586 $jobattributes .= 1587 $values['systag'] 1588 . self::_giveMeStringLength($key) 1589 . $key 1590 . self::_giveMeStringLength($item_value) 1591 . $item_value; 1592 } 1593 else 1594 { 1595 $jobattributes .= 1596 $values['systag'] 1597 . self::_giveMeStringLength('') 1598 . self::_giveMeStringLength($item_value) 1599 . $item_value; 1600 } 1601 $item++; 1602 } 1603 } 1604 } 1605 $printerattributes = ''; 1606 foreach($this->printer_tags as $key => $values) 1607 { 1608 $item = 0; 1609 if (array_key_exists('value', $values)) 1610 { 1611 foreach($values['value'] as $item_value) 1612 { 1613 if ($item == 0) 1614 { 1615 $printerattributes .= 1616 $values['systag'] 1617 . self::_giveMeStringLength($key) 1618 . $key 1619 . self::_giveMeStringLength($item_value) 1620 . $item_value; 1621 } 1622 else 1623 { 1624 $printerattributes .= 1625 $values['systag'] 1626 . self::_giveMeStringLength('') 1627 . self::_giveMeStringLength($item_value) 1628 . $item_value; 1629 } 1630 $item++; 1631 } 1632 } 1633 } 1634 reset($this->job_tags); 1635 reset($this->operation_tags); 1636 reset($this->printer_tags); 1637 return true; 1638 } 1639 1640 protected function _giveMeStringLength($string) 1641 { 1642 $length = strlen($string); 1643 if ($length > ((0xFF << 8) + 0xFF) ) 1644 { 1645 $errmsg = sprintf ( 1646 _('max string length for an ipp meta-information = %d, while here %d'), 1647 ((0xFF << 8) + 0xFF), $length); 1648 1649 if ($this->with_exceptions) 1650 { 1651 throw new ippException($errmsg); 1652 } 1653 else 1654 { 1655 trigger_error ($errmsg, E_USER_ERROR); 1656 } 1657 } 1658 $int1 = $length & 0xFF; 1659 $length -= $int1; 1660 $length = $length >> 8; 1661 $int2 = $length & 0xFF; 1662 return chr($int2) . chr($int1); 1663 } 1664 1665 protected function _enumBuild($tag, $value) 1666 { 1667 switch ($tag) 1668 { 1669 case "orientation-requested": 1670 switch ($value) 1671 { 1672 case 'portrait': 1673 $value = chr(3); 1674 break; 1675 1676 case 'landscape': 1677 $value = chr(4); 1678 break; 1679 1680 case 'reverse-landscape': 1681 $value = chr(5); 1682 break; 1683 1684 case 'reverse-portrait': 1685 $value = chr(6); 1686 break; 1687 } 1688 break; 1689 1690 case "print-quality": 1691 switch ($value) 1692 { 1693 case 'draft': 1694 $value = chr(3); 1695 break; 1696 1697 case 'normal': 1698 $value = chr(4); 1699 break; 1700 1701 case 'high': 1702 $value = chr(5); 1703 break; 1704 } 1705 break; 1706 1707 case "finishing": 1708 switch ($value) 1709 { 1710 case 'none': 1711 $value = chr(3); 1712 break; 1713 1714 case 'staple': 1715 $value = chr(4); 1716 break; 1717 1718 case 'punch': 1719 $value = chr(5); 1720 break; 1721 1722 case 'cover': 1723 $value = chr(6); 1724 break; 1725 1726 case 'bind': 1727 $value = chr(7); 1728 break; 1729 1730 case 'saddle-stitch': 1731 $value = chr(8); 1732 break; 1733 1734 case 'edge-stitch': 1735 $value = chr(9); 1736 break; 1737 1738 case 'staple-top-left': 1739 $value = chr(20); 1740 break; 1741 1742 case 'staple-bottom-left': 1743 $value = chr(21); 1744 break; 1745 1746 case 'staple-top-right': 1747 $value = chr(22); 1748 break; 1749 1750 case 'staple-bottom-right': 1751 $value = chr(23); 1752 break; 1753 1754 case 'edge-stitch-left': 1755 $value = chr(24); 1756 break; 1757 1758 case 'edge-stitch-top': 1759 $value = chr(25); 1760 break; 1761 1762 case 'edge-stitch-right': 1763 $value = chr(26); 1764 break; 1765 1766 case 'edge-stitch-bottom': 1767 $value = chr(27); 1768 break; 1769 1770 case 'staple-dual-left': 1771 $value = chr(28); 1772 break; 1773 1774 case 'staple-dual-top': 1775 $value = chr(29); 1776 break; 1777 1778 case 'staple-dual-right': 1779 $value = chr(30); 1780 break; 1781 1782 case 'staple-dual-bottom': 1783 $value = chr(31); 1784 break; 1785 } 1786 break; 1787 } 1788 $prepend = ''; 1789 while ((strlen($value) + strlen($prepend)) < 4) 1790 { 1791 $prepend .= chr(0); 1792 } 1793 return $prepend . $value; 1794 } 1795 1796 protected function _integerBuild($value) 1797 { 1798 if ($value >= 2147483647 || $value < - 2147483648) 1799 { 1800 trigger_error( 1801 _("Values must be between -2147483648 and 2147483647: assuming '0'") , E_USER_WARNING); 1802 return chr(0x00) . chr(0x00) . chr(0x00) . chr(0x00); 1803 } 1804 $initial_value = $value; 1805 $int1 = $value & 0xFF; 1806 $value -= $int1; 1807 $value = $value >> 8; 1808 $int2 = $value & 0xFF; 1809 $value-= $int2; 1810 $value = $value >> 8; 1811 $int3 = $value & 0xFF; 1812 $value-= $int3; 1813 $value = $value >> 8; 1814 $int4 = $value & 0xFF; //64bits 1815 if ($initial_value < 0) { 1816 $int4 = chr($int4) | chr(0x80); 1817 } 1818 else { 1819 $int4 = chr($int4); 1820 } 1821 $value = $int4 . chr($int3) . chr($int2) . chr($int1); 1822 return $value; 1823 } 1824 1825 protected function _rangeOfIntegerBuild($integers) 1826 { 1827 #$integers = split(":", $integers); 1828 $integers = preg_split("#:#", $integers); 1829 for ($i = 0; $i < 2; $i++) { 1830 $outvalue[$i] = self::_integerBuild($integers[$i]); 1831 } 1832 return $outvalue[0] . $outvalue[1]; 1833 } 1834 1835 protected function _setJobAttribute($attribute, $value) 1836 { 1837 //used by setAttribute 1838 $tag_type = $this->job_tags[$attribute]['tag']; 1839 switch ($tag_type) 1840 { 1841 case 'integer': 1842 $this->job_tags[$attribute]['value'][] = self::_integerBuild($value); 1843 break; 1844 1845 case 'boolean': 1846 case 'nameWithoutLanguage': 1847 case 'nameWithLanguage': 1848 case 'textWithoutLanguage': 1849 case 'textWithLanguage': 1850 case 'keyword': 1851 case 'naturalLanguage': 1852 $this->job_tags[$attribute]['value'][] = $value; 1853 break; 1854 1855 case 'enum': 1856 $value = $this->_enumBuild($attribute, $value); // may be overwritten by children 1857 $this->job_tags[$attribute]['value'][] = $value; 1858 break; 1859 1860 case 'rangeOfInteger': 1861 // $value have to be: INT1:INT2 , eg 100:1000 1862 $this->job_tags[$attribute]['value'][] = self::_rangeOfIntegerBuild($value); 1863 break; 1864 1865 case 'resolution': 1866 if (preg_match("#dpi#", $value)) { 1867 $unit = chr(0x3); 1868 } 1869 if (preg_match("#dpc#", $value)) { 1870 $unit = chr(0x4); 1871 } 1872 $search = array( 1873 "#(dpi|dpc)#", 1874 '#(x|-)#' 1875 ); 1876 $replace = array( 1877 "", 1878 ":" 1879 ); 1880 $value = self::_rangeOfIntegerBuild(preg_replace($search, $replace, $value)) . $unit; 1881 $this->job_tags[$attribute]['value'][] = $value; 1882 break; 1883 1884 default: 1885 trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , E_USER_NOTICE); 1886 self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2); 1887 self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2); 1888 return FALSE; 1889 break; 1890 } 1891 $this->job_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag']; 1892 } 1893 1894 protected function _setOperationAttribute($attribute, $value) 1895 { 1896 //used by setAttribute 1897 $tag_type = $this->operation_tags[$attribute]['tag']; 1898 switch ($tag_type) 1899 { 1900 case 'integer': 1901 $this->operation_tags[$attribute]['value'][] = self::_integerBuild($value); 1902 break; 1903 1904 case 'keyword': 1905 case 'naturalLanguage': 1906 $this->operation_tags[$attribute]['value'][] = $value; 1907 break; 1908 1909 default: 1910 trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , E_USER_NOTICE); 1911 self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2); 1912 self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2); 1913 return FALSE; 1914 break; 1915 } 1916 $this->operation_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag']; 1917 } 1918 1919 protected function _setPrinterAttribute($attribute, $value) 1920 { 1921 //used by setAttribute 1922 $tag_type = $this->printer_tags[$attribute]['tag']; 1923 switch ($tag_type) 1924 { 1925 case 'integer': 1926 $this->printer_tags[$attribute]['value'][] = self::_integerBuild($value); 1927 break; 1928 1929 case 'keyword': 1930 case 'naturalLanguage': 1931 $this->printer_tags[$attribute]['value'][] = $value; 1932 break; 1933 1934 default: 1935 trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , E_USER_NOTICE); 1936 self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2); 1937 self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute') , $attribute) , 2); 1938 return FALSE; 1939 break; 1940 } 1941 $this->printer_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag']; 1942 } 1943 1944 // 1945 // DEBUGGING 1946 // 1947 protected function _putDebug($string, $level = 1) 1948 { 1949 if ($level === false) { 1950 return; 1951 } 1952 1953 if ($level < $this->debug_level) { 1954 return; 1955 } 1956 1957 $this->debug[$this->debug_count] = substr($string, 0, 1024); 1958 $this->debug_count++; 1959 //$this->debug .= substr($string,0,1024); 1960 1961 } 1962 1963 // 1964 // LOGGING 1965 // 1966 protected function _errorLog($string_to_log, $level) 1967 { 1968 if ($level > $this->log_level) { 1969 return; 1970 } 1971 1972 $string = sprintf('%s : %s:%s user %s : %s', basename($_SERVER['PHP_SELF']) , $this->host, $this->port, $this->requesting_user, $string_to_log); 1973 1974 if ($this->log_type == 0) 1975 { 1976 error_log($string); 1977 return; 1978 } 1979 1980 $string = sprintf("%s %s Host %s:%s user %s : %s\n", date('M d H:i:s') , basename($_SERVER['PHP_SELF']) , $this->host, $this->port, $this->requesting_user, $string_to_log); 1981 error_log($string, $this->log_type, $this->log_destination); 1982 return; 1983 } 1984} 1985