Implement Curl::setError() and MultiCurl::setError()

This commit is contained in:
Zach Borboa
2023-08-21 20:44:45 -07:00
parent 166ddf17e9
commit 5e5d284a9b
8 changed files with 199 additions and 5 deletions
+2
View File
@@ -278,6 +278,7 @@ Curl::setDefaultTimeout()
Curl::setDefaultUserAgent()
Curl::setDefaultXmlDecoder()
Curl::setDigestAuthentication($username, $password = '')
Curl::setError($function)
Curl::setFile($file)
Curl::setFollowLocation($follow_location = true)
Curl::setForbidReuse($forbid_reuse = true)
@@ -340,6 +341,7 @@ MultiCurl::setCookieJar($cookie_jar)
MultiCurl::setCookieString($string)
MultiCurl::setCookies($cookies)
MultiCurl::setDigestAuthentication($username, $password = '')
MultiCurl::setError($function)
MultiCurl::setFile($file)
MultiCurl::setFollowLocation($follow_location = true)
MultiCurl::setForbidReuse($forbid_reuse = true)
+44
View File
@@ -0,0 +1,44 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
use Curl\Curl;
$max_retries = 5;
$curl = new Curl();
$curl->setRetry($max_retries);
$curl->beforeSend(function ($instance) {
echo 'about to make request to ' . $instance->url . "\n";
});
$curl->error(function ($instance) {
echo 'not lucky this round' . "\n";
});
$curl->success(function ($instance) {
echo
'success!' . "\n" .
'got number ' . $instance->response->args->number . ' ' .
'after ' . $instance->attempts . ' attempt(s).' . "\n";
});
$curl->setError(function ($instance) {
$random_number = (int)$instance->response->args->number;
$lucky = $random_number === 7;
$instance->error = !$lucky;
if (!$lucky) {
$instance->setUrl('https://httpbin.org/get?number=' . random_int(0, 10));
}
});
$curl->get('https://httpbin.org/get?number=' . random_int(0, 10));
// $ php curl_set_error.php
// about to make request to https://httpbin.org/get?number=3
// about to make request to https://httpbin.org/get?number=1
// about to make request to https://httpbin.org/get?number=7
// success!
// got number 7 after 3 attempt(s).
+44
View File
@@ -0,0 +1,44 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
use Curl\MultiCurl;
$max_retries = 5;
$multi_curl = new MultiCurl();
$multi_curl->setRetry($max_retries);
$multi_curl->beforeSend(function ($instance) {
echo 'about to make request to ' . $instance->url . "\n";
});
$multi_curl->error(function ($instance) {
echo 'not lucky this round' . "\n";
});
$multi_curl->success(function ($instance) {
echo
'success!' . "\n" .
'got number ' . $instance->response->args->number . ' ' .
'after ' . $instance->attempts . ' attempt(s).' . "\n";
});
$multi_curl->setError(function ($instance) {
$random_number = (int)$instance->response->args->number;
$lucky = $random_number === 7;
$instance->error = !$lucky;
if (!$lucky) {
$instance->setUrl('https://httpbin.org/get?number=' . random_int(0, 10));
}
});
$multi_curl->addGet('https://httpbin.org/get?number=' . random_int(0, 10));
$multi_curl->start();
// $ php multi_curl_set_error.php
// about to make request to https://httpbin.org/get?number=4
// about to make request to https://httpbin.org/get?number=7
// success!
// got number 7 after 2 attempt(s).
+22
View File
@@ -7,6 +7,7 @@ namespace Curl;
abstract class BaseCurl
{
public $beforeSendCallback = null;
public $errorDecider = null;
public $successCallback = null;
public $errorCallback = null;
public $completeCallback = null;
@@ -138,6 +139,27 @@ abstract class BaseCurl
$this->setOpt(CURLOPT_USERPWD, $username . ':' . $password);
}
/**
* Set Error
*
* Use this function to override the default implemention for determining
* whether or not the request errored. The instance is passed as the first
* argument to the function and the instance has attributes like
* $instance->httpStatusCode and $instance->response to help decide if the
* request errored. Set $instance->error to true or false within the
* function.
*
* When $instance->error is true indicating a request error, the error
* callback set by Curl::error() is called. When $instance->error is false,
* the success callback set by Curl::success() is called.
*
* @param $function callable
*/
public function setError($function)
{
$this->errorDecider = $function;
}
/**
* Set File
*
+18 -5
View File
@@ -526,11 +526,6 @@ class Curl extends BaseCurl
$this->curlErrorMessage = $curl_error_message;
}
$this->httpStatusCode = $this->getInfo(CURLINFO_HTTP_CODE);
$this->httpError = in_array((int) floor($this->httpStatusCode / 100), [4, 5], true);
$this->error = $this->curlError || $this->httpError;
$this->errorCode = $this->error ? ($this->curlError ? $this->curlErrorCode : $this->httpStatusCode) : 0;
// NOTE: CURLINFO_HEADER_OUT set to true is required for requestHeaders
// to not be empty (e.g. $curl->setOpt(CURLINFO_HEADER_OUT, true);).
if ($this->getOpt(CURLINFO_HEADER_OUT) === true) {
@@ -539,6 +534,24 @@ class Curl extends BaseCurl
$this->responseHeaders = $this->parseResponseHeaders($this->rawResponseHeaders);
$this->response = $this->parseResponse($this->responseHeaders, $this->rawResponse);
$this->httpStatusCode = $this->getInfo(CURLINFO_HTTP_CODE);
$this->httpError = in_array((int) floor($this->httpStatusCode / 100), [4, 5], true);
if ($this->errorDecider === null) {
$this->error = $this->curlError || $this->httpError;
} else {
$this->error = null;
$this->call($this->errorDecider);
if (!in_array($this->error, [true, false], true)) {
trigger_error(
'$instance->error MUST be set to true or false inside the setError() function',
E_USER_WARNING
);
}
}
$this->errorCode = $this->error ? ($this->curlError ? $this->curlErrorCode : $this->httpStatusCode) : 0;
$this->httpErrorMessage = '';
if ($this->error) {
if (isset($this->responseHeaders['Status-Line'])) {
+3
View File
@@ -844,6 +844,9 @@ class MultiCurl extends BaseCurl
if ($curl->beforeSendCallback === null) {
$curl->beforeSend($this->beforeSendCallback);
}
if ($curl->errorDecider === null) {
$curl->setError($this->errorDecider);
}
if ($curl->successCallback === null) {
$curl->success($this->successCallback);
}
+31
View File
@@ -4920,4 +4920,35 @@ class PHPCurlClassTest extends \PHPUnit\Framework\TestCase
$this->assertEquals('foo', $test->curl->response->{'abc'});
$this->assertEquals('bar', $test->curl->response->{'123'});
}
public function testSetErrorAttemptCount()
{
$test = new Test();
$test->curl->setRetry(10);
$test->curl->setError(function ($instance) {
if ($instance->attempts < 5) {
$instance->error = true;
} else {
$instance->error = false;
}
});
$test->server('json_response', 'GET');
$this->assertEquals(5, $test->curl->attempts);
$this->assertEquals(4, $test->curl->retries);
$this->assertFalse($test->curl->error);
}
public function testSetErrorResponseMessage()
{
$test = new Test();
$test->curl->setOpt(CURLOPT_COOKIEJAR, '/dev/null');
$test->curl->setRetry(5);
$test->curl->setError(function ($instance) {
$instance->error = $instance->response->message !== '202 Accepted';
});
$test->server('retry', 'GET', ['failures' => 3]);
$this->assertEquals(4, $test->curl->attempts);
$this->assertEquals(3, $test->curl->retries);
$this->assertFalse($test->curl->error);
}
}
@@ -5452,4 +5452,39 @@ class PHPMultiCurlClassTest extends \PHPUnit\Framework\TestCase
$this->assertEquals(5, $instance->retries);
$this->assertFalse($instance->error);
}
public function testSetErrorAttemptCount()
{
$multi_curl = new MultiCurl();
$multi_curl->setRetry(10);
$multi_curl->setError(function ($instance) {
if ($instance->attempts < 5) {
$instance->error = true;
} else {
$instance->error = false;
}
});
$multi_curl->setHeader('X-DEBUG-TEST', 'json_response');
$instance = $multi_curl->addGet(Test::TEST_URL);
$multi_curl->start();
$this->assertEquals(5, $instance->attempts);
$this->assertEquals(4, $instance->retries);
$this->assertFalse($instance->error);
}
public function testSetErrorResponseMessage()
{
$multi_curl = new MultiCurl();
$multi_curl->setOpt(CURLOPT_COOKIEJAR, '/dev/null');
$multi_curl->setRetry(5);
$multi_curl->setError(function ($instance) {
$instance->error = $instance->response->message !== '202 Accepted';
});
$multi_curl->setHeader('X-DEBUG-TEST', 'retry');
$instance = $multi_curl->addGet(Test::TEST_URL, ['failures' => 3]);
$multi_curl->start();
$this->assertEquals(4, $instance->attempts);
$this->assertEquals(3, $instance->retries);
$this->assertFalse($instance->error);
}
}