[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\Http\Transport; 11 12 use Joomla\CMS\Factory; 13 use Joomla\CMS\Http\Response; 14 use Joomla\CMS\Http\TransportInterface; 15 use Joomla\CMS\Uri\Uri; 16 use Joomla\Http\AbstractTransport; 17 use Joomla\Http\Exception\InvalidResponseCodeException; 18 use Joomla\Uri\UriInterface; 19 use Laminas\Diactoros\Stream as StreamResponse; 20 21 // phpcs:disable PSR1.Files.SideEffects 22 \defined('JPATH_PLATFORM') or die; 23 // phpcs:enable PSR1.Files.SideEffects 24 25 /** 26 * HTTP transport class for using sockets directly. 27 * 28 * @since 1.7.3 29 */ 30 class SocketTransport extends AbstractTransport implements TransportInterface 31 { 32 /** 33 * @var array Reusable socket connections. 34 * @since 1.7.3 35 */ 36 protected $connections; 37 38 /** 39 * Send a request to the server and return a Response object with the response. 40 * 41 * @param string $method The HTTP method for sending the request. 42 * @param UriInterface $uri The URI to the resource to request. 43 * @param mixed $data Either an associative array or a string to be sent with the request. 44 * @param array $headers An array of request headers to send with the request. 45 * @param integer $timeout Read timeout in seconds. 46 * @param string $userAgent The optional user agent string to send with the request. 47 * 48 * @return Response 49 * 50 * @since 1.7.3 51 * @throws \RuntimeException 52 */ 53 public function request($method, UriInterface $uri, $data = null, array $headers = [], $timeout = null, $userAgent = null) 54 { 55 $connection = $this->connect($uri, $timeout); 56 57 // Make sure the connection is alive and valid. 58 if (\is_resource($connection)) { 59 // Make sure the connection has not timed out. 60 $meta = stream_get_meta_data($connection); 61 62 if ($meta['timed_out']) { 63 throw new \RuntimeException('Server connection timed out.'); 64 } 65 } else { 66 throw new \RuntimeException('Not connected to server.'); 67 } 68 69 // Get the request path from the URI object. 70 $path = $uri->toString(array('path', 'query')); 71 72 // If we have data to send make sure our request is setup for it. 73 if (!empty($data)) { 74 // If the data is not a scalar value encode it to be sent with the request. 75 if (!is_scalar($data)) { 76 $data = http_build_query($data); 77 } 78 79 if (!isset($headers['Content-Type'])) { 80 $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'; 81 } 82 83 // Add the relevant headers. 84 $headers['Content-Length'] = \strlen($data); 85 } 86 87 // Build the request payload. 88 $request = array(); 89 $request[] = strtoupper($method) . ' ' . ((empty($path)) ? '/' : $path) . ' HTTP/1.1'; 90 $request[] = 'Host: ' . $uri->getHost(); 91 92 // If an explicit user agent is given use it. 93 if (isset($userAgent)) { 94 $headers['User-Agent'] = $userAgent; 95 } 96 97 // If there are custom headers to send add them to the request payload. 98 if (\is_array($headers)) { 99 foreach ($headers as $k => $v) { 100 $request[] = $k . ': ' . $v; 101 } 102 } 103 104 // Set any custom transport options 105 foreach ($this->getOption('transport.socket', array()) as $value) { 106 $request[] = $value; 107 } 108 109 // If we have data to send add it to the request payload. 110 if (!empty($data)) { 111 $request[] = null; 112 $request[] = $data; 113 } 114 115 // Authentication, if needed 116 if ($this->getOption('userauth') && $this->getOption('passwordauth')) { 117 $request[] = 'Authorization: Basic ' . base64_encode($this->getOption('userauth') . ':' . $this->getOption('passwordauth')); 118 } 119 120 // Send the request to the server. 121 fwrite($connection, implode("\r\n", $request) . "\r\n\r\n"); 122 123 // Get the response data from the server. 124 $content = ''; 125 126 while (!feof($connection)) { 127 $content .= fgets($connection, 4096); 128 } 129 130 $content = $this->getResponse($content); 131 132 // Follow Http redirects 133 if ($content->code >= 301 && $content->code < 400 && isset($content->headers['Location'])) { 134 return $this->request($method, new Uri($content->headers['Location']), $data, $headers, $timeout, $userAgent); 135 } 136 137 return $content; 138 } 139 140 /** 141 * Method to get a response object from a server response. 142 * 143 * @param string $content The complete server response, including headers. 144 * 145 * @return Response 146 * 147 * @since 1.7.3 148 * @throws InvalidResponseCodeException 149 */ 150 protected function getResponse($content) 151 { 152 if (empty($content)) { 153 throw new \UnexpectedValueException('No content in response.'); 154 } 155 156 // Split the response into headers and body. 157 $response = explode("\r\n\r\n", $content, 2); 158 159 // Get the response headers as an array. 160 $headers = explode("\r\n", $response[0]); 161 162 // Set the body for the response. 163 $body = empty($response[1]) ? '' : $response[1]; 164 165 // Get the response code from the first offset of the response headers. 166 preg_match('/[0-9]{3}/', array_shift($headers), $matches); 167 $code = $matches[0]; 168 169 if (!is_numeric($code)) { 170 // No valid response code was detected. 171 throw new InvalidResponseCodeException('No HTTP response code found.'); 172 } 173 174 $statusCode = (int) $code; 175 $verifiedHeaders = $this->processHeaders($headers); 176 177 $streamInterface = new StreamResponse('php://memory', 'rw'); 178 $streamInterface->write($body); 179 180 return new Response($streamInterface, $statusCode, $verifiedHeaders); 181 } 182 183 /** 184 * Method to connect to a server and get the resource. 185 * 186 * @param UriInterface $uri The URI to connect with. 187 * @param integer $timeout Read timeout in seconds. 188 * 189 * @return resource Socket connection resource. 190 * 191 * @since 1.7.3 192 * @throws \RuntimeException 193 */ 194 protected function connect(UriInterface $uri, $timeout = null) 195 { 196 $errno = null; 197 $err = null; 198 199 // Get the host from the uri. 200 $host = ($uri->isSsl()) ? 'ssl://' . $uri->getHost() : $uri->getHost(); 201 202 // If the port is not explicitly set in the URI detect it. 203 if (!$uri->getPort()) { 204 $port = ($uri->getScheme() === 'https') ? 443 : 80; 205 } else { 206 // Use the set port. 207 $port = $uri->getPort(); 208 } 209 210 // Build the connection key for resource memory caching. 211 $key = md5($host . $port); 212 213 // If the connection already exists, use it. 214 if (!empty($this->connections[$key]) && \is_resource($this->connections[$key])) { 215 // Connection reached EOF, cannot be used anymore 216 $meta = stream_get_meta_data($this->connections[$key]); 217 218 if ($meta['eof']) { 219 if (!fclose($this->connections[$key])) { 220 throw new \RuntimeException('Cannot close connection'); 221 } 222 } elseif (!$meta['timed_out']) { 223 // Make sure the connection has not timed out. 224 return $this->connections[$key]; 225 } 226 } 227 228 if (!is_numeric($timeout)) { 229 $timeout = ini_get('default_socket_timeout'); 230 } 231 232 // Capture PHP errors 233 $php_errormsg = ''; 234 $track_errors = ini_get('track_errors'); 235 ini_set('track_errors', true); 236 237 // PHP sends a warning if the uri does not exists; we silence it and throw an exception instead. 238 // Attempt to connect to the server 239 $connection = @fsockopen($host, $port, $errno, $err, $timeout); 240 241 if (!$connection) { 242 if (!$php_errormsg) { 243 // Error but nothing from php? Create our own 244 $php_errormsg = sprintf('Could not connect to resource %s: %s (error code %d)', $uri, $err, $errno); 245 } 246 247 // Restore error tracking to give control to the exception handler 248 ini_set('track_errors', $track_errors); 249 250 throw new \RuntimeException($php_errormsg); 251 } 252 253 // Restore error tracking to what it was before. 254 ini_set('track_errors', $track_errors); 255 256 // Since the connection was successful let's store it in case we need to use it later. 257 $this->connections[$key] = $connection; 258 259 // If an explicit timeout is set, set it. 260 if (isset($timeout)) { 261 stream_set_timeout($this->connections[$key], (int) $timeout); 262 } 263 264 return $this->connections[$key]; 265 } 266 267 /** 268 * Method to check if http transport socket available for use 269 * 270 * @return boolean True if available else false 271 * 272 * @since 3.0.0 273 */ 274 public static function isSupported() 275 { 276 return \function_exists('fsockopen') && \is_callable('fsockopen') && !Factory::getApplication()->get('proxy_enable'); 277 } 278 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |