webfutura.eu Open in urlscan Pro
2606:4700:3032::ac43:a979  Public Scan

Submitted URL: http://webfutura.eu/drupal-http-client-self-signed
Effective URL: https://webfutura.eu/drupal-http-client-self-signed
Submission: On March 21 via api from US — Scanned from US

Form analysis 1 forms found in the DOM

Name: sentMessage

<form id="commentForm" name="sentMessage" novalidate="novalidate">
  <div class="control-group">
    <div class="form-group floating-label-form-group controls mb-0 pb-2 first-item">
      <label>Name</label>
      <input class="form-control" id="name" type="text" placeholder="Name" required="required" data-validation-required-message="Please enter your name.">
      <p class="help-block text-danger"></p>
    </div>
  </div>
  <div class="control-group">
    <div class="form-group floating-label-form-group controls mb-0 pb-2">
      <label>Email Address</label>
      <input class="form-control" id="email" type="email" placeholder="Email Address" required="required" data-validation-required-message="Please enter your email address.">
      <p class="help-block text-danger"></p>
    </div>
  </div>
  <div class="control-group">
    <div class="form-group floating-label-form-group controls mb-0 pb-2">
      <label>Comment</label>
      <textarea class="form-control" id="comment" rows="5" placeholder="Comment" required="required" data-validation-required-message="Please enter your comment."></textarea>
      <p class="help-block text-danger"></p>
    </div>
  </div>
  <div class="control-group last-minute-info">
    <div class="form-group floating-label-form-group controls mb-0 pb-2">
      <label>Last minute info</label>
      <input class="form-control" id="last-minute-info" rows="5" placeholder="Last Minute Info">
      <div class="help-block"></div>
    </div>
  </div>
  <input type="hidden" id="post" value="">
  <br>
  <div id="success"></div>
  <div class="form-group">
    <button class="btn btn-warning text-white btn-xl" id="sendMessageButton" type="submit">Send </button>
  </div>
</form>

Text Content

WebFutura Menu
 * Skills
 * About
 * Clients
 * Contact
 * Blog


ADVANCED CONFIGURATION OF HTTP CLIENT IN DRUPAL 7/9


HOW TO ADD ADDITIONAL SETTINGS TO THE DRUPAL 7 OR 9 BUNDLED HTTP CLIENT. AN
EXAMPLE WITH A SELF-SIGNED CERTIFICATE

Posted on October 01, 2021 · 9 mins read


MOTIVATION

Drupal makes use of Guzzle HTTP client to provide API client capabilities
directly in its Core install. When a developer needs to call any external API it
is as easy as requesting for the client service and perform the call:

$response = \Drupal::httpClient()->get('https://demoserver/demo-items.json');


The problem arises when the developer wants to add settings to the HTTP Client.
In a bare-bones PHP project it could be done simply passing parameters to the
Guzzle client constructor as in following code, but this code does not use
Drupal core functionalities and might have problems on the long term:

$client = new GuzzleHttp\Client([
  'base_uri' => 'https://demoserver',
  'verify' => 'a_self_signed_certificate_we_want_to_accept.crt',
  (...)
]);
$response = $client->request('GET', 'demo-items.json');


I will show an example below on how to add some additional parameters in a
Drupal context without instantiating Guzzle HTTP client directly but using the
bundled Drupal service, to keep our code cleaner and more easily testable.

I will also how to do the same in Drupal 7, and how to replace the core
drupal_http_request method by Guzzle too.


DRUPAL 9: MAKING API REQUESTS TO SELF-SIGNED SERVERS

The basic method to do an HTTP client request to a server with a self-signed SSL
certificate in Drupal 9 is shown below. But the client throws the displayed
error if anything happens to the client system when validating the SSL
certificate:

$response = \Drupal::httpClient()
  ->get('https://selfsigned.webfutura.eu/demo-items.json');

// Results in
GuzzleHttp\Exception\RequestException: cURL error 60: SSL certificate problem: self signed certificate
(see https://curl.haxx.se/libcurl/c/libcurl-errors.html) in GuzzleHttp\Handler\CurlFactory::createRejection()
(line 201 of (..)/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php). 


To solve this self-signed certificate problem or other problems related to the
SSL chain we need to do two things. The first is to download the public
certificate we want to accept, which can be done from our web browser, and the
second is to tell the HTTP client to use it in our get / post / request method.
This way we can finally obtain the requested demo data:

$response = \Drupal::httpClient()
    ->get('https://selfsigned.webfutura.eu/demo-items.json', [
      'verify' => 'data/selfsigned_webfutura_eu.crt',
    ]);
$response_body = $response->getBody();
print_r(json_decode($response_body->getContents()));

// Results in
Array
(
    [0] => stdClass Object
        (
            [name] => item-1
            [label] => Item 1
        )

    [1] => stdClass Object
        (
            [name] => item-2
            [label] => Item 2
        )

)




DRUPAL 7: MAKING API REQUESTS TO SELF-SIGNED SERVERS

If we wanted to do the same as in the previous example but in Drupal 7, it would
be with code below, which makes use of drupal_http_request. The difference is
that this method does not throw an exception as Guzzle did, but returns
information about the error in $result array:

$result = drupal_http_request('https://selfsigned.webfutura.eu/demo-items.json');
print_r($result);

// Results in 
stdClass Object
(
    [code] => 0
    [error] => Error opening socket ssl://selfsigned.webfutura.eu:443
)


The solution is again to add the additional settings as an argument to
drupal_http_request as in following code:

$opts['context'] = stream_context_create([ 'ssl' => [
  'cafile' => 'selfsigned_webfutura_eu.crt',
]]);
$result = drupal_http_request('https://selfsigned.webfutura.eu/demo-items.json', $opts);
print_r(json_decode($result->data));

// Results in 
Array
(
    [0] => stdClass Object
        (
            [name] => item-1
            [label] => Item 1
        )

    [1] => stdClass Object
        (
            [name] => item-2
            [label] => Item 2
        )

)



DRUPAL 7: REPLACE CORE HTTP CLIENT WITH GUZZLE

Guzzle is a great and very standardized HTTP client library. Quite an important
actor nowadays in the PHP eco-system. We can make a step further in our legacy
Drupal 7 sites using it. The same process would be used for any other composer
based library, so let’s jump out of the (Drupal) island !!

We may begin adding composer libraries to our Drupal 7 project initializing the
project and answering a few questions. Directly we may add here the libraries we
want, guzzlehttp/guzzle in our case:

$ composer init
Welcome to the Composer config generator  
This command will guide you through creating your composer.json config.
(..)
Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]? yes
Search for a package: guzzlehttp/guzzle
Enter the version constraint to require (or leave blank to use the latest version): 
Using version ^7.3 for guzzlehttp/guzzle


Then in our custom code, we need to include the composer autoload file and we
are ready to use the library !!

require_once 'vendor/autoload.php';

$client = new GuzzleHttp\Client([
  'base_uri' => 'https://selfsigned.webfutura.eu',
]);

$response = $client->get('demo-items.json', ['verify' => 'data/selfsigned_webfutura_eu.crt',]);
$response_body = $response->getBody();
print_r(json_decode($response_body>getContents()));


But wait, what if we have a big amount of code relying in drupal_http_request?
Do I need to replace all my requests? Drupal 7 core developers who knows how
many years ago provided ways to overcome this situation. We only need to set a
custom alternative to the default function in our
sites/default/files/settings.php file:

$conf['drupal_http_request_function'] = 'my_custom_http_request';


And declare it somewhere in our custom module code:

/**
 * @param $url
 * @param array $options
 * 
 * @see drupal_http_request()
 */
function my_custom_http_request($url, array $options = array()) {
  $client = new GuzzleHttp\Client();
  $response = $client->request($options['type'], $url, $options);
  $response_body = $response->getBody();
  return $response_body->getContents()
}


Obviously, this function will need to translate parameters and responses if we
want to provide a plug-and-play replacement to core drupal_http_request but at
least we will be using a state-of-the-art HTTP client in our code.

--------------------------------------------------------------------------------

← Previous Post Next Post →
Images by all-free-download.com


COMMENT ON THIS POST

Name



Email Address



Comment



Last minute info



Send

LOCATION

C./ Sant Miquel 24
17003 Girona

AROUND THE WEB



Copyright © WebFutura 2023



THIS WEBSITE DOES NOT USE COOKIES GOT IT

We do not use cookies for any purpose. Check this post for an explanation of how
to check it by yourself.