| Current Path : /var/www/html/tmp/install_663b780918c7a/packages/lib_noboss/util/ |
| Current File : /var/www/html/tmp/install_663b780918c7a/packages/lib_noboss/util/curl.php |
<?php
/**
* @package No Boss Extensions
* @subpackage No Boss Library
* @author No Boss Technology <contact@nobosstechnology.com>
* @copyright Copyright (C) 2024 No Boss Technology. All rights reserved.
* @license GNU Lesser General Public License version 3 or later; see <https://www.gnu.org/licenses/lgpl-3.0.en.html>
*/
\defined('_JEXEC') or die;
use Joomla\Registry\Registry;
use Joomla\CMS\Uri\Uri;
use Joomla\Http\Exception\InvalidResponseCodeException;
use Joomla\Http\Response;
use Laminas\Diactoros\Stream as StreamResponse;
// Classe para requisicoes via curl
class NoBossUtilCurl{
private static function validateCurlRequest($response, $curlErroNo, $values){
$httpCode = $response->code;
// Verifica se código de erro da curl é de "timeout".
if($curlErroNo == 28){
$values->success = 0;
$values->message = JText::_('LIB_NOBOSS_UTIL_CURL_ERROR_TIMEOUT');
}
else if($curlErroNo == 35){
$values->success = 0;
$values->message = JText::_('LIB_NOBOSS_UTIL_CURL_ERROR_SSL_ERROR_35');
}
// Verifica se código de erro da curl é relacionado ao certificado SSL (HTTPS)
else if($curlErroNo == 60 || $curlErroNo == 77){
$values->success = 0;
$values->message = JText::_('LIB_NOBOSS_UTIL_CURL_ERROR_SSL_CERTIFICATE');
}
// Valida se não teve erro 404 (não encontrado)
else if($httpCode == 404){
$values->success = 0;
$values->message = JText::_('LIB_NOBOSS_UTIL_CURL_ERROR_NOT_FOUND');
} else if ($httpCode >= 400 && $httpCode < 500) {
$values->success = 0;
$values->message = JText::sprintf('LIB_NOBOSS_UTIL_CURL_ERROR_400_RANGE', $httpCode);
}
// Valida se não teve erro entre 500 e 600 (não encontrado)
else if($httpCode >= 500 && $httpCode < 600){
$values->success = 0;
$values->message = JText::sprintf('LIB_NOBOSS_UTIL_CURL_ERROR_500_RANGE', $httpCode);
}
// Verifica se a resposta não é falsa
else if (($response == "false" || empty($response)) && empty($curlErroNo)){
$values->success = 0;
$values->message = JText::_('LIB_NOBOSS_UTIL_CURL_ERROR_FALSE_RESPONSE');
}
return $values;
}
/**
* Send a request to the server and return a HttpResponse object with the response.
*
* Funcao baseada na do Joomla, com verificacoes adicionais desenvolvidas pela No Boss (funcao original disponivel em \libraries\vendor\joomla\http\src\Transport\Curl.php)
*
* @param string $method The HTTP method for sending the request.
* @param string $uri The URI to the resource to request.
* @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.
* @param string $paramsOptions Associative array of optional parameters
* @param boolean $returnFullInfo Sould return only the body response or bject with headers, body, httpcode and curl error code
*
* @return Response
*
* @since 11.3
* @throws \RuntimeException
*/
public static function request($method, $uri, $data = null, array $headers = null, $timeout = null, $userAgent = null, $paramsOptions = null, $returnFullInfo = false) {
if($headers == null){
$headers = array();
}
// Caso a curl não exista, solta um erro
if (!function_exists('curl_init') || !is_callable('curl_init')) {
throw new \RuntimeException('Cannot use a cURL transport when curl_init() is not available.');
}
// Cria um novo registro para não gerar erro
if($paramsOptions === null) {
$paramsOptions = new Registry;
}
// Caso um useragent não tenha sido definido, define como se fodde um navegador
if($userAgent == null) {
$userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36';
}
// Cria o objeto que será retornado
$values = new stdClass();
$values->success = 1;
// Setup the cURL handle.
$ch = curl_init();
$options = array();
// Set the request method.
switch (strtoupper($method)) {
case 'GET':
$options[CURLOPT_HTTPGET] = true;
break;
case 'POST':
$options[CURLOPT_POST] = true;
break;
case 'PUT':
default:
$options[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
break;
}
// Don't wait for body when $method is HEAD
$options[CURLOPT_NOBODY] = ($method === 'HEAD');
// Initialize the certificate store
$options[CURLOPT_CAINFO] = $paramsOptions->get('curl.certpath', __DIR__ . '/cacert.pems');
// Desativa a verificação ssl
$options[CURLOPT_SSL_VERIFYPEER] = false;
$options[CURLOPT_SSL_VERIFYHOST] = false;
// If data exists let's encode it and make sure our Content-type header is set.
if (isset($data) && !empty($data)) {
// If the data is a scalar value simply add it to the cURL post fields.
if (is_scalar($data) || (isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'multipart/form-data') === 0)) {
$options[CURLOPT_POSTFIELDS] = $data;
}
// Otherwise we need to encode the value first.
else {
$options[CURLOPT_POSTFIELDS] = http_build_query($data);
}
if (!isset($headers['Content-Type'])) {
$headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
}
// Add the relevant headers.
if (is_scalar($options[CURLOPT_POSTFIELDS])) {
$headers['Content-Length'] = strlen($options[CURLOPT_POSTFIELDS]);
}
}
// Build the headers string for the request.
$headerArray = array();
if (isset($headers)) {
foreach ($headers as $key => $value) {
$headerArray[] = $key . ': ' . $value;
}
// Add the headers string into the stream context options array.
$options[CURLOPT_HTTPHEADER] = $headerArray;
}
// Curl needs the accepted encoding header as option
if (isset($headers['Accept-Encoding'])) {
$options[CURLOPT_ENCODING] = $headers['Accept-Encoding'];
}
// If an explicit timeout is given user it.
if (isset($timeout)) {
$options[CURLOPT_TIMEOUT] = (int) $timeout;
$options[CURLOPT_CONNECTTIMEOUT] = (int) $timeout;
}
// If an explicit user agent is given use it.
if (isset($userAgent)) {
$options[CURLOPT_USERAGENT] = $userAgent;
}
// Set the request URL.
$options[CURLOPT_URL] = (string) $uri;
// We want our headers. :-)
$options[CURLOPT_HEADER] = true;
// Return it... echoing it would be tacky.
$options[CURLOPT_RETURNTRANSFER] = true;
// Override the Expect header to prevent cURL from confusing itself in its own stupidity.
// Link: http://the-stickman.com/web-development/php-and-curl-disabling-100-continue-header/
$options[CURLOPT_HTTPHEADER][] = 'Expect:';
//teste para "Error connecting to the server: HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)"
//$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
// Proxy configuration
$config = \JFactory::getConfig();
if ($config->get('proxy_enable')) {
$options[CURLOPT_PROXY] = $config->get('proxy_host') . ':' . $config->get('proxy_port');
if ($user = $config->get('proxy_user')) {
$options[CURLOPT_PROXYUSERPWD] = $user . ':' . $config->get('proxy_pass');
}
}
// Set any custom transport options
foreach ($paramsOptions->get('transport.curl', array()) as $key => $value) {
$options[$key] = $value;
}
// Authentification, if needed
if ($paramsOptions->get('userauth') && $paramsOptions->get('passwordauth')) {
$options[CURLOPT_USERPWD] = $paramsOptions->get('userauth') . ':' . $paramsOptions->get('passwordauth');
$options[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC;
}
// Set the cURL options.
curl_setopt_array($ch, $options);
// Execute the request and close the connection.
$content = curl_exec($ch);
// // Check if the content is a string. If it is not, it must be an error.
// if (!is_string($content)) {
// $message = curl_error($ch);
// if (empty($message)) {
// // Error but nothing from cURL? Create our own
// $message = 'No HTTP response received';
// }
// throw new \RuntimeException($message);
// }
// Pega o numero do erro curl
$curlErroNo = curl_errno($ch);
// Get the request information.
$info = curl_getinfo($ch);
// Joomla 4
if(version_compare(JVERSION, '4', '>=')){
$response = self::getResponse_j4($content, $info);
}
// Joomla 3
else{
$response = self::getResponse_j3($content, $info);
}
// Chama o método para fazer as validações de curl
$values = self::validateCurlRequest($response, $curlErroNo, $values);
// Obtem detalhes do erro, caso exista
$detailsError = curl_error($ch);
// Foi identificado um erro e temos detalhe da funcao curl_error
if(!empty($values->message) && !empty($detailsError)){
// Concatena informacao com mensagem ja obtida
$values->message .= "<br /><br /><b>".JText::_('LIB_NOBOSS_UTIL_CURL_ERROR_MSG_FUNCTION').":</b> <br />.{$detailsError}.";
// Requisicao nao eh da url de teste: adiciona orientacao para teste direto na url
if(empty($_GET['method']) || $_GET['method'] != 'curlTest'){
// url que permite ver o erro em simulacao de teste
$urlTest = JURI::root()."?option=com_nobossajax&library=noboss.util.support&method=curlTest";
// Concatena mensagem
$values->message .= "<br /><br />".JText::_('LIB_NOBOSS_UTIL_CURL_ERROR_MSG_LINK_TEST')." <br /> <a href='{$urlTest}' target='_blank'>{$urlTest}</a>";
// Concatena url de teste
$values->message .= "";
}
}
// fecha a curl
curl_close($ch);
// Seguir manualmente os redirecionamentos se o servidor não permitir seguir o local usando curl
if ($response->code >= 301 && $response->code < 400 && isset($response->headers['Location'])) {
$redirect_uri = new Uri($response->headers['Location'][0]);
if (in_array($redirect_uri->getScheme(), array('file', 'scp'))) {
throw new \RuntimeException('Curl redirect cannot be used in file or scp requests.');
}
return self::request($method, (string) $redirect_uri, $data, $headers, $timeout, $userAgent,$paramsOptions, $returnFullInfo);
}
// Armazena a resposta para retorno
if($returnFullInfo){
$values->data = $response;
} else {
$values->data = $response->body;
}
return $values;
}
/**
* Method to get a response object from a server response.
*
* * Funcao copiada do Joomla na versao 4.2 em 30/06/23 e apenas modificada para estatica e para chamar a outra funcao processHeaders como self (funcao original disponivel em \libraries\vendor\joomla\http\src\Transport\Curl.php)
*
* @param string $content The complete server response, including headers
* as a string if the response has no errors.
* @param array $info The cURL request information.
*
* @return Response
*
* @since 1.0
* @throws InvalidResponseCodeException
*/
protected static function getResponse_j4($content, $info)
{
// Try to get header size
if (isset($info['header_size']))
{
$headerString = trim(substr($content, 0, $info['header_size']));
$headerArray = explode("\r\n\r\n", $headerString);
// Get the last set of response headers as an array.
$headers = explode("\r\n", array_pop($headerArray));
// Set the body for the response.
$body = substr($content, $info['header_size']);
}
// Fallback and try to guess header count by redirect count
else
{
// Get the number of redirects that occurred.
$redirects = $info['redirect_count'] ?? 0;
/*
* Split the response into headers and body. If cURL encountered redirects, the headers for the redirected requests will
* also be included. So we split the response into header + body + the number of redirects and only use the last two
* sections which should be the last set of headers and the actual body.
*/
$response = explode("\r\n\r\n", $content, 2 + $redirects);
// Set the body for the response.
$body = array_pop($response);
// Get the last set of response headers as an array.
$headers = explode("\r\n", array_pop($response));
}
// Get the response code from the first offset of the response headers.
preg_match('/[0-9]{3}/', array_shift($headers), $matches);
$code = \count($matches) ? $matches[0] : null;
if (!is_numeric($code))
{
// No valid response code was detected.
throw new InvalidResponseCodeException('No HTTP response code found.');
}
$statusCode = (int) $code;
$verifiedHeaders = self::processHeaders($headers);
$streamInterface = new StreamResponse('php://memory', 'rw');
$streamInterface->write($body);
return new Response($streamInterface, $statusCode, $verifiedHeaders);
}
/**
* Method to get a response object from a server response.
*
* @param string $content The complete server response, including headers
* as a string if the response has no errors.
* @param array $info The cURL request information.
*
* @return Response
*
* @since 11.3
* @throws \UnexpectedValueException
*/
protected static function getResponse_j3($content, $info) {
// Create the response object.
$return = new JHttpResponse;
// Try to get header size
if (isset($info['header_size'])) {
$headerString = trim(substr($content, 0, $info['header_size']));
$headerArray = explode("\r\n\r\n", $headerString);
// Get the last set of response headers as an array.
$headers = explode("\r\n", array_pop($headerArray));
// Set the body for the response.
$return->body = substr($content, $info['header_size']);
}
// Fallback and try to guess header count by redirect count
else {
// Get the number of redirects that occurred.
$redirects = isset($info['redirect_count']) ? $info['redirect_count'] : 0;
/*
* Split the response into headers and body. If cURL encountered redirects, the headers for the redirected requests will
* also be included. So we split the response into header + body + the number of redirects and only use the last two
* sections which should be the last set of headers and the actual body.
*/
$response = explode("\r\n\r\n", $content, 2 + $redirects);
// Set the body for the response.
$return->body = array_pop($response);
// Get the last set of response headers as an array.
$headers = explode("\r\n", array_pop($response));
}
// Get the response code from the first offset of the response headers.
preg_match('/[0-9]{3}/', array_shift($headers), $matches);
$code = count($matches) ? $matches[0] : null;
if (is_numeric($code)){
$return->code = (int) $code;
} else {
$return->code = 500;
}
// 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;
}
/**
* Processes the headers from a transport's response data.
*
* Funcao copiada do Joomla na versao 4.2 em 30/06/23 e apenas modificada para estatica(funcao original disponivel em \libraries\vendor\joomla\http\src\AbstractTransport.php)
*
* @param array $headers The headers to process.
*
* @return array
*
* @since 2.0.0
*/
protected static function processHeaders(array $headers): array
{
$verifiedHeaders = [];
// Add the response headers to the response object.
foreach ($headers as $header)
{
$pos = strpos($header, ':');
$keyName = trim(substr($header, 0, $pos));
if (!isset($verifiedHeaders[$keyName]))
{
$verifiedHeaders[$keyName] = [];
}
$verifiedHeaders[$keyName][] = trim(substr($header, ($pos + 1)));
}
return $verifiedHeaders;
}
}