Goutte
PHP

Goutte is a screen scraping and web crawling library for PHP. Integrating Blackfire with Goutte lets you profile programmatically your websites, HTTP APIs, or web services.

First, add Blackfire PHP SDK as a dependency on your project and be sure to require Goutte as well:

1
composer require fabpot/goutte

To profile with Goutte, add the X-Blackfire-Query HTTP header before doing any HTTP request you want to profile with Blackfire:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Goutte\Client as GoutteClient;
use Blackfire\Client as BlackfireClient;

$blackfire = new BlackfireClient();

$client = new GoutteClient();

// as we want to profile the next request, add the Blackfire header
$profileRequest = $blackfire->createRequest('Blog Home');
$client->setHeader('X-Blackfire-Query', $profileRequest->getToken());

$crawler = $client->request('GET', 'https://www.symfony.com/blog/');

// get the profile for the request
$profile = $blackfire->getProfile($profileRequest->getUuid());

$link = $crawler->selectLink('Security Advisories')->link();

// also works before clicking on a link or submitting a form
$client->setHeader('X-Blackfire-Query', $blackfire->createRequest('Security Advisories')->getToken());
$crawler = $client->click($link);

Never re-use a token for different HTTP requests.

If you execute this script, two profiles will be created on your Blackfire account (tests defined in .blackfire.yaml will be executed as well if any).

You can also take several samples of the same page to get more accurate results as done by default by the Blackfire CLI or the browser extension:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$blackfire = new BlackfireClient();

// the number of samples to take
$samples = 10;

$config = new \Blackfire\Profile\Configuration();
$config->setSamples($samples);

$client = new GoutteClient();
$config->setTitle('Blog Home');
$profileRequest = $blackfire->createRequest($config);
$client->setHeader('X-Blackfire-Query', $profileRequest->getToken());

// requests the target $samples times
for ($i = 1; $i <= $samples; $i++) {
    $crawler = $client->request('GET', 'https://www.symfony.com/blog/');
}

// get the profile for the request
$profile = $blackfire->getProfile($profileRequest->getUuid());

When running this script, you will get one profile which will be the aggregation of the 10 HTTP requests executed.

Learn more about profiling configuration settings in the PHP SDK documentation.

As Goutte provides great support for HTTP, you can create almost any HTTP request you can think of, but more importantly, you can simulate complex user interactions. Writing scenarios with Goutte is a powerful alternative to the scenarios defined in a .blackfire.yaml file.

To generate a report from a scenario created with Goutte, store all profiles in a build:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
use Goutte\Client as GoutteClient;
use Blackfire\Client as BlackfireClient;

$client = new GoutteClient();

$blackfire = new BlackfireClient();

// create a build
$build = $blackfire->startBuild('Symfony Prod', array('title' => 'Build from Goutte'));

// create a scenario
$scenario = $blackfire->startScenario($build, array('title' => 'My first scenario'));

// create a configuration
$config = new \Blackfire\Profile\Configuration();
$config->setScenario($scenario);

// set the Profile and Job name
$config->setTitle('Blog Home');

// make a profiled request
$profileRequest = $blackfire->createRequest($config);
$client->setHeader('X-Blackfire-Query', $profileRequest->getToken());
$crawler = $client->request('GET', 'https://www.symfony.com/blog/');

// get the profile for the request
$profile = $blackfire->getProfile($profileRequest->getUuid());

// click on a link, generate another profile in the build
$link = $crawler->selectLink('Security Advisories')->link();
$config->setTitle('Security Advisories');
$client->setHeader('X-Blackfire-Query', $blackfire->createRequest($config)->getToken());
$crawler = $client->click($link);

// end the scenario and fetch the report
// the scenario contains two profiles
$report = $blackfire->closeScenario($scenario);

// end the build
$blackfire->closeBuild($build);

Note that createRequest() received a Configuration tied to the scenario.