Modules

Request_Client_Stream
extends Kohana_Request_Client_Stream
extends Request_Client_External
extends Kohana_Request_Client_External
extends Request_Client
extends Kohana_Request_Client

Request_Client_External Stream driver performs external requests using php sockets. To use this driver, ensure the following is completed before executing an external request- ideally in the application bootstrap.

example
// In application bootstrap Request_Client_External::$client = 'Request_Client_Stream';
package
Kohana
category
Base
author
Kohana Team
copyright
© 2008-2012 Kohana Team
license
https://kohana.top/license
uses
[PHP Streams](http://php.net/manual/en/book.stream.php)

Class declared in SYSPATH/classes/Request/Client/Stream.php on line 3.

Properties

public static string $client

defines the external client to use by default

string(19) "Request_Client_Curl"

protected Cache $_cache

Caching library for request caching

Default value:
NULL

protected int $_callback_depth

Tracks the callback depth of the currently executing request

Default value:
integer 1

protected array $_callback_params

Arbitrary parameters that are shared with header callbacks through their Request_Client object

Default value:
array(0) 

protected bool $_follow

Should redirects be followed?

Default value:
bool FALSE

protected array $_follow_headers

Headers to preserve when following a redirect

Default value:
array(1) (
    0 => string(13) "authorization"
)

protected array $_header_callbacks

Callbacks to use when response contains given headers

Default value:
array(1) (
    "Location" => string(34) "Request_Client::on_header_location"
)

protected int $_max_callback_depth

Maximum number of requests that header callbacks can trigger before the request is aborted

Default value:
integer 5

protected array $_options

curl options

Default value:
array(0) 

protected bool $_strict_redirect

Follow 302 redirect with original request method?

Default value:
bool TRUE

Methods

public _send_message( Request $request , Response $response ) (defined in Kohana_Request_Client_Stream)

Sends the HTTP message Request to a remote server and processes the response.

Parameters

  • Request $request required - Request to send
  • Response $response required - $request response to send

Tags

  • Uses - [PHP cURL](http://php.net/manual/en/book.curl.php)

Return Values

  • Response

Source Code

public function _send_message(Request $request, Response $response)
{
    // Calculate stream mode
    $mode = ($request->method() === HTTP_Request::GET) ? 'r' : 'r+';

    // Process cookies
    if ($cookies = $request->cookie()) {
        $request->headers('cookie', http_build_query($cookies, null, '; '));
    }

    // Get the message body
    $body = $request->body();

    if (is_resource($body)) {
        $body = stream_get_contents($body);
    }

    // Set the content length
    $request->headers('content-length', (string) strlen($body));

    list($protocol) = explode('/', $request->protocol());

    // Create the context
    $options = [
        strtolower($protocol) => [
            'method' => $request->method(),
            'header' => (string) $request->headers(),
            'content' => $body
        ]
    ];

    // Create the context stream
    $context = stream_context_create($options);

    stream_context_set_option($context, $this->_options);

    $uri = $request->uri();

    if ($query = $request->query()) {
        $uri .= '?' . http_build_query($query, null, '&');
    }

    $stream = fopen($uri, $mode, false, $context);

    $meta_data = stream_get_meta_data($stream);

    // Get the HTTP response code
    $http_response = array_shift($meta_data['wrapper_data']);

    if (preg_match_all('/(\w+\/\d\.\d) (\d{3})/', $http_response, $matches) !== false) {
        $protocol = $matches[1][0];
        $status = (int) $matches[2][0];
    } else {
        $protocol = null;
        $status = null;
    }

    // Get any exisiting response headers
    $response_header = $response->headers();

    // Process headers
    array_map([$response_header, 'parse_header_string'], [], $meta_data['wrapper_data']);

    $response->status($status)
        ->protocol($protocol)
        ->body(stream_get_contents($stream));

    // Close the stream after use
    fclose($stream);

    return $response;
}

public execute_request( Request $request , Response $response ) (defined in Kohana_Request_Client_External)

Processes the request, executing the controller action that handles this request, determined by the Route.

  1. Before the controller action is called, the Controller::before method will be called.
  2. Next the controller action will be called.
  3. After the controller action is called, the Controller::after method will be called.

By default, the output from the controller is captured and returned, and no headers are sent.

$request->execute();

Parameters

  • Request $request required - A request object
  • Response $response required - A response object

Tags

Return Values

  • Response

Source Code

public function execute_request(Request $request, Response $response)
{
    if (Kohana::$profiling) {
        // Set the benchmark name
        $benchmark = '"' . $request->uri() . '"';

        if ($request !== Request::$initial AND Request::$current) {
            // Add the parent request uri
            $benchmark .= ' « "' . Request::$current->uri() . '"';
        }

        // Start benchmarking
        $benchmark = Profiler::start('Requests', $benchmark);
    }

    // Store the current active request and replace current with new request
    $previous = Request::$current;
    Request::$current = $request;

    // Resolve the POST fields
    if ($post = $request->post()) {
        $request->body(http_build_query($post, null, '&'))
            ->headers('content-type', 'application/x-www-form-urlencoded; charset=' . Kohana::$charset);
    }

    $request->headers('content-length', (string) $request->content_length());

    // If Kohana expose, set the user-agent
    if (Kohana::$expose) {
        $request->headers('user-agent', Kohana::version());
    }

    try {
        $response = $this->_send_message($request, $response);
    } catch (Exception $e) {
        // Restore the previous request
        Request::$current = $previous;

        if (isset($benchmark)) {
            // Delete the benchmark, it is invalid
            Profiler::delete($benchmark);
        }

        // Re-throw the exception
        throw $e;
    }

    // Restore the previous request
    Request::$current = $previous;

    if (isset($benchmark)) {
        // Stop the benchmark
        Profiler::stop($benchmark);
    }

    // Return the response
    return $response;
}

public static factory( [ array $params = array(0) , string $client = NULL ] ) (defined in Kohana_Request_Client_External)

Factory method to create a new Request_Client_External object based on the client name passed, or defaulting to Request_Client_External::$client by default.

Request_Client_External::$client can be set in the application bootstrap.

Parameters

  • array $params = array(0) - Parameters to pass to the client
  • string $client = NULL - External client to use

Tags

Return Values

  • Request_Client_External

Source Code

public static function factory(array $params = [], $client = null)
{
    if ($client === null) {
        $client = Request_Client_External::$client;
    }

    $client = new $client($params);

    if (!$client instanceof Request_Client_External) {
        throw new Request_Exception('Selected client is not a Request_Client_External object.');
    }

    return $client;
}

public options( [ mixed $key = NULL , mixed $value = NULL ] ) (defined in Kohana_Request_Client_External)

Set and get options for this request.

Parameters

  • mixed $key = NULL - Option name, or array of options
  • mixed $value = NULL - Option value

Return Values

  • mixed
  • Request_Client_External

Source Code

public function options($key = null, $value = null)
{
    if ($key === null)
        return $this->_options;

    if (is_array($key)) {
        $this->_options = $key;
    } elseif ($value === null) {
        return Arr::get($this->_options, $key);
    } else {
        $this->_options[$key] = $value;
    }

    return $this;
}

public __construct( [ array $params = array(0) ] ) (defined in Kohana_Request_Client)

Creates a new Request_Client object, allows for dependency injection.

Parameters

  • array $params = array(0) - Params

Source Code

public function __construct(array $params = [])
{
    foreach ($params as $key => $value) {
        if (method_exists($this, $key)) {
            $this->$key($value);
        }
    }
}

public assign_client_properties( Request_Client $client ) (defined in Kohana_Request_Client)

Assigns the properties of the current Request_Client to another Request_Client instance - used when setting up a subsequent request.

Parameters

  • Request_Client $client required - $client

Source Code

public function assign_client_properties(Request_Client $client)
{
    $client->cache($this->cache());
    $client->follow($this->follow());
    $client->follow_headers($this->follow_headers());
    $client->header_callbacks($this->header_callbacks());
    $client->max_callback_depth($this->max_callback_depth());
    $client->callback_params($this->callback_params());
}

public cache( [ HTTP_Cache $cache = NULL ] ) (defined in Kohana_Request_Client)

Getter and setter for the internal caching engine, used to cache responses if available and valid.

Parameters

  • HTTP_Cache $cache = NULL - Engine to use for caching

Return Values

  • HTTP_Cache
  • Request_Client

Source Code

public function cache(HTTP_Cache $cache = null)
{
    if ($cache === null)
        return $this->_cache;

    $this->_cache = $cache;
    return $this;
}

public callback_depth( [ int $depth = NULL ] ) (defined in Kohana_Request_Client)

Getter/Setter for the callback depth property, which is used to track how many recursions have been executed within the current request execution.

Parameters

  • int $depth = NULL - Current recursion depth

Return Values

  • Request_Client|int

Source Code

public function callback_depth($depth = null)
{
    if ($depth === null)
        return $this->_callback_depth;

    $this->_callback_depth = $depth;

    return $this;
}

public callback_params( [ string|array $param = NULL , mixed $value = NULL ] ) (defined in Kohana_Request_Client)

Getter/Setter for the callback_params array, which allows additional application-specific parameters to be shared with callbacks.

As with other Kohana setter/getters, usage is:

// Set full array
$client->callback_params(['foo' => 'bar']);

// Set single key
$client->callback_params('foo','bar');

// Get full array
$params = $client->callback_params();

// Get single key
$foo = $client->callback_params('foo');

Parameters

  • string|array $param = NULL - $param
  • mixed $value = NULL - $value

Return Values

  • Request_Client|mixed

Source Code

public function callback_params($param = null, $value = null)
{
    // Getter for full array
    if ($param === null)
        return $this->_callback_params;

    // Setter for full array
    if (is_array($param)) {
        $this->_callback_params = $param;
        return $this;
    }
    // Getter for single value
    elseif ($value === null) {
        return Arr::get($this->_callback_params, $param);
    }
    // Setter for single value
    else {
        $this->_callback_params[$param] = $value;
        return $this;
    }
}

public execute( Request $request ) (defined in Kohana_Request_Client)

Processes the request, executing the controller action that handles this request, determined by the Route.

  1. Before the controller action is called, the Controller::before method will be called.
  2. Next the controller action will be called.
  3. After the controller action is called, the Controller::after method will be called.

By default, the output from the controller is captured and returned, and no headers are sent.

$request->execute();

Parameters

  • Request $request required - $request

Tags

Return Values

  • Response

Source Code

public function execute(Request $request)
{
    // Prevent too much recursion of header callback requests
    if ($this->callback_depth() > $this->max_callback_depth())
        throw new Request_Client_Recursion_Exception("Could not execute request to :uri - too many recursions after :depth requests", [
        ':uri' => $request->uri(),
        ':depth' => $this->callback_depth() - 1,
        ]);

    // Execute the request and pass the currently used protocol
    $orig_response = $response = Response::factory(['_protocol' => $request->protocol()]);

    if (($cache = $this->cache()) instanceof HTTP_Cache)
        return $cache->execute($this, $request, $response);

    $response = $this->execute_request($request, $response);

    // Execute response callbacks
    foreach ($this->header_callbacks() as $header => $callback) {
        if ($response->headers($header)) {
            $cb_result = call_user_func($callback, $request, $response, $this);

            if ($cb_result instanceof Request) {
                // If the callback returns a request, automatically assign client params
                $this->assign_client_properties($cb_result->client());
                $cb_result->client()->callback_depth($this->callback_depth() + 1);

                // Execute the request
                $response = $cb_result->execute();
            } elseif ($cb_result instanceof Response) {
                // Assign the returned response
                $response = $cb_result;
            }

            // If the callback has created a new response, do not process any further
            if ($response !== $orig_response)
                break;
        }
    }

    return $response;
}

public follow( [ bool $follow = NULL ] ) (defined in Kohana_Request_Client)

Getter and setter for the follow redirects setting.

Parameters

  • bool $follow = NULL - Boolean indicating if redirects should be followed

Return Values

  • bool
  • Request_Client

Source Code

public function follow($follow = null)
{
    if ($follow === null)
        return $this->_follow;

    $this->_follow = $follow;

    return $this;
}

public follow_headers( [ array $follow_headers = NULL ] ) (defined in Kohana_Request_Client)

Getter and setter for the follow redirects headers array.

Parameters

  • array $follow_headers = NULL - Array of headers to be re-used when following a Location header

Return Values

  • array
  • Request_Client

Source Code

public function follow_headers($follow_headers = null)
{
    if ($follow_headers === null)
        return $this->_follow_headers;

    $this->_follow_headers = array_map('strtolower', $follow_headers);

    return $this;
}

public header_callbacks( [ array $header_callbacks = NULL ] ) (defined in Kohana_Request_Client)

Getter and setter for the header callbacks array.

Accepts an array with HTTP response headers as keys and a PHP callback function as values. These callbacks will be triggered if a response contains the given header and can either issue a subsequent request or manipulate the response as required.

By default, the Request_Client::on_header_location callback is assigned to the Location header to support automatic redirect following.

$client->header_callbacks([
    'Location' => 'Request_Client::on_header_location',
    'WWW-Authenticate' => function($request, $response, $client) {
        return $new_response;
    }
];

Parameters

  • array $header_callbacks = NULL - Array of callbacks to trigger on presence of given headers

Return Values

  • Request_Client

Source Code

public function header_callbacks($header_callbacks = null)
{
    if ($header_callbacks === null)
        return $this->_header_callbacks;

    $this->_header_callbacks = $header_callbacks;

    return $this;
}

public max_callback_depth( [ int $depth = NULL ] ) (defined in Kohana_Request_Client)

Getter and setter for the maximum callback depth property.

This protects the main execution from recursive callback execution (eg following infinite redirects, conflicts between callbacks causing loops etc). Requests will only be allowed to nest to the level set by this param before execution is aborted with a Request_Client_Recursion_Exception.

Parameters

  • int $depth = NULL - Maximum number of callback requests to execute before aborting

Return Values

  • Request_Client|int

Source Code

public function max_callback_depth($depth = null)
{
    if ($depth === null)
        return $this->_max_callback_depth;

    $this->_max_callback_depth = $depth;

    return $this;
}

public static on_header_location( Request $request , Response $response , Request_Client $client ) (defined in Kohana_Request_Client)

The default handler for following redirects, triggered by the presence of a Location header in the response.

The client's follow property must be set true and the HTTP response status one of 201, 301, 302, 303 or 307 for the redirect to be followed.

Parameters

  • Request $request required - $request
  • Response $response required - $response
  • Request_Client $client required - $client

Source Code

public static function on_header_location(Request $request, Response $response, Request_Client $client)
{
    // Do we need to follow a Location header ?
    if ($client->follow() AND in_array($response->status(), [201, 301, 302, 303, 307])) {
        // Figure out which method to use for the follow request
        switch ($response->status()) {
            default:
            case 301:
            case 307:
                $follow_method = $request->method();
                break;
            case 201:
            case 303:
                $follow_method = Request::GET;
                break;
            case 302:
                // Cater for sites with broken HTTP redirect implementations
                if ($client->strict_redirect()) {
                    $follow_method = $request->method();
                } else {
                    $follow_method = Request::GET;
                }
                break;
        }

        // Prepare the additional request, copying any follow_headers that were present on the original request
        $orig_headers = $request->headers()->getArrayCopy();
        $follow_header_keys = array_intersect(array_keys($orig_headers), $client->follow_headers());
        $follow_headers = \Arr::extract($orig_headers, $follow_header_keys);

        $follow_request = Request::factory($response->headers('Location'))
            ->method($follow_method)
            ->headers($follow_headers);

        if ($follow_method !== Request::GET) {
            $follow_request->body($request->body());
        }

        return $follow_request;
    }

    return null;
}

public strict_redirect( [ bool $strict_redirect = NULL ] ) (defined in Kohana_Request_Client)

Getter and setter for the strict redirects setting

HTTP/1.1 specifies that a 302 redirect should be followed using the original request method. However, the vast majority of clients and servers get this wrong, with 302 widely used for 'POST - 302 redirect - GET' patterns. By default, Kohana's client is fully compliant with the HTTP spec. Some non-compliant third party sites may require that strict_redirect is set false to force the client to switch to GET following a 302 response.

Parameters

  • bool $strict_redirect = NULL - Boolean indicating if 302 redirects should be followed with the original method

Return Values

  • Request_Client

Source Code

public function strict_redirect($strict_redirect = null)
{
    if ($strict_redirect === null)
        return $this->_strict_redirect;

    $this->_strict_redirect = $strict_redirect;

    return $this;
}