ZetCode

PHP cURL

last modified January 10, 2023

PHP cURL tutorial shows how to work with cURL library in PHP. cURL is a wrapper over the libcurl library.

$ php -v
php -v
PHP 8.1.2 (cli) (built: Aug  8 2022 07:28:23) (NTS)
...

We use PHP version 8.1.2.

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.

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.