Current File : /var/www/vinorea/modules/ps_mbo/src/Helpers/AsyncClient.php
<?php
/**
 * Copyright since 2007 PrestaShop SA and Contributors
 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License version 3.0
 * that is bundled with this package in the file LICENSE.md.
 * It is also available through the world-wide-web at this URL:
 * https://opensource.org/licenses/AFL-3.0
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * @author    PrestaShop SA and Contributors <contact@prestashop.com>
 * @copyright Since 2007 PrestaShop SA and Contributors
 * @license   https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
 */
declare(strict_types=1);

namespace PrestaShop\Module\Mbo\Helpers;

/**
 * The purpose of this class is to provide a way to make asynchronous HTTP requests.
 * GuzzleHttp\Client::requestAsync() is not used because it does not allow "Fire and Forget" requests.
 */
class AsyncClient
{
    public const METHOD_POST = 'POST';

    public const METHOD_GET = 'GET';

    /**
     * Process an async request using the socket connection
     *
     * @param string $url
     * @param array $params
     * @param array $customHeaders
     * @param string $method
     *
     * @return bool
     */
    public static function request(string $url, array $params = [], array $customHeaders = [], string $method = self::METHOD_POST): bool
    {
        $endpointParts = parse_url($url);
        $endpointParts['path'] = $endpointParts['path'] ?? '/';
        $endpointParts['port'] = $endpointParts['port'] ?? ($endpointParts['scheme'] === 'https' ? 443 : 80);
        $socket = self::openSocket($endpointParts['host'], $endpointParts['port']);

        if (!$socket) {
            return false;
        }

        if ($method === self::METHOD_GET) {
            return self::get($endpointParts, $socket, $customHeaders);
        }

        return self::post($endpointParts, $socket, $params, $customHeaders);
    }

    private static function get(array $endpointParts, $socket, array $customHeaders = []): bool
    {
        if (!empty($endpointParts['query'])) {
            $endpointParts['path'] .= '?' . $endpointParts['query'];
        }
        $request = "GET {$endpointParts['path']} HTTP/1.1\r\n";
        $request .= "Host: {$endpointParts['host']}\r\n";
        foreach ($customHeaders as $header) {
            $request .= "{$header}\r\n";
        }
        $request .= "Content-Type: application/json\r\n\r\n";
        $request .= "Connection:Close\r\n\r\n";

        fwrite($socket, $request);
        fclose($socket);

        return true;
    }

    private static function post(array $endpointParts, $socket, array $postData = [], array $customHeaders = []): bool
    {
        $encodedPostData = http_build_query($postData, '', '&');
        $contentLength = strlen($encodedPostData);

        $request = "POST {$endpointParts['path']} HTTP/1.1\r\n";
        $request .= "Accept: application/json\r\n";
        $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $request .= "Host: {$endpointParts['host']}\r\n";
        foreach ($customHeaders as $header) {
            $request .= "{$header}\r\n";
        }
        $request .= "Content-Length: {$contentLength}\r\n\r\n";
        $request .= $encodedPostData;

        fwrite($socket, $request);
        fclose($socket);

        return true;
    }

    private static function openSocket(string $host, int $port)
    {
        try {
            return fsockopen($host, $port, $errno, $errstr, 0.1);
        } catch (\Exception $e) {
            return false;
        }
    }
}