Skip to content
22 changes: 22 additions & 0 deletions ext/curl/tests/curl_curlfile_seek.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
curl seek within uploaded file
--EXTENSIONS--
curl
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();

$url = "{$host}/get.inc?test=redirect&target=file";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'file' => new CURLFile(__DIR__ . '/curl_testdata1.txt')
]);
curl_exec($ch);

?>
--EXPECT--
curl_testdata1.txt|application/octet-stream|6
110 changes: 110 additions & 0 deletions ext/curl/tests/curl_errors.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
--TEST--
curl error constants
--EXTENSIONS--
curl
--FILE--
<?php

$errors = [
"CURLE_OK",
"CURLE_UNSUPPORTED_PROTOCOL",
"CURLE_FAILED_INIT",
"CURLE_URL_MALFORMAT",
"CURLE_COULDNT_RESOLVE_PROXY",
"CURLE_COULDNT_RESOLVE_HOST",
"CURLE_COULDNT_CONNECT",
"CURLE_WEIRD_SERVER_REPLY",
"CURLE_FTP_WEIRD_PASS_REPLY",
"CURLE_FTP_WEIRD_PASV_REPLY",
"CURLE_FTP_WEIRD_227_FORMAT",
"CURLE_FTP_CANT_GET_HOST",
"CURLE_PARTIAL_FILE",
"CURLE_FTP_COULDNT_RETR_FILE",
"CURLE_HTTP_RETURNED_ERROR",
"CURLE_WRITE_ERROR",
"CURLE_READ_ERROR",
"CURLE_OUT_OF_MEMORY",
"CURLE_OUT_OF_MEMORY",
"CURLE_OPERATION_TIMEDOUT",
"CURLE_FTP_PORT_FAILED",
"CURLE_FTP_COULDNT_USE_REST",
"CURLE_HTTP_POST_ERROR",
"CURLE_SSL_CONNECT_ERROR",
"CURLE_BAD_DOWNLOAD_RESUME",
"CURLE_FILE_COULDNT_READ_FILE",
"CURLE_LDAP_CANNOT_BIND",
"CURLE_LDAP_SEARCH_FAILED",
"CURLE_FUNCTION_NOT_FOUND",
"CURLE_ABORTED_BY_CALLBACK",
"CURLE_BAD_FUNCTION_ARGUMENT",
"CURLE_TOO_MANY_REDIRECTS",
"CURLE_TELNET_OPTION_SYNTAX",
"CURLE_GOT_NOTHING",
"CURLE_SSL_ENGINE_NOTFOUND",
"CURLE_SSL_ENGINE_SETFAILED",
"CURLE_SEND_ERROR",
"CURLE_RECV_ERROR",
"CURLE_SSL_CERTPROBLEM",
"CURLE_SSL_CIPHER",
"CURLE_SSL_CACERT",
"CURLE_BAD_CONTENT_ENCODING",
"CURLE_LDAP_INVALID_URL",
"CURLE_FILESIZE_EXCEEDED",
"CURLE_SSL_CACERT_BADFILE",
"CURLE_SSH",
"CURLE_SSL_PINNEDPUBKEYNOTMATCH",
];

foreach ($errors as $error) {
$value = defined($error) ? constant($error) : 'undefined';
echo $error, '=', $value, "\n";
}

--EXPECT--
CURLE_OK=0
CURLE_UNSUPPORTED_PROTOCOL=1
CURLE_FAILED_INIT=2
CURLE_URL_MALFORMAT=3
CURLE_COULDNT_RESOLVE_PROXY=5
CURLE_COULDNT_RESOLVE_HOST=6
CURLE_COULDNT_CONNECT=7
CURLE_WEIRD_SERVER_REPLY=8
CURLE_FTP_WEIRD_PASS_REPLY=11
CURLE_FTP_WEIRD_PASV_REPLY=13
CURLE_FTP_WEIRD_227_FORMAT=14
CURLE_FTP_CANT_GET_HOST=15
CURLE_PARTIAL_FILE=18
CURLE_FTP_COULDNT_RETR_FILE=19
CURLE_HTTP_RETURNED_ERROR=22
CURLE_WRITE_ERROR=23
CURLE_READ_ERROR=26
CURLE_OUT_OF_MEMORY=27
CURLE_OUT_OF_MEMORY=27
CURLE_OPERATION_TIMEDOUT=28
CURLE_FTP_PORT_FAILED=30
CURLE_FTP_COULDNT_USE_REST=31
CURLE_HTTP_POST_ERROR=34
CURLE_SSL_CONNECT_ERROR=35
CURLE_BAD_DOWNLOAD_RESUME=36
CURLE_FILE_COULDNT_READ_FILE=37
CURLE_LDAP_CANNOT_BIND=38
CURLE_LDAP_SEARCH_FAILED=39
CURLE_FUNCTION_NOT_FOUND=41
CURLE_ABORTED_BY_CALLBACK=42
CURLE_BAD_FUNCTION_ARGUMENT=43
CURLE_TOO_MANY_REDIRECTS=47
CURLE_TELNET_OPTION_SYNTAX=49
CURLE_GOT_NOTHING=52
CURLE_SSL_ENGINE_NOTFOUND=53
CURLE_SSL_ENGINE_SETFAILED=54
CURLE_SEND_ERROR=55
CURLE_RECV_ERROR=56
CURLE_SSL_CERTPROBLEM=58
CURLE_SSL_CIPHER=59
CURLE_SSL_CACERT=60
CURLE_BAD_CONTENT_ENCODING=61
CURLE_LDAP_INVALID_URL=62
CURLE_FILESIZE_EXCEEDED=63
CURLE_SSL_CACERT_BADFILE=77
CURLE_SSH=79
CURLE_SSL_PINNEDPUBKEYNOTMATCH=90
26 changes: 26 additions & 0 deletions ext/curl/tests/curl_getinfo_CURLINFO_CERTINFO.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
curl_getinfo - CURLINFO_CERTINFO
--EXTENSIONS--
curl
--SKIPIF--
<?php
include 'skipif-nocaddy.inc';
?>
--FILE--
<?php

$ch = curl_init("https://localhost/ping");
curl_setopt($ch, CURLOPT_CERTINFO, 1);
curl_exec($ch);
echo "\n";

$certinfo = curl_getinfo($ch, CURLINFO_CERTINFO);

var_dump(empty($certinfo));
var_dump(str_starts_with($certinfo[0]['Cert'], '-----BEGIN CERTIFICATE-----'));

?>
--EXPECT--
pong
bool(false)
bool(true)
42 changes: 42 additions & 0 deletions ext/curl/tests/curl_getinfo_CURLINFO_HEADER_OUT.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
curl_getinfo CURLINFO_HEADER_OUT
--DESCRIPTION--
Verify that CURLINFO_HEADER_OUT returns the request header sent on the
last request, and that toggling it back to 0 returns FALSE.
--EXTENSIONS--
curl
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();

$ch = curl_init("{$host}/get.inc?test=method");
curl_setopt($ch, CURLINFO_HEADER_OUT, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Request-num: 1']);
curl_exec($ch);

// The header string contains the full request header line(s).
$headers = rtrim(curl_getinfo($ch, CURLINFO_HEADER_OUT));
echo "With CURLINFO_HEADER_OUT=1:\n";
echo $headers, "\n---\n";

// Toggling back to 0 should clear the buffer; next getinfo returns false.
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Request-num: 2']);
curl_setopt($ch, CURLINFO_HEADER_OUT, 0);
curl_exec($ch);

$headers = curl_getinfo($ch, CURLINFO_HEADER_OUT);
echo "With CURLINFO_HEADER_OUT=0:\n";
var_dump($headers);

?>
--EXPECTF--
With CURLINFO_HEADER_OUT=1:
GET /get.inc?test=method HTTP/1.1
Host: localhost:%d
%s
Request-num: 1
---
With CURLINFO_HEADER_OUT=0:
bool(false)
41 changes: 41 additions & 0 deletions ext/curl/tests/curl_setopt_CURLOPT_FNMATCH_FUNCTION.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
Curl option CURLOPT_FNMATCH_FUNCTION
--EXTENSIONS--
curl
--SKIPIF--
<?php
if (getenv('SKIP_ONLINE_TESTS')) die('skip Online test');
?>
--FILE--
<?php

$seen_patterns = [];
$seen_fnames = [];

function fnmatch_function($ch, string $pattern, string $fname) {
global $seen_patterns, $seen_fnames;

$seen_patterns[] = $pattern;
$seen_fnames[] = $fname;

if ($fname === 'README.mirrors.txt') {
return CURL_FNMATCHFUNC_MATCH;
} else {
return CURL_FNMATCHFUNC_NOMATCH;
}
}

$ch = curl_init('ftp://debian.snt.utwente.nl/debian/README.*');
curl_setopt($ch, CURLOPT_FNMATCH_FUNCTION, 'fnmatch_function');
curl_setopt($ch, CURLOPT_WILDCARDMATCH, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
echo curl_exec($ch);

var_dump(in_array('README.*', $seen_patterns));
var_dump(in_array('README.html', $seen_fnames));

?>
--EXPECT--
The list of Debian mirror sites is available here: https://www.debian.org/mirror/list
Comment on lines +32 to +39

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
echo curl_exec($ch);
var_dump(in_array('README.*', $seen_patterns));
var_dump(in_array('README.html', $seen_fnames));
?>
--EXPECT--
The list of Debian mirror sites is available here: https://www.debian.org/mirror/list
var_dump(curl_exec($ch) !== false);
var_dump(in_array('README.*', $seen_patterns));
var_dump(in_array('README.html', $seen_fnames));
?>
--EXPECT--
bool(true)

We probably do not want changing content to affect tests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this is a little bit brittle, but this is to test that the return value of fnmatch_function works. I.e. fnmatch_function returns that only README.mirrors.txt matches and no other files, so here we expect only the contents of README.mirrors.txt.

bool(true)
bool(true)
54 changes: 54 additions & 0 deletions ext/curl/tests/curl_setopt_CURLOPT_MAXFILESIZE_LARGE.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
--TEST--
Curl option CURLOPT_MAXFILESIZE_LARGE
--DESCRIPTION--
Test CURLOPT_MAXFILESIZE_LARGE with values that exceed, do not exceed, and
disable the limit, as well as a negative value that triggers an error.
--EXTENSIONS--
curl
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();

echo "Body larger than CURLOPT_MAXFILESIZE_LARGE\n";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "{$host}/get.inc");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_MAXFILESIZE_LARGE, 10);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version gate in SKIPIF?

php-src/ext/curl/curl.stub.php

Lines 1449 to 1454 in c621cbe

/* Available since 7.11.1 */
/**
* @var int
* @cvalue CURLOPT_MAXFILESIZE_LARGE
*/
const CURLOPT_MAXFILESIZE_LARGE = UNKNOWN;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minimum curl version PHP can be built with is 7.61, so CURLOPT_MAXFILESIZE_LARGE is always available.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then the responder needs a case for this test that sends content length.

$r = curl_exec($ch);
var_dump($r);
var_dump(curl_errno($ch) === CURLE_FILESIZE_EXCEEDED);

echo "Body smaller than CURLOPT_MAXFILESIZE_LARGE\n";
curl_setopt($ch, CURLOPT_MAXFILESIZE_LARGE, 30);
$r = curl_exec($ch);
var_dump(strlen($r));

echo "Limit disabled by setting CURLOPT_MAXFILESIZE_LARGE to 0\n";
curl_setopt($ch, CURLOPT_MAXFILESIZE_LARGE, 0);
$r = curl_exec($ch);
var_dump(strlen($r));

echo "Negative value for CURLOPT_MAXFILESIZE_LARGE\n";
$ok = curl_setopt($ch, CURLOPT_MAXFILESIZE_LARGE, -1);
var_dump($ok);
var_dump(curl_errno($ch) === CURLE_BAD_FUNCTION_ARGUMENT);

echo "Negative value not set, CURLOPT_MAXFILESIZE_LARGE is still 0\n";
$r = curl_exec($ch);
var_dump(strlen($r));

?>
--EXPECTF--
Body larger than CURLOPT_MAXFILESIZE_LARGE
bool(false)
bool(true)
Body smaller than CURLOPT_MAXFILESIZE_LARGE
int(25)
Limit disabled by setting CURLOPT_MAXFILESIZE_LARGE to 0
int(25)
Negative value for CURLOPT_MAXFILESIZE_LARGE
bool(false)
bool(true)
Negative value not set, CURLOPT_MAXFILESIZE_LARGE is still 0
int(25)
59 changes: 59 additions & 0 deletions ext/curl/tests/curl_setopt_CURLOPT_POSTREDIR.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
--TEST--
Curl option CURLOPT_POSTREDIR
--DESCRIPTION--
Verify that CURLOPT_POSTREDIR controls whether POST data is retained on
301, 302, and 303 redirects. By default libcurl turns POST into GET on
301, 302, and 303. Setting the appropriate bit in CURLOPT_POSTREDIR
keeps the POST method and body.
--EXTENSIONS--
curl
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();

function do_redirect($code, $postredir_value = null) {
global $host;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "{$host}/get.inc?test=redirect&code={$code}");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'postdata was kept in redirect');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
if ($postredir_value !== null) {
curl_setopt($ch, CURLOPT_POSTREDIR, $postredir_value);
}
return trim(curl_exec($ch));
}

$options = [null, CURL_REDIR_POST_301, CURL_REDIR_POST_302, CURL_REDIR_POST_303, CURL_REDIR_POST_ALL, 0];
$codes = [301, 302, 303];

foreach ($options as $option) {
foreach ($codes as $code) {
echo "code: $code; option ", var_export($option, true), ': ';
echo do_redirect($code, $option), "\n";
}
}

?>
--EXPECT--
code: 301; option NULL: string(0) ""
code: 302; option NULL: string(0) ""
code: 303; option NULL: string(0) ""
code: 301; option 1: string(29) "postdata was kept in redirect"
code: 302; option 1: string(0) ""
code: 303; option 1: string(0) ""
code: 301; option 2: string(0) ""
code: 302; option 2: string(29) "postdata was kept in redirect"
code: 303; option 2: string(0) ""
code: 301; option 4: string(0) ""
code: 302; option 4: string(0) ""
code: 303; option 4: string(29) "postdata was kept in redirect"
code: 301; option 7: string(29) "postdata was kept in redirect"
code: 302; option 7: string(29) "postdata was kept in redirect"
code: 303; option 7: string(29) "postdata was kept in redirect"
code: 301; option 0: string(0) ""
code: 302; option 0: string(0) ""
code: 303; option 0: string(0) ""
30 changes: 30 additions & 0 deletions ext/curl/tests/curl_setopt_CURLOPT_SSH_HOSTKEYFUNCTION.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
Curl option CURLOPT_SSH_HOSTKEYFUNCTION
--EXTENSIONS--
curl
--SKIPIF--
<?php
if (getenv('SKIP_ONLINE_TESTS')) die('skip Online test');
$curl_version = curl_version();
if ($curl_version['version_number'] < 0x075400) {
exit("skip: test works only with curl >= 7.84.0");
}
?>
--FILE--
<?php

function hostkeyfunction($ch, int $keyType, string $key, int $keyLength) {
return CURLKHMATCH_MISMATCH;
}

// GitHub doesn't actually support SFTP, it does get far enough that the host key callback is called.
$ch = curl_init('sftp://php@github.com/file.txt');
curl_setopt($ch, CURLOPT_SSH_HOSTKEYFUNCTION, 'hostkeyfunction');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what's up there, but this test says CURLOPT_SSH_HOSTKEYFUNCTION cannot be properly tested. But others do test it; looks like it needs at least a version gate in SKIPIF?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the version check.

@Girgias Do you have any insight into why CURLOPT_SSH_HOSTKEYFUNCTION cannot be properly tested?

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
var_dump(curl_exec($ch));
var_dump(curl_error($ch));

?>
--EXPECT--
bool(false)
string(49) "SSL peer certificate or SSH remote key was not OK"
Loading
Loading