Same library, different syntax
PHP’s curl extension is a binding to libcurl — the same library the curl command-line tool uses. That makes this the most faithful of all the conversions: almost every command-line flag has a matching CURLOPT_* constant, and the request PHP sends is the one curl would send. The generated code sets every option in a single curl_setopt_array call, which is easier to read and review than a long list of curl_setopt lines, then executes the request, throws a RuntimeException with curl_error() if it fails, and echoes the status code and response.
Flag to CURLOPT mapping
| curl flag | PHP option |
|---|---|
| URL | CURLOPT_URL (plus CURLOPT_RETURNTRANSFER => true) |
-X, or any body |
CURLOPT_CUSTOMREQUEST |
-I |
CURLOPT_NOBODY |
-H |
CURLOPT_HTTPHEADER array of "Name: value" lines |
-b, -A, -e |
CURLOPT_COOKIE, CURLOPT_USERAGENT, CURLOPT_REFERER |
-d, --json |
CURLOPT_POSTFIELDS string |
-F |
CURLOPT_POSTFIELDS array with CURLFile objects |
-u |
CURLOPT_USERPWD |
-L |
CURLOPT_FOLLOWLOCATION |
--compressed |
CURLOPT_ENCODING => '' |
-k |
CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => 0 |
-m, --connect-timeout |
CURLOPT_TIMEOUT, CURLOPT_CONNECTTIMEOUT (the _MS variants for fractions) |
-x, -U |
CURLOPT_PROXY, CURLOPT_PROXYUSERPWD |
Headers curl adds implicitly, such as Content-Type: application/x-www-form-urlencoded for -d, are written into the header list so nothing depends on defaults. An empty header -H 'X-Empty;' keeps libcurl’s semicolon syntax.
Bodies and uploads
A -d body is passed as a string, byte for byte, which keeps JSON, XML or url-encoded data exactly as in the command; several -d flags are joined with & first. Passing a string to CURLOPT_POSTFIELDS sends a regular body, while passing an array makes libcurl build a multipart/form-data request — which is precisely what -F does, so form fields become an array. Files use new CURLFile($path, $mimeType, $postName), read from disk when the script runs.
PHP arrays cannot hold the same key twice, so a field repeated with -F keeps only its last value; a warning points this out. -T uploads use file_get_contents.
To work with a JSON response, decode it with json_decode($response, true) after checking $status; the generated script deliberately stops at printing so you can choose how to handle errors.
Notes on security and scope
Disabling peer and host verification for -k is fine against a local development server but should never reach production; consider pointing CURLOPT_CAINFO at your own CA instead. Options that only affect curl’s terminal output are dropped, and unsupported features are listed as notes. The conversion runs entirely in your browser. For framework code, the same request is straightforward to port to Guzzle or Symfony HttpClient, and the PHP formatter can tidy the result.
Examples
Form POST with cookies and a user agent
The user agent and cookie get their dedicated CURLOPT constants, and the implied form Content-Type is added to the header list.
curl -X POST https://shop.example.com/cart \
-H 'Accept: application/json' \
-A 'Mozilla/5.0 (PasteKit test)' \
-b 'session=abc123' \
-d 'sku=KB-104&qty=2' -L --compressed<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://shop.example.com/cart',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_USERAGENT => 'Mozilla/5.0 (PasteKit test)',
CURLOPT_COOKIE => 'session=abc123',
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'Content-Type: application/x-www-form-urlencoded',
],
CURLOPT_POSTFIELDS => 'sku=KB-104&qty=2',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => '',
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
echo $status, PHP_EOL;
echo $response, PHP_EOL;
Multipart upload with auth and a timeout
The file becomes a CURLFile with its MIME type, -u maps to CURLOPT_USERPWD, and the fractional timeout uses CURLOPT_TIMEOUT_MS.
curl https://files.example.com/upload \
-u reports:Tr0ub4dor \
-F '[email protected];type=application/pdf' \
-F 'folder=finance' -m 1.5<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://files.example.com/upload',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => [
'file' => new CURLFile('q3-report.pdf', 'application/pdf', 'q3-report.pdf'),
'folder' => 'finance',
],
CURLOPT_USERPWD => 'reports:Tr0ub4dor',
CURLOPT_TIMEOUT_MS => 1500,
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
echo $status, PHP_EOL;
echo $response, PHP_EOL;
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
PHP arrays cannot repeat the form field "f"; only its last value is sent | The command repeats an -F field name, which a PHP array cannot represent. | Rename the fields (f[0], f[1]) if the server accepts that, or build the multipart body manually. |
Reading cookies from the file "cookies.txt" is not supported; add the cookies inline with -b 'name=value' | The command loads cookies from a cookie-jar file with -b file. | Use CURLOPT_COOKIEFILE in the PHP code, or paste the cookie values inline. |
Header "Accept application/json" has no colon and is ignored | A -H value is missing the colon between name and value. | Write the header as Name: value. |
This double-quoted string is never closed | The pasted command has an unbalanced double quote. | Copy the complete command again, or close the quote manually. |
Frequently asked questions
Why curl_setopt_array instead of curl_setopt?
It sets all options in one call, which is shorter and lets you scan every option at a glance. The behaviour is identical.
How is a JSON body sent?
As a string in CURLOPT_POSTFIELDS together with the Content-Type header from your command. Passing an array would switch to multipart encoding, so the string form is used.
Does the code work with PHP 8?
Yes. It uses ext-curl functions and the CURLFile class, available in all supported PHP versions.
Is my command uploaded for conversion?
No, it is converted in your browser, so passwords and tokens in it do not leave your machine.