ZetCode

PHP cURL

last modified February 16, 2025

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.

get_req.php
<?php

$ch = curl_init('http://webcode.me');

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('http://webcode.me');

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 provice 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">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My html page</title>
</head>
<body>

    <p>
        Today is a beautiful day. We go swimming and fishing.
    </p>
    
    <p>
         Hello there. How are you?
    </p>
    
</body>
</html>

In the next example, we send the output of the transfer to a variable.

get_req2.php
<?php

$ch = curl_init('http://webcode.me');
 
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.

download_file.php
<?php

$ch = curl_init('http://webcode.me');
$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.

head_req.php
<?php

$ch = curl_init('http://webcode.me');

$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/1.1 200 OK
Server: nginx/1.6.2
Date: Mon, 08 Feb 2021 16:00:24 GMT
Content-Type: text/html
Content-Length: 348
Last-Modified: Sat, 20 Jul 2019 11:49:25 GMT
Connection: keep-alive
ETag: "5d32ffc5-15c"
Accept-Ranges: bytes

PHP cURL status code

With the curl_getinfo function we get information regarding a specific transfer.

status.php
<?php

$ch = curl_init('http://webcode.me');
 
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 reqeust 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.

post_form.php
<?php

$ch = curl_init('http://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; ...
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-602162bf-3d24fe793b7403de54ad250f"
  }, 
  "json": null, 
  ...
  "url": "http://httpbin.org/post"
}

PHP cURL POST JSON

In the following example, we POST JSON data.

post_json.php
<?php

$ch = curl_init('http://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", 
    "X-Amzn-Trace-Id": "Root=1-60216559-2436c3fe055f0fb61eb074d1"
   }, 
  "json": {
    "name": "John Doe", 
    "occupation": "gardener"
  }, 
  ...
  "url": "http://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.

multi_async.php
<?php

$urls = [ 
    "http://webcode.me", 
    "https://example.com",
    "http://httpbin.org",
    "https://www.perl.org"
];

$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_req.php 
200
200
200
200
----------------------
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Mon, 08 Feb 2021 16:37:31 GMT
Content-Type: text/html
Content-Length: 348
Last-Modified: Sat, 20 Jul 2019 11:49:25 GMT
Connection: keep-alive
ETag: "5d32ffc5-15c"
Accept-Ranges: bytes

----------------------
HTTP/2 200 
content-encoding: gzip
accept-ranges: bytes
age: 285367
cache-control: max-age=604800
content-type: text/html; charset=UTF-8
date: Mon, 08 Feb 2021 16:36:11 GMT
etag: "3147526947"
expires: Mon, 15 Feb 2021 16:36:11 GMT
last-modified: Thu, 17 Oct 2019 07:18:26 GMT
server: ECS (dcb/7F83)
x-cache: HIT
content-length: 648

----------------------
HTTP/1.1 200 OK
Date: Mon, 08 Feb 2021 16:36:11 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 9593
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

----------------------
HTTP/2 200 
server: Combust/Plack (Perl)
content-type: text/html; charset=utf-8
last-modified: Mon, 08 Feb 2021 15:29:36 GMT
x-content-type-options: nosniff
x-frame-options: deny
x-xss-protection: 1
strict-transport-security: max-age=15768000
via: 1.1 varnish, 1.1 varnish
accept-ranges: bytes
date: Mon, 08 Feb 2021 16:36:11 GMT
age: 2713
x-served-by: cache-lga21948-LGA, cache-vie21642-VIE
x-cache: HIT, HIT
x-cache-hits: 2, 1
x-timer: S1612802172.507868,VS0,VE1
content-length: 12011

PHP cURL send email

We build a custom request with the CURLOPT_CUSTOMREQUEST option.

send_mail
<?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

The cURL - PHP manual

In this article we have worked with the PHP cURL library.

Author

My name is Jan Bodnar and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all PHP tutorials.