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 (); $this->arguments["URL"] = $arguments["URL"] = $url; $this->arguments["RequestMethod"] = $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'), $arguments['RequestURI']); $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 $this->_HttpError(_("not connected"), E_USER_WARNING); } $this->arguments = $arguments; $content_length = 0; foreach ($this->arguments["BodyStream"] as $argument) { // list ($type, $value) = each ($argument); $type = key($argument); $value = current($argument); reset($argument); if ($type == "Data") { $length = strlen($value); } elseif ($type == "File") { if (is_readable($value)) { $length = filesize($value); } else { $length = 0; return $this->_HttpError(sprintf(_("%s: file is not readable"), $value), E_USER_WARNING); } } else { $length = 0; return $this->_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 $this->_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 $this->_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 $this->_HttpError(_("Error while puts HTTP headers"), E_USER_WARNING); } } $string = "\r\n"; if (!$this->_streamString($string)) { return $this->_HttpError(_("Error while ends HTTP headers"), E_USER_WARNING); } foreach ($this->arguments["BodyStream"] as $argument) { // list ($type, $value) = each ($argument); $type = key($argument); $value = current($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 $this->_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 $this->_HttpError(_("cannot read file to upload"), E_USER_WARNING); } if (!$this->_streamString($block)) { return $this->_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 $this->_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; } }