Stream.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. <?php
  2. /**
  3. * Stream driver performs external requests using php
  4. * sockets.
  5. *
  6. * This is the default driver for all external requests.
  7. *
  8. * @package KO7\Request
  9. *
  10. * @copyright (c) 2007-2016 Kohana Team
  11. * @copyright (c) since 2016 Koseven Team
  12. * @license https://koseven.dev/LICENSE
  13. *
  14. */
  15. class KO7_Request_Client_Stream extends Request_Client_External {
  16. /**
  17. * Sends the HTTP message [Request] to a remote server and processes
  18. * the response.
  19. *
  20. * @param Request $request request to send
  21. * @param Response $response response to send
  22. *
  23. * @throws Request_Exception
  24. *
  25. * @return Response
  26. */
  27. public function _send_message(Request $request, Response $response): Response
  28. {
  29. // Calculate stream mode
  30. $mode = ($request->method() === HTTP_Request::GET) ? 'r' : 'r+';
  31. // Process cookies
  32. if ($cookies = $request->cookie())
  33. {
  34. $request->headers('cookie', http_build_query($cookies, NULL, '; '));
  35. }
  36. // Get the message body
  37. $body = $request->body();
  38. // Set the content length and form-urlencoded
  39. if ($body)
  40. {
  41. $request->headers('content-length', (string)strlen($body));
  42. $request->headers('content-type', 'application/x-www-form-urlencoded');
  43. }
  44. [$protocol] = explode('/', $request->protocol());
  45. // Create the context
  46. $options = [
  47. strtolower($protocol) => [
  48. 'method' => $request->method(),
  49. 'header' => (string)$request->headers(),
  50. 'content' => $body
  51. ]
  52. ];
  53. // Create the context stream
  54. $context = stream_context_create($options);
  55. // Set options
  56. if (!empty($this->_options))
  57. {
  58. stream_context_set_option($context, $this->_options);
  59. }
  60. $uri = $request->uri();
  61. if ($query = $request->query())
  62. {
  63. $uri .= '?' . http_build_query($query, NULL, '&');
  64. }
  65. // Throws an Exception if you try to write smth. but requested stream is not write-able or unavailable
  66. try
  67. {
  68. //Suppress warning: failed to open stream: HTTP wrapper does not support writeable connections
  69. if (is_resource($context) && get_resource_type($context) === 'stream-context' && $mode === 'r+') {
  70. throw new Request_Exception('Failed to open stream: HTTP wrapper does not support writeable connections: '.$uri);
  71. }
  72. $stream = fopen($uri, $mode, FALSE, $context);
  73. }
  74. catch(Exception $e)
  75. {
  76. throw new Request_Exception($e->getMessage());
  77. }
  78. if (is_resource($stream)) {
  79. $meta_data = stream_get_meta_data($stream);
  80. // Get the HTTP response code
  81. $http_response = array_shift($meta_data['wrapper_data']);
  82. // Fetch respone protocol and status
  83. preg_match_all('/(\w+\/\d\.\d) (\d{3})/', $http_response, $matches);
  84. $protocol = $matches[1][0];
  85. $status = (int)$matches[2][0];
  86. // Get any existing response headers
  87. $response_header = $response->headers();
  88. // Process headers
  89. array_map([$response_header, 'parse_header_string'], [], $meta_data['wrapper_data']);
  90. // Build the response
  91. $response->status($status)->protocol($protocol)->body(stream_get_contents($stream));
  92. // Close the stream after use
  93. fclose($stream);
  94. return $response;
  95. } else {
  96. throw new Request_Exception('Request stream could not be opened: '.$request->method() .' '.$request->uri());
  97. }
  98. }
  99. }