Print IPP lib

This commit is contained in:
frederic34 2013-03-08 11:17:46 +01:00
parent ffa2c2fb58
commit 717ba46a5f
5 changed files with 6616 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,671 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
/* @(#) $Header: /sources/phpprintipp/phpprintipp/php_classes/CupsPrintIPP.php,v 1.1 2008/06/21 00:30:56 harding Exp $
*
* Class PrintIPP - Send extended IPP requests.
*
* Copyright (C) 2005-2006 Thomas HARDING
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* mailto:thomas.harding@laposte.net
* Thomas Harding, 56 rue de la bourie rouge, 45 000 ORLEANS -- FRANCE
*
*/
/*
This class is intended to implement Internet Printing Protocol on client side.
References needed to debug / add functionnalities:
- RFC 2910
- RFC 2911
- RFC 3382
- ...
- CUPS-IPP-1.1
*/
require_once("ExtendedPrintIPP.php");
class CupsPrintIPP extends ExtendedPrintIPP {
// {{{ variables declaration
public $printers_attributes;
public $defaults_attributes;
// }}}
// {{{ constructor
public function __construct() {
parent::__construct();
self::_initTags();
}
// }}}
//
// OPERATIONS
//
// {{{ cupsGetDefaults ($attributes="all")
public function cupsGetDefaults($attributes=array("all")) {
//The CUPS-Get-Default operation returns the default printer URI and attributes
$this->jobs = array_merge($this->jobs,array(""));
$this->jobs_uri = array_merge($this->jobs_uri,array(""));
$this->parsed = array();
unset($this->printer_attributes);
if (!isset($this->setup->charset))
self::setCharset('us-ascii');
if (!isset($this->setup->language))
self::setLanguage('en');
self::_setOperationId();
for($i = 0 ; $i < count($attributes) ; $i++)
if ($i == 0)
$this->meta->attributes = chr(0x44) // Keyword
. self::_giveMeStringLength('requested-attributes')
. 'requested-attributes'
. self::_giveMeStringLength($attributes[0])
. $attributes[0];
else
$this->meta->attributes .= chr(0x44) // Keyword
. chr(0x0).chr(0x0) // zero-length name
. self::_giveMeStringLength($attributes[$i])
. $attributes[$i];
$this->stringjob = chr(0x01) . chr(0x01) // IPP version 1.1
. chr(0x40). chr(0x01) // operation: cups vendor extension: get defaults
. $this->meta->operation_id // request-id
. chr(0x01) // start operation-attributes | operation-attributes-tag
. $this->meta->charset
. $this->meta->language
. $this->meta->attributes
. chr(0x03); // end operations attribute
$this->output = $this->stringjob;
self::_putDebug("Request: ".$this->output);
$post_values = array( "Content-Type" => "application/ipp",
"Data" => $this->output);
if (self::_sendHttp ($post_values,'/')) {
if(self::_parseServerOutput())
self::_parsePrinterAttributes();
}
$this->attributes = &$this->printer_attributes;
if (isset($this->printer_attributes->printer_type)) {
$printer_type = $this->printer_attributes->printer_type->_value0;
$table = self::_interpretPrinterType($printer_type);
for($i = 0 ; $i < count($table) ; $i++ ) {
$index = '_value'.$i;
$this->printer_attributes->printer_type->$index = $table[$i];
}
}
if (isset($this->serveroutput) && isset($this->serveroutput->status)) {
$this->status = array_merge($this->status,array($this->serveroutput->status));
if ($this->serveroutput->status == "successfull-ok")
self::_errorLog("getting defaults: ".$this->serveroutput->status,3);
else
self::_errorLog("getting defaults: ".$this->serveroutput->status,1);
return $this->serveroutput->status;
} else {
$this->status = array_merge($this->status,array("OPERATION FAILED"));
self::_errorLog("getting defaults : OPERATION FAILED",1);
}
return false;
}
// }}}
// {{{ cupsAcceptJobs ($printer_uri)
public function cupsAcceptJobs($printer_uri) {
//The CUPS-Get-Default operation returns the default printer URI and attributes
$this->jobs = array_merge($this->jobs,array(""));
$this->jobs_uri = array_merge($this->jobs_uri,array(""));
$this->parsed = array();
unset($this->printer_attributes);
if (!isset($this->setup->charset))
self::setCharset('us-ascii');
if (!isset($this->setup->language))
self::setLanguage('en');
self::_setOperationId();
$this->stringjob = chr(0x01) . chr(0x01) // IPP version 1.1
. chr(0x40). chr(0x08) // operation: cups vendor extension: Accept-Jobs
. $this->meta->operation_id // request-id
. chr(0x01) // start operation-attributes | operation-attributes-tag
. $this->meta->charset
. $this->meta->language
. chr(0x45) // uri
. self::_giveMeStringLength('printer-uri')
. 'printer-uri'
. self::_giveMeStringLength($printer_uri)
. $printer_uri
. chr(0x03); // end operations attribute
$this->output = $this->stringjob;
self::_putDebug("Request: ".$this->output);
$post_values = array( "Content-Type" => "application/ipp",
"Data" => $this->output);
if (self::_sendHttp ($post_values,'/admin/')) {
if(self::_parseServerOutput())
self::_parseAttributes();
}
if (isset($this->serveroutput) && isset($this->serveroutput->status)) {
$this->status = array_merge($this->status,array($this->serveroutput->status));
if ($this->serveroutput->status == "successfull-ok")
self::_errorLog("getting defaults: ".$this->serveroutput->status,3);
else
self::_errorLog("getting defaults: ".$this->serveroutput->status,1);
return $this->serveroutput->status;
} else {
$this->status = array_merge($this->status,array("OPERATION FAILED"));
self::_errorLog("getting defaults : OPERATION FAILED",1);
}
return false;
}
// }}}
// {{{ cupsRejectJobs ($printer_uri,$printer_state_message=false)
public function cupsRejectJobs($printer_uri,$printer_state_message) {
//The CUPS-Get-Default operation returns the default printer URI and attributes
$this->jobs = array_merge($this->jobs,array(""));
$this->jobs_uri = array_merge($this->jobs_uri,array(""));
$this->parsed = array();
unset($this->attributes);
if (!isset($this->setup->charset))
self::setCharset('us-ascii');
if (!isset($this->setup->language))
self::setLanguage('en');
self::_setOperationId();
$message = "";
if ($printer_state_message)
$message = chr(0x04) // start printer-attributes
. chr(0x41) // textWithoutLanguage
. self::_giveMeStringLength("printer-state-message")
. "printer-state-message"
. self::_giveMeStringLength($printer_state_message)
. $printer_state_message;
$this->stringjob = chr(0x01) . chr(0x01) // IPP version 1.1
. chr(0x40). chr(0x09) // operation: cups vendor extension: Reject-Jobs
. $this->meta->operation_id // request-id
. chr(0x01) // start operation-attributes | operation-attributes-tag
. $this->meta->charset
. $this->meta->language
. chr(0x45) // uri
. self::_giveMeStringLength('printer-uri')
. 'printer-uri'
. self::_giveMeStringLength($printer_uri)
. $printer_uri
. $message
. chr(0x03); // end operations attribute
$this->output = $this->stringjob;
self::_putDebug("Request: ".$this->output);
$post_values = array( "Content-Type" => "application/ipp",
"Data" => $this->output);
if (self::_sendHttp ($post_values,'/admin/')) {
if(self::_parseServerOutput())
self::_parseAttributes();
}
if (isset($this->serveroutput) && isset($this->serveroutput->status)) {
$this->status = array_merge($this->status,array($this->serveroutput->status));
if ($this->serveroutput->status == "successfull-ok")
self::_errorLog("getting defaults: ".$this->serveroutput->status,3);
else
self::_errorLog("getting defaults: ".$this->serveroutput->status,1);
return $this->serveroutput->status;
} else {
$this->status = array_merge($this->status,array("OPERATION FAILED"));
self::_errorLog("getting defaults : OPERATION FAILED",1);
}
return false;
}
// }}}
// {{{ getPrinters()
public function getPrinters($printer_location=false,$printer_info=false,$attributes=array()) {
if (count($attributes) == 0)
true;
$attributes=array('printer-uri-supported','printer-location','printer-info','printer-type','color-supported');
$this->jobs = array_merge($this->jobs,array(""));
$this->jobs_uri = array_merge($this->jobs_uri,array(""));
unset ($this->printers_attributes);
if (!isset($this->setup->charset))
self::setCharset('us-ascii');
if (!isset($this->setup->language))
self::setLanguage('en-us');
self::_setOperationId();
$this->meta->attributes='';
if ($printer_location)
$this->meta->attributes .= chr(0x41) // textWithoutLanguage
. self::_giveMeStringLength('printer-location')
. 'printer-location'
. self::_giveMeStringLength($printer_location)
. $printer_location;
if ($printer_info)
$this->meta->attributes .= chr(0x41) // textWithoutLanguage
. self::_giveMeStringLength('printer-info')
. 'printer-info'
. self::_giveMeStringLength($printer_info)
. $printer_info;
for($i = 0 ; $i < count($attributes) ; $i++)
if ($i == 0)
$this->meta->attributes .= chr(0x44) // Keyword
. self::_giveMeStringLength('requested-attributes')
. 'requested-attributes'
. self::_giveMeStringLength($attributes[0])
. $attributes[0];
else
$this->meta->attributes .= chr(0x44) // Keyword
. chr(0x0).chr(0x0) // zero-length name
. self::_giveMeStringLength($attributes[$i])
. $attributes[$i];
$this->stringjob = chr(0x01) . chr(0x01) // IPP version 1.1
. chr(0x40). chr(0x02) // operation: cups vendor extension: get printers
. $this->meta->operation_id // request-id
. chr(0x01) // start operation-attributes | operation-attributes-tag
. $this->meta->charset
. $this->meta->language
. $this->meta->attributes
. chr(0x03); // end operations attribute
$this->output = $this->stringjob;
$post_values = array( "Content-Type" => "application/ipp",
"Data" => $this->output);
if (self::_sendHttp ($post_values,'/')) {
if(self::_parseServerOutput())
$this->_getAvailablePrinters();
}
if (isset($this->serveroutput) && isset($this->serveroutput->status)) {
$this->status = array_merge($this->status,array($this->serveroutput->status));
if ($this->serveroutput->status == "successfull-ok")
self::_errorLog("getting printers: ".$this->serveroutput->status,3);
else
self::_errorLog("getting printers: ".$this->serveroutput->status,1);
return $this->serveroutput->status;
} else {
$this->status = array_merge($this->status,array("OPERATION FAILED"));
self::_errorLog("getting printers : OPERATION FAILED",1);
}
return false;
}
// }}}
// {{{ cupsGetPrinters ()
public function cupsGetPrinters () {
// alias for getPrinters();
self::getPrinters();
}
// }}}
// {{{ getPrinterAttributes()
public function getPrinterAttributes() {
// complete informations from parent with Cups-specific stuff
if(!$result = parent::getPrinterAttributes())
return FALSE;
if(!isset($this->printer_attributes))
return FALSE;
if (isset ($this->printer_attributes->printer_type)) {
$printer_type = $this->printer_attributes->printer_type->_value0;
$table = self::_interpretPrinterType($printer_type);
for($i = 0 ; $i < count($table) ; $i++ ) {
$index = '_value'.$i;
$this->printer_attributes->printer_type->$index = $table[$i];
}
}
return $result;
}
// }}}
//
// SETUP
//
// {{{ _initTags ()
protected function _initTags () {
// override parent with specific cups attributes
$operation_tags = array ();
$this->operation_tags = array_merge ($this->operation_tags, $operation_tags);
$job_tags = array ( "job-billing" => array("tag" => "textWithoutLanguage"),
"blackplot" => array("tag" => "boolean"),
"brightness" => array("tag" => "integer"),
"columns" => array("tag" => "integer"),
"cpi" => array("tag" => "enum"),
"fitplot" => array("tag" => "boolean"),
"gamma" => array("tag" => "integer"),
"hue" => array("tag" => "integer"),
"lpi" => array("tag" => "enum"),
"mirror" => array("tag","boolean"),
"natural-scaling" => array("tag" => "integer"),
"number-up-layout" => array("tag" => "keyword"),
"page-border" => array("tag" => "keyword"),
"page-bottom" => array("tag" => "integer"),
"page-label" => array("tag" => "textWithoutLanguage"),
"page-left" => array("tag" => "integer"),
"page-right" => array("tag" => "integer"),
"page-set" => array("tag" => "keyword"),
"page-top" => array("tag" => "integer"),
"penwidth" => array("tag" => "integer"),
"position" => array("tag" => "keyword"),
"ppi" => array("tag" => "integer"),
"prettyprint" => array("tag","boolean"),
"saturation" => array("tag" => "integer"),
"scaling" => array("tag" => "integer"),
"wrap" => array("tag","boolean"),
);
$this->job_tags = array_merge ($this->job_tags, $job_tags);
}
// }}}
//
// REQUEST BUILDING
//
// {{{ _enumBuild ($tag,$value)
protected function _enumBuild ($tag,$value) {
$value_built = parent::_enumBuild($tag,$value);
switch ($tag) {
case "cpi":
switch ($value) {
case '10':
$value_built = chr(10);
break;
case '12':
$value_built = chr(12);
break;
case '17':
$value_built = chr(17);
break;
default:
$value_built = chr(10);
}
break;
case "lpi":
switch ($value) {
case '6':
$value_built = chr(6);
break;
case '8':
$value_built = chr(8);
break;
default:
$value_built = chr(6);
}
break;
}
$prepend = '';
while ((strlen($value_built) + strlen($prepend)) < 4)
$prepend .= chr(0);
return $prepend.$value_built;
}
// }}}
//
// RESPONSE PARSING
//
// {{{ _getAvailablePrinters ()
private function _getAvailablePrinters () {
$this->available_printers = array();
$k = 0;
$this->printers_attributes = new stdClass();
for ($i = 0 ; (array_key_exists($i,$this->serveroutput->response)) ; $i ++)
if (($this->serveroutput->response[$i]['attributes']) == "printer-attributes") {
$phpname = "_printer".$k;
$this->printers_attributes->$phpname = new stdClass();
for ($j = 0 ; array_key_exists($j,$this->serveroutput->response[$i]) ; $j++) {
$value = $this->serveroutput->response[$i][$j]['value'];
$name = str_replace("-","_",$this->serveroutput->response[$i][$j]['name']);
switch ($name) {
case "printer_uri_supported":
$this->available_printers = array_merge($this->available_printers,array($value));
break;
case "printer_type":
$table = self::_interpretPrinterType($value);
$this->printers_attributes->$phpname->$name = new stdClass();
for($l = 0 ; $l < count($table) ; $l++ ) {
$index = '_value'.$l;
$this->printers_attributes->$phpname->$name->$index = $table[$l];
}
break;
case '':
break;
default:
$this->printers_attributes->$phpname->$name = $value;
break;
}
}
$k ++;
}
}
// }}}
// {{{ _getEnumVendorExtensions
protected function _getEnumVendorExtensions ($value_parsed) {
switch ($value_parsed) {
case 0x4002:
$value = 'Get-Availables-Printers';
break;
default:
$value = sprintf('Unknown(Cups extension for operations): 0x%x',$value_parsed);
break;
}
if (isset($value))
return ($value);
return sprintf('Unknown: 0x%x',$value_parsed);
}
// }}}
// {{{ _interpretPrinterType($type)
private function _interpretPrinterType($value) {
$value_parsed = 0;
for ($i = strlen($value) ; $i > 0 ; $i --)
$value_parsed += pow(256,($i - 1)) * ord($value[strlen($value) - $i]);
$type[0] = $type[1] = $type[2] = $type[3] = $type[4] = $type[5] = '';
$type[6] = $type[7] = $type[8] = $type[9] = $type[10] = '';
$type[11] = $type[12] = $type[13] = $type[14] = $type[15] = '';
$type[16] = $type[17] = $type[18] = $type[19] = '';
if ($value_parsed %2 == 1) {
$type[0] = 'printer-class';
$value_parsed -= 1;
}
if ($value_parsed %4 == 2 ) {
$type[1] = 'remote-destination';
$value_parsed -= 2;
}
if ($value_parsed %8 == 4 ) {
$type[2] = 'print-black';
$value_parsed -= 4;
}
if ($value_parsed %16 == 8 ) {
$type[3] = 'print-color';
$value_parsed -= 8;
}
if ($value_parsed %32 == 16) {
$type[4] = 'hardware-print-on-both-sides';
$value_parsed -= 16;
}
if ($value_parsed %64 == 32) {
$type[5] = 'hardware-staple-output';
$value_parsed -= 32;
}
if ($value_parsed %128 == 64) {
$type[6] = 'hardware-fast-copies';
$value_parsed -= 64;
}
if ($value_parsed %256 == 128) {
$type[7] = 'hardware-fast-copy-collation';
$value_parsed -= 128;
}
if ($value_parsed %512 == 256) {
$type[8] = 'punch-output';
$value_parsed -= 256;
}
if ($value_parsed %1024 == 512) {
$type[9] = 'cover-output';
$value_parsed -= 512;
}
if ($value_parsed %2048 == 1024) {
$type[10] = 'bind-output';
$value_parsed -= 1024;
}
if ($value_parsed %4096 == 2048) {
$type[11] = 'sort-output';
$value_parsed -= 2048;
}
if ($value_parsed %8192 == 4096) {
$type[12] = 'handle-media-up-to-US-Legal-A4';
$value_parsed -= 4096;
}
if ($value_parsed %16384 == 8192) {
$type[13] = 'handle-media-between-US-Legal-A4-and-ISO_C-A2';
$value_parsed -= 8192;
}
if ($value_parsed %32768 == 16384) {
$type[14] = 'handle-media-larger-than-ISO_C-A2';
$value_parsed -= 16384;
}
if ($value_parsed %65536 == 32768) {
$type[15] = 'handle-user-defined-media-sizes';
$value_parsed -= 32768;
}
if ($value_parsed %131072 == 65536) {
$type[16] = 'implicit-server-generated-class';
$value_parsed -= 65536;
}
if ($value_parsed %262144 == 131072) {
$type[17] = 'network-default-printer';
$value_parsed -= 131072;
}
if ($value_parsed %524288 == 262144) {
$type[18] = 'fax-device';
$value_parsed -= 262144;
}
return $type;
}
// }}}
// {{{ _interpretEnum()
protected function _interpretEnum($attribute_name,$value) {
$value_parsed = self::_interpretInteger($value);
switch ($attribute_name) {
case 'cpi':
case 'lpi':
$value = $value_parsed;
break;
default:
$value = parent::_interpretEnum($attribute_name,$value);
break;
}
return $value;
}
// }}}
};
/*
* Local variables:
* mode: php
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,615 @@
<?php
/* @(#) $Header: /sources/phpprintipp/phpprintipp/php_classes/http_class.php,v 1.7 2010/08/22 15:45:17 harding Exp $ */
/* vim: set expandtab tabstop=2 shiftwidth=2 foldmethod=marker: */
/* ====================================================================
* GNU Lesser General Public License
* Version 2.1, February 1999
*
* Class http_class - Basic http client with "Basic" and Digest/MD5
* authorization mechanism.
* handle ipv4/v6 addresses, Unix sockets, http and https
* have file streaming capability, to cope with php "memory_limit"
*
* Copyright (C) 2006,2007,2008 Thomas HARDING
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* $Id: http_class.php,v 1.7 2010/08/22 15:45:17 harding Exp $
*/
/**
* This class is intended to implement a subset of Hyper Text Transfer Protocol
* (HTTP/1.1) on client side  (currently: POST operation), with file streaming
* capability.
*
* It can perform Basic and Digest authentication.
*
* References needed to debug / add functionnalities:
* - RFC 2616
* - RFC 2617
*
*
* Class and Function List:
* Function list:
* - __construct()
* - getErrorFormatted()
* - getErrno()
* - __construct()
* - GetRequestArguments()
* - Open()
* - SendRequest()
* - ReadReplyHeaders()
* - ReadReplyBody()
* - Close()
* - _StreamRequest()
* - _ReadReply()
* - _ReadStream()
* - _BuildDigest()
* Classes list:
* - httpException extends Exception
* - http_class
*/
/***********************
*
* httpException class
*
************************/
class httpException extends Exception
{
protected $errno;
public function __construct ($msg, $errno = null)
{
parent::__construct ($msg);
$this->errno = $errno;
}
public function getErrorFormatted ()
{
return sprintf ("[http_class]: %s -- "._(" file %s, line %s"),
$this->getMessage (), $this->getFile (), $this->getLine ());
}
public function getErrno ()
{
return $this->errno;
}
}
function error2string($value)
{
$level_names = array(
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE'
);
if(defined('E_STRICT')) $level_names[E_STRICT]='E_STRICT';
$levels=array();
if(($value&E_ALL)==E_ALL)
{
$levels[]='E_ALL';
$value&=~E_ALL;
}
foreach($level_names as $level=>$name)
if(($value&$level)==$level) $levels[]=$name;
return implode(' | ',$levels);
}
/***********************
*
* class http_class
*
************************/
class http_class
{
// variables declaration
public $debug;
public $html_debug;
public $timeout = 30; // time waiting for connection, seconds
public $data_timeout = 30; // time waiting for data, milliseconds
public $data_chunk_timeout = 1; // time waiting between data chunks, millisecond
public $force_multipart_form_post;
public $username;
public $password;
public $request_headers = array ();
public $request_body = "Not a useful information";
public $status;
public $window_size = 1024; // chunk size of data
public $with_exceptions = 0; // compatibility mode for old scripts
public $port;
public $host;
private $default_port = 631;
private $headers;
private $reply_headers = array ();
private $reply_body = array ();
private $connection;
private $arguments;
private $bodystream = array ();
private $last_limit;
private $connected;
private $nc = 1;
private $user_agent = "PRINTIPP/0.81+CVS";
private $readed_bytes = 0;
public function __construct ()
{
true;
}
/*********************
*
* Public functions
*
**********************/
public function GetRequestArguments ($url, &$arguments)
{
$this->arguments = array ();
$arguments["URL"] = $this->arguments["URL"] = $url;
$arguments["RequestMethod"] = $this->arguments["RequestMethod"] = "POST";
$this->headers["Content-Length"] = 0;
$this->headers["Content-Type"] = "application/octet-stream";
$this->headers["Host"] = $this->host;
$this->headers["User-Agent"] = $this->user_agent;
//$this->headers["Expect"] = "100-continue";
}
public function Open ($arguments)
{
$this->connected = false;
$url = $arguments["URL"];
$port = $this->default_port;
#$url = split (':', $url, 2);
$url = preg_split ('#:#', $url, 2);
$transport_type = $url[0];
$unix = false;
switch ($transport_type)
{
case 'http':
$transport_type = 'tcp://';
break;
case 'https':
$transport_type = 'tls://';
break;
case 'unix':
$transport_type = 'unix://';
$port = 0;
$unix = true;
break;
default:
$transport_type = 'tcp://';
break;
}
$url = $url[1];
if (!$unix)
{
#$url = split ("/", preg_replace ("#^/{1,}#", '', $url), 2);
$url = preg_split ("#/#", preg_replace ("#^/{1,}#", '', $url), 2);
$url = $url[0];
$port = $this->port;
$error = sprintf (_("Cannot resolve url: %s"), $url);
$ip = gethostbyname ($url);
$ip = @gethostbyaddr ($ip);
if (!$ip)
{
return $this->_HttpError ($error, E_USER_WARNING);
}
if (strstr ($url, ":")) // we got an ipv6 address
if (!strstr ($url, "[")) // it is not escaped
$url = sprintf ("[%s]", $url);
}
$this->connection = @fsockopen ($transport_type.$url, $port, $errno, $errstr, $this->timeout);
$error =
sprintf (_('Unable to connect to "%s%s port %s": %s'), $transport_type,
$url, $port, $errstr);
if (!$this->connection)
{
return $this->_HttpError ($error, E_USER_WARNING);
}
$this->connected = true;
return array (true, "success");
}
public function SendRequest ($arguments)
{
$error =
sprintf (_('Streaming request failed to %s'), $arguments['RequestURI']);
$result = self::_StreamRequest ($arguments);
if (!$result[0])
{
return $this->_HttpError ($error." ".$result[1], E_USER_WARNING);
}
self::_ReadReply ();
if (!preg_match ('#http/1.1 401 unauthorized#', $this->status))
{
return array (true, "success");
}
$headers = array_keys ($this->reply_headers);
$error = _("need authentication but no mechanism provided");
if (!in_array ("www-authenticate", $headers))
{
return $this->_HttpError ($error, E_USER_WARNING);
}
#$authtype = split (' ', $this->reply_headers["www-authenticate"]);
$authtype = preg_split ('# #', $this->reply_headers["www-authenticate"]);
$authtype = strtolower ($authtype[0]);
switch ($authtype)
{
case 'basic':
$pass = base64_encode ($this->user.":".$this->password);
$arguments["Headers"]["Authorization"] = "Basic ".$pass;
break;
case 'digest':
$arguments["Headers"]["Authorization"] = self::_BuildDigest ();
break;
default:
$error =
sprintf (_("need '%s' authentication mechanism, but have not"),
$authtype[0]);
return $this->_HttpError ($error, E_USER_WARNING);
break;
}
self::Close ();
self::Open ($arguments);
$error =
sprintf (_
('Streaming request failed to %s after a try to authenticate'),
$url);
$result = self::_StreamRequest ($arguments);
if (!$result[0])
{
return $this->_HttpError ($error.": ".$result[1], E_USER_WARNING);
}
self::_ReadReply ();
return array (true, "success");
}
public function ReadReplyHeaders (&$headers)
{
$headers = $this->reply_headers;
}
public function ReadReplyBody (&$body, $chunk_size)
{
$body = substr ($this->reply_body, $this->last_limit, $chunk_size);
$this->last_limit += $chunk_size;
}
public function Close ()
{
if (!$this->connected)
return;
fclose ($this->connection);
}
/*********************
*
* Private functions
*
*********************/
private function _HttpError ($msg, $level, $errno = null)
{
$trace = '';
$backtrace = debug_backtrace;
foreach ($backtrace as $trace)
{
$trace .= sprintf ("in [file: '%s'][function: '%s'][line: %s];\n", $trace['file'], $trace['function'],$trace['line']);
}
$msg = sprintf ( '%s\n%s: [errno: %s]: %s',
$trace, error2string ($level), $errno, $msg);
if ($this->with_exceptions)
{
throw new httpException ($msg, $errno);
}
else
{
trigger_error ($msg, $level);
return array (false, $msg);
}
}
private function _streamString ($string)
{
$success = fwrite ($this->connection, $string);
if (!$success)
{
return false;
}
return true;
}
private function _StreamRequest ($arguments)
{
$this->status = false;
$this->reply_headers = array ();
$this->reply_body = "";
if (!$this->connected)
{
return _HttpError (_("not connected"), E_USER_WARNING);
}
$this->arguments = $arguments;
$content_length = 0;
foreach ($this->arguments["BodyStream"] as $argument)
{
list ($type, $value) = each ($argument);
reset ($argument);
if ($type == "Data")
{
$length = strlen ($value);
}
elseif ($type == "File")
{
if (is_readable ($value))
{
$length = filesize ($value);
}
else
{
$length = 0;
return
_HttpError (sprintf (_("%s: file is not readable"), $value),
E_USER_WARNING);
}
}
else
{
$length = 0;
return
_HttpError (sprintf
(_("%s: not a valid argument for content"), $type),
E_USER_WARNING);
}
$content_length += $length;
}
$this->request_body = sprintf (_("%s Bytes"), $content_length);
$this->headers["Content-Length"] = $content_length;
$this->arguments["Headers"] =
array_merge ($this->headers, $this->arguments["Headers"]);
if ($this->arguments["RequestMethod"] != "POST")
{
return
_HttpError (sprintf
(_("%s: method not implemented"),
$arguments["RequestMethod"]), E_USER_WARNING);
}
$string =
sprintf ("POST %s HTTP/1.1\r\n", $this->arguments["RequestURI"]);
$this->request_headers[$string] = '';
if (!$this->_streamString ($string))
{
return _HttpError (_("Error while puts POST operation"),
E_USER_WARNING);
}
foreach ($this->arguments["Headers"] as $header => $value)
{
$string = sprintf ("%s: %s\r\n", $header, $value);
$this->request_headers[$header] = $value;
if (!$this->_streamString ($string))
{
return _HttpError (_("Error while puts HTTP headers"),
E_USER_WARNING);
}
}
$string = "\r\n";
if (!$this->_streamString ($string))
{
return _HttpError (_("Error while ends HTTP headers"),
E_USER_WARNING);
}
foreach ($this->arguments["BodyStream"] as $argument)
{
list ($type, $value) = each ($argument);
reset ($argument);
if ($type == "Data")
{
$streamed_length = 0;
while ($streamed_length < strlen ($value))
{
$string = substr ($value, $streamed_length, $this->window_size);
if (!$this->_streamString ($string))
{
return _HttpError (_("error while sending body data"),
E_USER_WARNING);
}
$streamed_length += $this->window_size;
}
}
elseif ($type == "File")
{
if (is_readable ($value))
{
$file = fopen ($value, 'rb');
while (!feof ($file))
{
if (gettype ($block = @fread ($file, $this->window_size)) !=
"string")
{
return _HttpError (_("cannot read file to upload"),
E_USER_WARNING);
}
if (!$this->_streamString ($block))
{
return _HttpError (_("error while sending body data"),
E_USER_WARNING);
}
}
}
}
}
return array (true, "success");
}
private function _ReadReply ()
{
if (!$this->connected)
{
return array (false, _("not connected"));
}
$this->reply_headers = array ();
$this->reply_body = "";
$headers = array ();
$body = "";
while (!feof ($this->connection))
{
$line = fgets ($this->connection, 1024);
if (strlen (trim($line)) == 0)
break; // \r\n => end of headers
if (preg_match ('#^[[:space:]]#', $line))
{
$headers[-1] .= sprintf(' %s', trim ($line));
continue;
}
$headers[] = trim ($line);
}
$this->status = isset ($headers[0]) ? strtolower ($headers[0]) : false;
foreach ($headers as $header)
{
$header = preg_split ("#: #", $header);
$header[0] = strtolower ($header[0]);
if ($header[0] !== "www-authenticate")
{
$header[1] = isset ($header[1]) ? strtolower ($header[1]) : "";
}
if (!isset ($this->reply_headers[$header[0]]))
{
$this->reply_headers[$header[0]] = $header[1];
}
}
self::_ReadStream ();
return true;
}
private function _ReadStream ()
{
if (! array_key_exists ("content-length", $this->reply_headers))
{
stream_set_blocking($this->connection, 0);
$this->reply_body = stream_get_contents($this->connection);
return true;
}
stream_set_blocking($this->connection, 1);
$content_length = $this->reply_headers["content-length"];
$this->reply_body = stream_get_contents($this->connection,$content_length);
return true;
}
private function _BuildDigest ()
{
$auth = $this->reply_headers["www-authenticate"];
#list ($head, $auth) = split (" ", $auth, 2);
list ($head, $auth) = preg_split ("# #", $auth, 2);
#$auth = split (", ", $auth);
$auth = preg_split ("#, #", $auth);
foreach ($auth as $sheme)
{
#list ($sheme, $value) = split ('=', $sheme);
list ($sheme, $value) = preg_split ('#=#', $sheme);
$fields[$sheme] = trim (trim ($value), '"');
}
$nc = sprintf ('%x', $this->nc);
$prepend = "";
while ((strlen ($nc) + strlen ($prepend)) < 8)
$prependi .= "0";
$nc = $prepend.$nc;
$cnonce = "printipp";
$username = $this->user;
$password = $this->password;
$A1 = $username.":".$fields["realm"].":".$password;
if (array_key_exists ("algorithm", $fields))
{
$algorithm = strtolower ($fields["algorithm"]);
switch ($algorithm)
{
case "md5":
break;
case "md5-sess":
$A1 =
$username.":".$fields["realm"].":".$password.":".
$fields['nonce'].":".$cnonce;
break;
default:
return _HttpError(
sprintf (_("digest Authorization: algorithm '%s' not implemented"),
$algorithm),
E_USER_WARNING);
return false;
break;
}
}
$A2 = "POST:".$this->arguments["RequestURI"];
if (array_key_exists ("qop", $fields))
{
$qop = strtolower ($fields["qop"]);
#$qop = split (" ", $qop);
$qop = preg_split ("# #", $qop);
if (in_array ("auth", $qop))
$qop = "auth";
else
{
self::_HttpError(
sprintf (_("digest Authorization: algorithm '%s' not implemented"),
$qop),
E_USER_WARNING);
return false;
}
}
$response = md5 (md5 ($A1).":".$fields["nonce"].":".md5 ($A2));
if (isset ($qop) && ($qop == "auth"))
{
$response =
md5 (md5 ($A1).":".$fields["nonce"].":".$nc.":".$cnonce.":".$qop.
":".$A2);
}
$auth_scheme =
sprintf
('Digest username="%s", realm="%s", nonce="%s", uri="%s", response="%s"',
$username, $fields["realm"], $fields['nonce'],
$this->arguments["RequestURI"], $response);
if (isset ($algorithm))
$auth_scheme .= sprintf (', algorithm="%s"', $algorithm);
if (isset ($qop))
$auth_scheme .= sprintf (', cnonce="%s"', $cnonce);
if (array_key_exists ("opaque", $fields))
$auth_scheme .= sprintf (', opaque="%s"', $fields['opaque']);
if (isset ($qop))
$auth_scheme .= sprintf (', qop="%s"', $qop);
$auth_scheme .= sprintf (', nc=%s', $nc);
$this->nc++;
return $auth_scheme;
}
};
/*
* Local variables:
* mode: php
* tab-width: 2
* c-basic-offset: 2
* End:
*/
?>