File: /var/www/shoetique/wp-content/plugins/googleanalytics/lib/class-ga-lib-api-request.php
<?php
/**
 * API Request library.
 *
 * @package GoogleAnalytics
 */
// phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
// phpcs:disable WordPress.WP.AlternativeFunctions
// NOTE: Alternative function recommendation for curl noted! Plans to switch to google service library in backlog.
require_once 'class-ga-lib-api-request-exception.php';
/**
 * API Request Library response.
 */
class Ga_Lib_Api_Request {
	/**
	 * Instance object.
	 *
	 * @var Ga_Lib_Api_Request|null
	 */
	public static $instance = null;
	const HEADER_CONTENT_TYPE      = 'application/x-www-form-urlencoded';
	const HEADER_CONTENT_TYPE_JSON = 'Content-type: application/json';
	const HEADER_ACCEPT            = 'Accept: application/json, text/javascript, */*; q=0.01';
	const TIMEOUT                  = 5;
	const USER_AGENT               = 'googleanalytics-wordpress-plugin';
	/**
	 * Headers array.
	 *
	 * @var array
	 */
	private $headers = array();
	/**
	 * Whether to cache or not.
	 *
	 * @var bool
	 */
	private $cache = false;
	/**
	 * Appendix.
	 *
	 * @var string
	 */
	private $appendix = '';
	/**
	 * Constructor.
	 *
	 * @param bool   $cache    Whether to cache or not.
	 * @param string $appendix Appendix string.
	 */
	private function __construct( $cache = false, $appendix = '' ) {
		$this->cache    = $cache;
		$this->appendix = $appendix;
	}
	/**
	 * Returns API client instance.
	 *
	 * @param bool   $cache    Whether to cache.
	 * @param string $appendix Appendix string.
	 *
	 * @return Ga_Lib_Api_Request|null
	 */
	public static function get_instance( $cache = false, $appendix = '' ) {
		if ( null === self::$instance ) {
			self::$instance = new Ga_Lib_Api_Request( $cache, $appendix );
		}
		return self::$instance;
	}
	/**
	 * Sets request headers.
	 *
	 * @param array|mixed $headers Headers array.
	 */
	public function set_request_headers( $headers ) {
		if ( is_array( $headers ) ) {
			$this->headers = array_merge( $this->headers, $headers );
		} else {
			$this->headers[] = $headers;
		}
	}
	/**
	 * Perform HTTP request.
	 *
	 * @param string  $url            URL address.
	 * @param string  $raw_post_body  Raw Post body.
	 * @param boolean $json           Whether to append JSON content type.
	 * @param boolean $force_no_cache Whether to force not to cache response data even if cache property is set to true.
	 *
	 * @return array Response object.
	 * @throws Exception Throws exception on error.
	 */
	public function make_request( $url, $raw_post_body = null, $json = false, $force_no_cache = false ) {
		// Return cached data if exist.
		if ( false === $force_no_cache ) {
			if ( $this->cache ) {
				$wp_transient_name = Ga_Cache::get_transient_name( $url, $raw_post_body, $this->appendix );
				$cached            = Ga_Cache::get_cached_result( $wp_transient_name );
				if ( false === empty( $cache ) ) {
					if ( ! Ga_Cache::is_data_cache_outdated( $wp_transient_name, $this->appendix ) ) {
						return $cached;
					}
				}
				// Check if the next request after error is allowed.
				if ( false === Ga_Cache::is_next_request_allowed( $wp_transient_name ) ) {
					throw new Ga_Lib_Api_Client_Exception(
						__( 'There are temporary connection issues, please try again later.' )
					);
				}
			}
		}
		if ( false === function_exists( 'curl_init' ) ) {
			throw new Ga_Lib_Api_Client_Exception(
				__( 'cURL functions are not available' )
			);
		}
		// Set default headers.
		$this->set_request_headers(
			array(
				( $json ? self::HEADER_CONTENT_TYPE_JSON : self::HEADER_CONTENT_TYPE ),
				self::HEADER_ACCEPT,
			)
		);
		$ch      = curl_init( $url );
		$headers = $this->headers;
		$curl_timeout       = self::TIMEOUT;
		$php_execution_time = ini_get( 'max_execution_time' );
		if ( false === empty( $php_execution_time ) && true === is_numeric( $php_execution_time ) ) {
			if ( $php_execution_time < 36 && $php_execution_time > 9 ) {
				$curl_timeout = $php_execution_time - 5;
			} elseif ( $php_execution_time < 10 ) {
				$curl_timeout = 5;
			}
		}
		// Set the proxy configuration. The user can provide this in wp-config.php.
		if ( defined( 'WP_PROXY_HOST' ) ) {
			curl_setopt( $ch, CURLOPT_PROXY, WP_PROXY_HOST );
		}
		if ( defined( 'WP_PROXY_PORT' ) ) {
			curl_setopt( $ch, CURLOPT_PROXYPORT, WP_PROXY_PORT );
		}
		if ( defined( 'WP_PROXY_USERNAME' ) ) {
			$auth = WP_PROXY_USERNAME;
			if ( defined( 'WP_PROXY_PASSWORD' ) ) {
				$auth .= ':' . WP_PROXY_PASSWORD;
			}
			curl_setopt( $ch, CURLOPT_PROXYUSERPWD, $auth );
		}
		curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $curl_timeout );
		curl_setopt( $ch, CURLOPT_TIMEOUT, $curl_timeout );
		curl_setopt( $ch, CURLOPT_HEADER, true );
		curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, true );
		curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
		if ( false === function_exists( 'ini_get' ) || false === ini_get( 'curl.cainfo' ) ) {
			curl_setopt( $ch, CURLOPT_CAINFO, $this->get_cert_path() );
		}
		curl_setopt( $ch, CURLINFO_HEADER_OUT, true );
		curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
		curl_setopt( $ch, CURLOPT_USERAGENT, self::USER_AGENT );
		if ( defined( 'CURLOPT_IPRESOLVE' ) && defined( 'CURL_IPRESOLVE_V4' ) ) {
			curl_setopt( $ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
		}
		// POST body.
		if ( false === empty( $raw_post_body ) ) {
			curl_setopt( $ch, CURLOPT_POST, true );
			curl_setopt(
				$ch,
				CURLOPT_POSTFIELDS,
				( $json ? $raw_post_body : http_build_query( $raw_post_body, null, '&' ) )
			);
		}
		// Execute request.
		$response = curl_exec( $ch );
		$error    = curl_error( $ch );
		if ( false === empty( $error ) ) {
			$errno = curl_errno( $ch );
			curl_close( $ch );
			// Store last cache time when unsuccessful.
			if ( false === $force_no_cache && true === $this->cache ) {
				Ga_Cache::set_last_cache_time( $wp_transient_name );
				Ga_Cache::set_last_time_attempt();
			}
			throw new Ga_Lib_Api_Client_Exception( $error . ' (' . $errno . ')' );
		} else {
			$http_code   = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
			$header_size = curl_getinfo( $ch, CURLINFO_HEADER_SIZE );
			$header      = substr( $response, 0, $header_size );
			$body        = substr( $response, $header_size, strlen( $response ) );
			if ( preg_match( '/^(4|5)[0-9]{2}/', $http_code ) ) {
				throw new Ga_Lib_Api_Request_Exception(
					404 === $http_code ? sprintf(
						/* translators: %s stands for the URL. */
						__( 'Requested URL doesn\'t exists: %s', 'googleanalytics' ),
						$url
					) : $body
				);
			}
			curl_close( $ch );
			$response_data = array( $header, $body );
			// Cache result.
			if ( false === $force_no_cache ) {
				if ( true === $this->cache ) {
					Ga_Cache::set_cache( $wp_transient_name, $response_data );
				}
			}
			return $response_data;
		}
	}
}