Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
crazyfactory/printipp / src / HttpClass.php
Size: Mime:
<?php
namespace CrazyFactory\PrintIpp;

class HttpClass
{
    // 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)
    {
        $traceStr = '';
        $backtrace = debug_backtrace();
        foreach ($backtrace as $trace) {
            $traceStr .= sprintf("in [file: '%s'][function: '%s'][line: %s];\n",
                $trace['file'] ?? 'n/a', $trace['function'] ?? 'n/a', $trace['line'] ?? 0
            );
        }
        $msg = sprintf('%s\n%s: [errno: %s]: %s',
            $traceStr, $this->_errorToStringfunction($level), $errno, $msg);
        if ($this->with_exceptions) {
            throw new HttpException($msg, $errno);
        }
        else {
            trigger_error($msg, $level);

            return array(false, $msg);
        }
    }

    private function _errorToStringfunction($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);
    }

    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) {
            $type  = key($argument);
            $value = current($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) {
            $type  = key($argument);
            $value = current($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 = "";
        $prependi = '';
        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;
    }
}

/*
 * Local variables:
 * mode: php
 * tab-width: 2
 * c-basic-offset: 2
 * End:
 */