JHttpTransportSocket
/** * @package Joomla.Platform * @subpackage HTTP * * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die(); /** * HTTP transport class for using sockets directly. Класс HTTP Транспорт, для непосредственного использования сокетов. * * @package Joomla.Platform * @subpackage HTTP * @since 11.3 */ class JHttpTransportSocket implements JHttpTransport { /** * @var array Reusable socket connections. Многоразовые socket соединения. * @since 11.3 */ protected $connections; /** * @var JRegistry The client options. Параметры клиента. * @since 11.3 */ protected $options; /** * Constructor. Конструктор. * * @param JRegistry &$options Client options object. Объект Параметров клиента. * * @since 11.3 * @throws RuntimeException */ public function __construct(JRegistry &$options) { if (!function_exists('fsockopen') || !is_callable('fsockopen')) { throw new RuntimeException('Cannot use a socket transport when fsockopen() is not available.'); } $this->options = $options; } /** * Send a request to the server and return a JHttpResponse object with the response. Отправить запрос серверу и возвратить объект JHttpResponse с ответом. * * @param string $method The HTTP method for sending the request. Метод HTTP для отправки запроса. * @param JUri $uri The URI to the resource to request. URI к ресурсу запроса. * @param mixed $data Either an associative array or a string to be sent with the request. Ассоциативный массив или строка, отправляемая с запросом. * @param array $headers An array of request headers to send with the request. Массив заголовков запроса для отправки с запросом. * @param integer $timeout Read timeout in seconds. Тайм-аут чтения в секундах. * @param string $userAgent The optional user agent string to send with the request. Строка юзер-агента необязательная для отправки с запросом. * * @return JHttpResponse * * @since 11.3 * @throws RuntimeException */ public function request($method, JUri $uri, $data = null, array $headers = null, $timeout = null, $userAgent = null) { $connection = $this->connect($uri, $timeout); // Make sure the connection is alive and valid. // Удостовериться, что соединение живо и допустимо. if (is_resource($connection)) { // Make sure the connection has not timed out. // Убедится, что подключение не истекло. $meta = stream_get_meta_data($connection); if ($meta['timed_out']) { throw new RuntimeException('Server connection timed out.'); } } else { throw new RuntimeException('Not connected to server.'); } // Get the request path from the URI object. // Получить путь запроса от объекта URI. $path = $uri->toString(array('path', 'query')); // If we have data to send make sure our request is setup for it. // Если у нас есть данные для отправки убедитесь, что наш запрос яустановлен в нем. if (!empty($data)) { // If the data is not a scalar value encode it to be sent with the request. // Если данные не скалярное значение кодировать его для отправки. if (!is_scalar($data)) { $data = http_build_query($data); } // Add the relevant headers. // Добавить соответствующие заголовки. $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'; $headers['Content-Length'] = strlen($data); } // Build the request payload. // Создать полезную нагрузку запроса. $request = array(); $request[] = strtoupper($method) . ' ' . ((empty($path)) ? '/' : $path) . ' HTTP/1.0'; $request[] = 'Host: ' . $uri->getHost(); // If an explicit user agent is given use it. // Если задан юзер-агент - использовать его. if (isset($userAgent)) { $headers['User-Agent'] = $userAgent; } // If there are custom headers to send add them to the request payload. // Если есть пользовательские заголовки, для отправки добавить их в полезные данные запроса. if (is_array($headers)) { foreach ($headers as $k => $v) { $request[] = $k . ': ' . $v; } } // If we have data to send add it to the request payload. // Если у нас есть данные для отправки добавить их в полезные данныхе запроса. if (!empty($data)) { $request[] = null; $request[] = $data; } // Send the request to the server. // Отправить запрос на сервер. fwrite($connection, implode("\r\n", $request) . "\r\n\r\n"); // Get the response data from the server. // Получить данные ответа от сервера. $content = ''; while (!feof($connection)) { $content .= fgets($connection, 4096); } return $this->getResponse($content); } /** * Method to get a response object from a server response. Метод для получения объекта ответа из ответа сервера. * * @param string $content The complete server response, including headers. Полный ответ сервера, включая заголовки. * * @return JHttpResponse * * @since 11.3 * @throws UnexpectedValueException */ protected function getResponse($content) { // Create the response object. // Создать объект ответа. $return = new JHttpResponse; // Split the response into headers and body. // Разделить ответ на заголовки и тело. $response = explode("\r\n\r\n", $content, 2); // Get the response headers as an array. // Получить заголовки ответа как массив. $headers = explode("\r\n", $response[0]); // Set the body for the response. // Установить тело для ответа. $return->body = $response[1]; // Get the response code from the first offset of the response headers. // Получить код ответа от первого взятого заголовка ответа. preg_match('/[0-9]{3}/', array_shift($headers), $matches); $code = $matches[0]; if (is_numeric($code)) { $return->code = (int) $code; } // No valid response code was detected. // Допустимый код ответа не был обнаружен. else { throw new UnexpectedValueException('No HTTP response code found.'); } // Add the response headers to the response object. // Добавить заголовки ответа к объекту ответа. foreach ($headers as $header) { $pos = strpos($header, ':'); $return->headers[trim(substr($header, 0, $pos))] = trim(substr($header, ($pos + 1))); } return $return; } /** * Method to connect to a server and get the resource. Метод, чтобы соединиться с сервером и получить ресурс. * * @param JUri $uri The URI to connect with. URI, соединения. * @param integer $timeout Read timeout in seconds. Тайм-аут считывания в секундах. * * @return resource Socket connection resource. Ресурс сокетного соединения. * * @since 11.3 * @throws RuntimeException */ protected function connect(JUri $uri, $timeout = null) { // Initialize variables. // Инициализация переменных. $errno = null; $err = null; // Get the host from the uri. //Получить хост из uri. $host = ($uri->isSSL()) ? 'ssl://' . $uri->getHost() : $uri->getHost(); // If the port is not explicitly set in the URI detect it. //Если порт явно не устанавлен в URI, обнаруживаем его. if (!$uri->getPort()) { $port = ($uri->getScheme() == 'https') ? 443 : 80; } // Use the set port. // Использовать заданный порт. else { $port = $uri->getPort(); } // Build the connection key for resource memory caching. // Создать ключ соединения для кэширования ресурса. $key = md5($host . $port); // If the connection already exists, use it. // Если соединение уже существует, использовать его. if (!empty($this->connections[$key]) && is_resource($this->connections[$key])) { // Make sure the connection has not timed out. // Удостовериться, что соединение не просрочено. $meta = stream_get_meta_data($this->connections[$key]); if (!$meta['timed_out']) { return $this->connections[$key]; } } // Attempt to connect to the server. //Попытайться соединиться с сервером. $connection = fsockopen($host, $port, $errno, $err, $timeout); if (!$connection) { throw new RuntimeException($err, $errno); } // Since the connection was successful let's store it in case we need to use it later. // Так как соединение было успешно, сохраним его на случай, если мы будем использовать его позже. $this->connections[$key] = $connection; // If an explicit timeout is set, set it. // Если явный тайм-аут устанавливается, установите его. if (isset($timeout)) { stream_set_timeout($this->connections[$key], (int) $timeout); } return $this->connections[$key]; } }