PHP cURL
last modified October 22, 2026
PHP cURL tutorial shows how to work with cURL library in PHP. cURL is a wrapper over the libcurl library.
cURL
The curl is a command line tool and library for transferring data with
URL. It supports multiple protocols including HTTP, HTTPS, FTP, GOPHER, MQTT,
or SMTP. The cURL is a PHP wrapper over the library.
The cURL must be installed. For instance, on Debian the package name is
php-curl.
PHP cURL GET request
In the following examples, we create simple GET requests.
<?php
$ch = curl_init('https://example.com');
curl_exec($ch);
curl_close($ch);
In the example, we send a GET request to a small website. The output is directly shown in the standard output.
$ch = curl_init('https://example.com');
The curl_init function initializes a new session and returns a cURL
handle for use with the curl_setopt, curl_exec,
and curl_close functions. We provide a URL to which we sent the
request.
curl_exec($ch);
The curl_exec executes the given cURL session.
curl_close($ch);
The curl_close closes the cURL session.
$ php get_req.php
<!doctype html><html lang=en><head><meta charset=utf-8><link rel=icon href=data:,><meta name=viewport content="width=device-width,initial-scale=1"><title>Example Domain</title><style>html{color-scheme:light dark;background:light-dark(#eee,#222)}body{font:16px/1.6 system-ui,sans-serif;max-width:26em;margin:auto;padding:25vh 2em 2em;text-align:center}</style></head><body><p>This domain is for use in documentation examples without needing permission. This is not a service; avoid relying on it for testing and monitoring purposes.</p><script src=/s.js></script></body></html>
In the next example, we send the output of the transfer to a variable.
<?php
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
curl_close($ch);
echo $data;
With the curl_setopt we set options for the cURL transfer. The
CURLOPT_RETURNTRANSFER returns the transfer as a string of the
return value of curl_exec instead of outputting it directly.
PHP cURL download file
The CURLOPT_FILE option specifies where the transfer should be
written to; the default is the standard output.
<?php
$ch = curl_init('https://example.com');
$fp = fopen('index.html', 'w');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_exec($ch);
if (curl_error($ch)) {
fwrite($fp, curl_error($ch));
}
curl_close($ch);
fclose($fp);
In the example, we set CURLOPT_FILE option to a file handle, that
we have created. With the CURLOPT_HEADER, we disable the header.
PHP cURL HEAD request
A HEAD request is a GET request without the body.
<?php
$ch = curl_init('https://example.com');
$options = [CURLOPT_HEADER => true, CURLOPT_NOBODY => true,
CURLOPT_RETURNTRANSFER => true ];
curl_setopt_array($ch, $options);
$data = curl_exec($ch);
echo $data;
curl_close($ch);
In order to generate a HEAD request, we set the CURLOPT_HEADER
to true and the CURLOPT_NOBODY to false. We set all the options
at once with curl_setopt_array.
$ php head_req.php HTTP/2 200 date: Thu, 22 Oct 2026 19:42:35 GMT content-type: text/html; charset=utf-8 server: cloudflare last-modified: Wed, 21 Oct 2026 19:59:02 GMT allow: GET, HEAD accept-ranges: bytes age: 6 cf-cache-status: HIT cf-ray: a4eafc706bfababc-VIE alt-svc: h3=":443"; ma=86400
PHP cURL status code
With the curl_getinfo function we get information regarding a
specific transfer.
<?php
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
echo $status;
curl_close($ch);
We send a HEAD request to a website. After executing the request, we get the
status by passing the CURLINFO_RESPONSE_CODE option to the
curl_getinfo function.
$ php status.php 200
PHP cURL POST form
The POST form request issues a POST to the specified URL, with data's keys and values URL-encoded as the request body. The Content-Type header is set to application/x-www-form-urlencoded. The data is sent in the body of the request; the keys and values are encoded in key-value tuples separated by '&', with a '=' between the key and the value.
<?php
$ch = curl_init('https://httpbin.org/post');
$fields = ['name' => 'John Doe', 'occupation' => 'gardener'];
$options = [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $fields,
CURLOPT_RETURNTRANSFER => true];
curl_setopt_array($ch, $options);
$data = curl_exec($ch);
curl_close($ch);
echo $data;
The POST request is set with the CURLOPT_POST option. The POST
fields are set with the CURLOPT_POSTFIELDS option.
$ php post_form.php
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "John Doe",
"occupation": "gardener"
},
"headers": {
"Accept": "*/*",
"Content-Length": "254",
"Content-Type": "multipart/form-data; boundary=------------------------9486d8af92b30dd9",
"Host": "httpbin.org",
"User-Agent": "curl/7.81.0",
"X-Amzn-Trace-Id": "Root=1-6ada672c-41b5c92f22c7cdb46ba09a0a"
},
"json": null,
"origin": "195.12.142.153",
"url": "https://httpbin.org/post"
}
PHP cURL POST JSON
In the following example, we POST JSON data.
<?php
$ch = curl_init('https://httpbin.org/post');
$fields = json_encode(['name' => 'John Doe', 'occupation' => 'gardener']);
$options = [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $fields,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true];
curl_setopt_array($ch, $options);
$data = curl_exec($ch);
curl_close($ch);
echo $data;
We encode the JSON data with the json_encode function. We set the
appropriate header with the CURLOPT_HTTPHEADER option.
$ php post_json.php
{
"args": {},
"data": "{\"name\":\"John Doe\",\"occupation\":\"gardener\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "43",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "curl/7.81.0",
"X-Amzn-Trace-Id": "Root=1-6ada672d-2dad55514cf321ef3692e288"
},
"json": {
"name": "John Doe",
"occupation": "gardener"
},
"origin": "195.12.142.153",
"url": "https://httpbin.org/post"
}
PHP cURL multiple async requests
The curl_multi_init function creates a new multi handle, which
allows the processing of multiple cURL handles asynchronously.
<?php
$urls = [
"https://example.com",
"https://httpbin.org",
"https://www.perl.org",
"https://www.php.net"
];
$options = [CURLOPT_HEADER => true, CURLOPT_NOBODY => true,
CURLOPT_RETURNTRANSFER => true];
$mh = curl_multi_init();
$chs = [];
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt_array($ch, $options);
curl_multi_add_handle($mh, $ch);
$chs[] = $ch;
}
$running = false;
do {
curl_multi_exec($mh, $running);
} while ($running);
foreach ($chs as $h) {
curl_multi_remove_handle($mh, $h);
}
curl_multi_close($mh);
foreach ($chs as $h) {
$status = curl_getinfo($h, CURLINFO_RESPONSE_CODE);
echo $status . "\n";
}
foreach ($chs as $h) {
echo "----------------------\n";
echo curl_multi_getcontent($h);
}
In the example, we create asynchronous requests to four websites. We print their status codes and headers.
$mh = curl_multi_init();
We initiate the multi handle.
foreach ($urls as $url) {
$ch = curl_init($url);
curl_setopt_array($ch, $options);
curl_multi_add_handle($mh, $ch);
$chs[] = $ch;
}
We create standard handles for each URLs and add them to the multi handle with
curl_multi_add_handle.
$running = false;
do {
curl_multi_exec($mh, $running);
} while ($running);
We execute all queries asynchronously, and continue when all are complete.
foreach ($chs as $h) {
curl_multi_remove_handle($mh, $h);
}
curl_multi_close($mh);
We close the handles.
foreach ($chs as $h) {
$status = curl_getinfo($h, CURLINFO_RESPONSE_CODE);
echo $status . "\n";
}
We get the status codes.
foreach ($chs as $h) {
echo "----------------------\n";
echo curl_multi_getcontent($h);
}
We get the headers.
$ php multi_async.php 200 200 200 200 ---------------------- HTTP/2 200 date: Thu, 22 Oct 2026 19:42:37 GMT content-type: text/html; charset=utf-8 server: cloudflare last-modified: Wed, 21 Oct 2026 19:59:02 GMT allow: GET, HEAD accept-ranges: bytes age: 8 cf-cache-status: HIT cf-ray: a4eafc7d88bf5ad5-VIE alt-svc: h3=":443"; ma=86400 ---------------------- HTTP/2 200 date: Thu, 22 Oct 2026 19:42:38 GMT content-type: text/html; charset=utf-8 content-length: 9593 server: gunicorn/19.9.0 access-control-allow-origin: * access-control-allow-credentials: true ---------------------- HTTP/2 200 content-type: text/html; charset=utf-8 last-modified: Thu, 22 Oct 2026 18:07:28 GMT server: Combust/Plack (Perl) x-content-type-options: nosniff x-frame-options: deny x-xss-protection: 1 via: 1.1 varnish, 1.1 varnish strict-transport-security: max-age=63072000; includeSubDomains; preload accept-ranges: bytes age: 3121 date: Thu, 22 Oct 2026 19:42:38 GMT x-served-by: cache-dfw-kdfw8210122-DFW, cache-vie6375-VIE x-cache: HIT, HIT x-cache-hits: 32, 0 x-timer: S1792698158.442320,VS0,VE1 vary: Accept-Encoding x-backend: dala x-backend-front: ssl_shield_dallas_tx_us alt-svc: h3=":443";ma=86400,h3-29=":443";ma=86400,h3-27=":443";ma=86400 content-length: 12345 ---------------------- HTTP/2 200 date: Thu, 22 Oct 2026 19:42:38 GMT content-type: text/html; charset=utf-8 vary: Accept-Encoding server: BunnyCDN-SK1-721 cdn-pullzone: 5992589 cdn-requestcountrycode: SK cache-control: public, max-age=300 content-language: en last-modified: Thu, 22 Oct 2026 19:30:20 GMT strict-transport-security: max-age=15768000 permissions-policy: interest-cohort=() x-frame-options: SAMEORIGIN link: <https://www.php.net/index>; rel=shorturl cdn-proxyver: 1.71 cdn-requestpullcode: 200 cdn-requestpullsuccess: True cdn-edgestorageid: 1216, 721 cdn-cachedat: 10/22/2026 19:38:39 cdn-status: 200 cdn-requesttime: 0 cdn-requestid: 2d7b8de0fd23b7c035170a920403eb30 cdn-cache: HIT
PHP cURL send email
We build a custom request with the CURLOPT_CUSTOMREQUEST option.
<?php
$ch = curl_init("core9");
curl_setopt($ch, CURLOPT_PORT, 25);
curl_setopt($ch, CURLOPT_CRLF, true);
$from = "john.doe@example.com";
$to = "root@core9";
$name = "John Doe";
$subject = "Hello";
$body = "Hello there";
$data = "EHLO core9\n";
$data .= "MAIL FROM:<$from>\n";
$data .= "RCPT TO:<$to>\n";
$data .= "DATA\n";
$data .= "$subject\n";
$data .= "$body\n";
$data .= "\n.\n";
$data .= "QUIT\n";
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $data);
curl_exec($ch);
curl_close($ch);
The example sends an email to a computer on a local network.
$ch = curl_init("core9");
The core9 is the name of the computer running email server on
a LAN.
curl_setopt($ch, CURLOPT_PORT, 25); curl_setopt($ch, CURLOPT_CRLF, true);
We specify the port number with CURLOPT_PORT. The
CURLOPT_CRLF translates Unix new lines into \r\n,
which are control characters of the SMTP protocol.
$data = "EHLO core9\n"; $data .= "MAIL FROM:<$from>\n"; $data .= "RCPT TO:<$to>\n"; $data .= "DATA\n"; $data .= "$subject\n"; $data .= "$body\n"; $data .= "\n.\n"; $data .= "QUIT\n";
The mail is build by using the SMPT commands.
From john.doe@example.com Tue Feb 9 18:00:08 2021
Return-Path: <john.doe@example.com>
Received: from core9 (spartan.local [192.168.0.20])
by core9 (8.15.2/8.15.2) with ESMTP id 119H08go001746
for <root@core9>; Tue, 9 Feb 2021 18:00:08 +0100 (CET)
(envelope-from john.doe@example.com)
Date: Tue, 9 Feb 2021 18:00:08 +0100 (CET)
From: john.doe@example.com
Message-Id: <202102091700.119H08go001746@core9>
To: undisclosed-recipients:;
Status: RO
Hello
Hello there
We check the email with an email client on the server.
Source
In this article we have worked with the PHP cURL library.
Author
List all PHP tutorials.