Skip to content

Commit

Permalink
[PHP] Only use Guzzle to send requests
Browse files Browse the repository at this point in the history
Remove deprecated code about sending requests.
  • Loading branch information
rldhont committed Dec 3, 2024
1 parent b0056cd commit fd4ad02
Showing 1 changed file with 74 additions and 236 deletions.
310 changes: 74 additions & 236 deletions lizmap/modules/lizmap/lib/Request/Proxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Lizmap\App;
use Psr\Http\Message\ResponseInterface;

class Proxy
{
Expand Down Expand Up @@ -318,171 +320,6 @@ protected static function buildHeaders($url, $options)
return array($url, $options);
}

/**
* @param string $url
* @param array $options
*
* @return array{0: string, 1: string, 2: int} Array containing data (0: string), mime type (1: string) and HTTP code (2: int)
*/
protected static function curlProxy($url, $options)
{
$services = self::getServices();
$http_code = null;

$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

// For POST, remove parameters from the URL
// and add them to the body of the request
// Also change the content type
if ($options['method'] === 'post') {
if (empty($options['body'])) {
$explode_url = explode('?', $url);
if (count($explode_url) == 2) {
// Override previous url by removing the parameters after ?
$url = $explode_url[0];

// Set the body to use POST instead of GET
$options['body'] = $explode_url[1];
$options['headers']['Content-type'] = 'application/x-www-form-urlencoded';
}
}
}
curl_setopt($ch, CURLOPT_HTTPHEADER, self::encodeHttpHeaders($options['headers']));
curl_setopt($ch, CURLOPT_URL, $url);

if ($services->requestProxyEnabled && $services->requestProxyHost != '') {
$proxy = $services->requestProxyHost;
if ($services->requestProxyPort) {
$proxy .= ':'.$services->requestProxyPort;
}
curl_setopt($ch, CURLOPT_PROXY, $proxy);
if ($services->requestProxyType) {
curl_setopt($ch, CURLOPT_PROXYTYPE, $services->requestProxyType);
}
if ($services->requestProxyNotForDomain) {
curl_setopt($ch, CURLOPT_NOPROXY, $services->requestProxyNotForDomain);
}
if ($services->requestProxyUser) {
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $services->requestProxyUser.':'.$services->requestProxyPassword);
}
}

if ($options['referer']) {
curl_setopt($ch, CURLOPT_REFERER, $options['referer']);
}
if ($options['method'] === 'post') {
curl_setopt($ch, CURLOPT_POST, 1);
if (!empty($options['body'])) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $options['body']);
}
}
$data = curl_exec($ch);
if (!$data) {
$data = '';
}
$info = curl_getinfo($ch);
$mime = $info['content_type'];
$http_code = (int) $info['http_code'];
// Optionnal debug
if ($options['debug'] and curl_errno($ch)) {
\jLog::log('--> CURL: '.json_encode($info));
}

curl_close($ch);

return array($data, $mime, $http_code);
}

/**
* @param string $url
* @param array $options
*
* @return array{0: string, 1: string, 2: int} Array containing data (0: string), mime type (1: string) and HTTP code (2: int)
*/
protected static function fileProxy($url, $options)
{
$services = self::getServices();
$http_code = null;

$urlInfo = parse_url($url);
$scheme = isset($urlInfo['scheme']) ? $urlInfo['scheme'] : 'http';

$opts = array(
'protocol_version' => '1.1',
'method' => strtoupper($options['method']),
);

if ($services->requestProxyEnabled && $services->requestProxyHost != '') {
$okproxy = true;
if ($services->requestProxyNotForDomain) {
$noProxy = preg_split('/\s*,\s*/', $services->requestProxyNotForDomain);
$host = isset($urlInfo['host']) ? $urlInfo['host'] : 'localhost';
if (in_array($host, $noProxy)) {
$okproxy = false;
}
}
if ($okproxy) {
$proxy = 'tcp://'.$services->requestProxyHost;
if ($services->requestProxyPort) {
$proxy .= ':'.$services->requestProxyPort;
}
$opts['proxy'] = $proxy;
$opts['request_fulluri'] = true;

if ($services->requestProxyUser) {
$options['headers']['Proxy-Authorization'] =
'Basic '.base64_encode($services->requestProxyUser.':'.$services->requestProxyPassword);
}
}
}
if ($options['referer']) {
$options['headers']['Referer'] = $options['referer'];
}
if ($options['method'] != 'get' && $options['body'] != '') {
$opts['content'] = $options['body'];
} else {
unset($options['headers']['Connection']);
}
$opts['header'] = self::encodeHttpHeaders($options['headers']);

$context = stream_context_create(array($scheme => $opts));
// for debug, uncomment it and uncomment the lizmap_stream_notification_callback function below
// use stream_context_set_params($context, array("notification" => "lizmap_stream_notification_callback"));

$data = file_get_contents($url, false, $context);
if (!$data) {
$data = '';
}
$mime = 'image/png';
$matches = array();
$http_code = 0;
// $http_response_header is created by file_get_contents
foreach ($http_response_header as $header) {
if (preg_match('#^Content-Type:\s+([\w/\.+]+)(;\s+charset=(\S+))?#i', $header, $matches)) {
$mime = $matches[1];
if (count($matches) > 3) {
$mime .= '; charset='.$matches[3];
}
} elseif (substr($header, 0, 5) === 'HTTP/') {
list($version, $code, $phrase) = explode(' ', $header, 3) + array('', false, '');
$http_code = (int) $code;
}
}
// optional debug
if ($options['debug'] && ($http_code >= 400)) {
\jLog::log('getRemoteData, bad response for '.$url, 'error');
\jLog::dump($opts, 'getRemoteData, bad response, options', 'error');
\jLog::dump($http_response_header, 'getRemoteData, bad response, response headers', 'error');
}

return array($data, $mime, $http_code);
}

/**
* Log if the HTTP code is a 4XX or 5XX error code.
*
Expand All @@ -500,87 +337,30 @@ protected static function logRequestIfError($httpCode, $url)
}

/**
* Get remote data from URL, with curl or internal php functions.
*
* @param string $url url of the remote data to fetch
* @param null|array|string $options list of options for the http request.
* Option items can be: "method", "referer", "proxyHttpBackend",
* "headers" (array of headers strings), "body", "debug".
* If $options is a string, this should be the proxy method
* for compatibility to old calls.
* $proxyHttpBackend: method for the proxy : 'php' or 'curl', or ''.
* by default, it is the proxy method indicated into lizmapService
* @param null|int $debug deprecated. 0 or 1 to get debug log.
* if null, it uses the method indicated into lizmapService.
* it is ignored if $options is an array.
* @param string|string[] $method deprecated. the http method.
* it is ignored if $options is an array.
*
* @return array{0: string, 1: string, 2: int} Array containing data (0: string), mime type (1: string) and HTTP code (2: int)
*/
public static function getRemoteData($url, $options = null, $debug = null, $method = 'get')
{
$options = self::buildOptions($options, $method, $debug);
list($url, $options) = self::buildHeaders($url, $options);

// check is the env variable is set
if (getenv('ECHO_OGC_ORIGINAL_REQUEST')) {
// did the request has to be echoed ?
if (self::hasEchoInBody($options['body'])) {
$content = self::getEchoFromRequest($url, $options['body']);

// We do not perform the request, but return the content previously logged
return array(
$content,
'text/json',
200,
);
}
// All requests are logged
self::logRequestToEcho($url, $options['body']);
}

// Proxy http backend : use curl or file_get_contents
if (extension_loaded('curl') && $options['proxyHttpBackend'] != 'php') {
// With curl
$curlRequest = self::curlProxy($url, $options);
self::logRequestIfError($curlRequest[2], $url);

return $curlRequest;
}
// With file_get_contents
$request = self::fileProxy($url, $options);
self::logRequestIfError($request[2], $url);

return $request;
}

/**
* Sends a request, and return the body response as a stream.
* Sends a request with Guzzle.
*
* @param string $url url of the remote data to fetch
* @param null|array $options list of options for the http request.
* Option items can be: "method", "referer", "proxyHttpBackend",
* "headers" (array of headers strings), "body", "debug".
* "headers" (array of headers strings), "body", "debug", stream.
*
* @return ProxyResponse
* @return ResponseInterface
*/
public static function getRemoteDataAsStream($url, $options = null)
protected static function sendRequest($url, $options)
{
$options = self::buildOptions($options, 'get', null);
list($url, $options) = self::buildHeaders($url, $options);

// check is the env variable is set
if (getenv('ECHO_OGC_ORIGINAL_REQUEST')) {
// did the request has to be echoed ?
if (self::hasEchoInBody($options['body'])) {
$content = self::getEchoFromRequest($url, $options['body']);
// We do not perform the request, but return the content previously logged
$stream = \GuzzleHttp\Psr7\Utils::streamFor($content);

return new ProxyResponse(
// We do not perform the request, but return the content previously logged
return new Response(
200,
'text/json',
$stream
array('Content-Type' => 'text/json'),
$content,
);
}
// All requests are logged
Expand All @@ -591,21 +371,30 @@ public static function getRemoteDataAsStream($url, $options = null)
$options['headers']['Referer'] = $options['referer'];
}

// Create Client
$client = new Client(array(
// You can set any number of default request options.
'timeout' => max(10.0, floatval(ini_get('max_execution_time')) - 5.0),
));

// Create request
$request = new Request(
$options['method'],
$url,
$options['headers'],
$options['body'],
);

$reqOptions = array(
'stream' => true,
);
// Define request options
$requestOptions = array();

// Set stream request option
$requestOptions['stream'] = false;
if (array_key_exists('stream', $options) && $options['stream'] === true) {
$requestOptions['stream'] = true;
}

// Set proxy request options
$services = self::getServices();
if ($services->requestProxyEnabled && $services->requestProxyHost != '') {
if ($services->requestProxyType == 'socks5') {
Expand All @@ -625,16 +414,65 @@ public static function getRemoteDataAsStream($url, $options = null)

$noProxy = preg_split('/\s*,\s*/', $services->requestProxyNotForDomain);

$reqOptions['proxy'] = array(
$requestOptions['proxy'] = array(
'http' => $proxy, // Use this proxy with "http"
'https' => $proxy, // Use this proxy with "https",
'no' => $noProxy, // Don't use a proxy with these
);
}

$response = $client->send($request, $reqOptions);
// Send request
$response = $client->send($request, $requestOptions);

// Log if error
self::logRequestIfError($response->getStatusCode(), $url);

return $response;
}

/**
* Sends a request, and return the body response as string.
*
* @param string $url url of the remote data to fetch
* @param null|array $options list of options for the http request.
* Option items can be: "method", "referer", "proxyHttpBackend",
* "headers" (array of headers strings), "body", "debug".
* @param null|int $debug deprecated. 0 or 1 to get debug log.
* it is ignored if $options is an array.
* @param string|string[] $method deprecated. the http method.
* it is ignored if $options is an array.
*
* @return array{0: string, 1: string, 2: int} Array containing data (0: string), mime type (1: string) and HTTP code (2: int)
*/
public static function getRemoteData($url, $options = null, $debug = null, $method = 'get')
{
$options = self::buildOptions($options, $method, $debug);
$response = self::sendRequest($url, $options);

return array(
(string) $response->getBody(),
$response->getHeader('Content-Type')[0],
$response->getStatusCode(),
);
}

/**
* Sends a request, and return the body response as a stream.
*
* @param string $url url of the remote data to fetch
* @param null|array $options list of options for the http request.
* Option items can be: "method", "referer", "proxyHttpBackend",
* "headers" (array of headers strings), "body", "debug".
*
* @return ProxyResponse
*/
public static function getRemoteDataAsStream($url, $options = null)
{
$options = self::buildOptions($options, 'get', null);
$options['stream'] = true;

$response = self::sendRequest($url, $options);

return new ProxyResponse(
$response->getStatusCode(),
$response->getHeader('Content-Type')[0],
Expand Down

0 comments on commit fd4ad02

Please sign in to comment.