Optimized requests with curl_multi

If you need to make many requests at once but feel that you don't want to regenerate or reuse the wrapper for each request, you can use the internal support for curl_multi-requests. This feature is limited to the CurlWrapper and is currently not tested through NetWrapper. However, it should be able to use the NetWrapper out of the box. However, if the curl driver isn't available and you are using the NetWrapper, this will never happen either. This is not automated, and could also break the way netcurl works if you're using this feature outside the CurlWrapper.

6.1.3 and below

In 6.1.3 and prior versions the default request syntax looks like this:

$wrapperRequest = (new CurlWrapper)->request(["url1", "url2", "url3", ...]);

For each url, you can then use this syntax to get each response from the urls:

$wrapperRequest->getParsed('url2');
// And so on.

The most important rule for those requests is that your urls has to be unique. For example, you can't repeat your request like this:

$wrapperRequest = (new CurlWrapper)->request(['url1', ['url2']);

This is caused by the fact that we use associative requests to fetch each url via the multi request.

6.1.4 and above

As of 6.1.4, the multi-requests has been extended, so each request can be configured separately. By means, if you use the above syntax, multiple requests should work mostly as it always have. The different is that the request-method now supports extended data.

Is the unittests we have an example ready for this:

Curl multi extended parameters
    /**
     * @test
     * Make multiple URL request s.
     * @throws ExceptionHandler
     * @since 6.1.4
     */
    public function basicMultiIdentical()
    {
        // First request: Custom duplicate request (configurable arrays have higher priority in test).
        $wrapperFirst = (new CurlWrapper())->request([
            [
                'url' => 'https://ipv4.netcurl.org/',
                'requestMethod' => requestMethod::METHOD_POST,
                'dataType' => dataType::NORMAL,
                'data' => [
                    'dataRequestMethod' => 'FIRST',
                ],
                'headers' => [
                    'XHeaderFirst' => 'yes',
                    'X-Real-IP' => '255.255.255.0',
                    'Client-IP' => '127.0.0.255',
                    'X-Forwarded-For' => '127.255.0.0',
                ],
                'headers_static' => [
                    'HeaderIsForever' => 'only-in-non-multi-curls',
                ],
            ],
            [
                'url' => 'https://ipv4.netcurl.org/',
                'requestMethod' => requestMethod::METHOD_POST,
                'dataType' => dataType::NORMAL,
                'data' => [
                    'dataRequestMethod' => 'SECOND',
                ],
                'headers' => [
                    'XHeaderSecond' => 'yes',
                ],
            ],
            [
                'url' => 'https://ipv4.netcurl.org/',
                'requestMethod' => requestMethod::METHOD_GET,
                'data' => [
                    'dataRequestMethod' => 'THIRD',
                ],
            ],
        ]);

        // Second request: Single URL request. No extra data.
        $wrapperSecond = (new CurlWrapper())->request([
            'https://ipv4.netcurl.org/',
            'https://ipv4.netcurl.org/',
        ]);

        $bodies = [];
        while ($parsed = $wrapperFirst->getParsed()) {
            $bodies[] = $parsed;
        }
        while ($parsed = $wrapperSecond->getParsed()) {
            $bodies[] = $parsed;
        }

        static::assertTrue(
            count($bodies) === 5 &&
            $bodies[0]->REQUEST_METHOD === 'POST' &&
            $bodies[1]->REQUEST_METHOD === 'POST' &&
            $bodies[2]->REQUEST_METHOD === 'GET' &&
            $bodies[3]->REQUEST_METHOD === 'GET' &&
            $bodies[4]->REQUEST_METHOD === 'GET' &&
            $bodies[0]->PARAMS_REQUEST->dataRequestMethod === 'FIRST'
        );
    }

As you can see in the above example, each url is extended with a non-associative for each request being made. This means that all urls also are based on indexed arrayed instead of the urls stored as keys. This opens up for partially configurable curl_multi-requests. See the list of parameters below. The multi-request here is limited in the way that most data will fall back to global settings when not set. Also, you can currently not configure SSL separately for each curl session. Nor you can't set up separate curloptions, as the handles are set deeper in the core. It is considered, but since this method has been built for a specific reason, this wasn't planned this time.

[
    'url' => 'https://your.host.name',
    'requestMethod' => requestMethod::methodType,
    'dataType' => dataType::dataType,
    'data' => ['Your_data'=>'Array']
    'headers' => [
        'X-Request-Header-Key' => 'X-Request-Header-Value',
    ],
    'auth' => [
        'username'=>'username',
        'password'=>'password',
        'type' => authenticationType
    ]
]

The syntax very much looks like how the request()-method is actually built.

Each response from each curlhandle should be fetched very much like how database-rows are fetched. This may be changed in the future, so that you can fetch everything as one big return-array.

$bodies = [];
while ($parsed = $wrapperFirst->getParsed()) {
    $bodies[] = $parsed;
}

Undocumented features

One thing that is currently untested is the user authentication in the multi requests. However, the data should work like the setAuthentication()-method usually do. In the setAuthentication()-request, we primarily requesting defaults, so by not setting authentication variables for each handle, but within the normal requests userdata will be fetched for all calls. In the below code-block we're currently demonstrating how the setAuthentication() fetches its userdata by overwriting the parent variable set, from the ConfigWrapper.

$authData = $this->getAuthentication();
if (!is_null($urlData)) {
    if (isset($urlData['auth'])) {
        $authData = $urlData['auth'];
    }
}