EzDev.org

guzzle

Guzzle, an extensible PHP HTTP client Guzzle, PHP HTTP client — Guzzle Documentation


Unable to find wrapper when testing Guzzle call with PHPUnit

I am writing a unit test for an API that I am developing. The API is written in the Codeigniter framework, that calls another API using Guzzle. The test I am writing verifies that the API call returns the correct response.

The Test.php file contains the following code

require '/application/libraries/apiWrappers/Breathehr.php';

class BreathehrTest extends PHPUnit_Framework_TestCase {

    public function testCanReturnEmployeeArray() {
        $breatheHR = new Breathehr();

        $employees = $breatheHR->list_employees(1);
        $this->assertArrayHasKey('employees', $employees);
    }


}

The method that is being tested is as follows

class Breathehr {

    function __construct() {

    }

    public function list_employees($page)
    {
        $client = new GuzzleHttp\Client(
            ['base_uri' => 'https://xxx/',
                'headers' => ['X-API-KEY' => 'xxx'],
                'verify' => false]
        );

        $request = $client->get('employees?page='.$page);
        $employees = json_decode($request->getBody(true));

        $employeeData = array(
            'employees' => array(),
            'pagination' => array()
        );

        $i = 0;
        foreach($employees->employees as $employee) {
            if($employee->status !== 'Ex-employee') {
                $employeeData['employees'][$i]['firstName'] = $employee->first_name;
                $employeeData['employees'][$i]['lastName'] = $employee->last_name;
                $employeeData['employees'][$i]['jobTitle'] = $employee->job_title;
                if(isset($employee->line_manager)) {
                    $employeeData['employees'][$i]['lineManagerName'] = $employee->line_manager->first_name . ' '. $employee->line_manager->last_name;
                    $employeeData['employees'][$i]['lineManagerID'] = $employee->line_manager->id;
                }
                $employeeData['employees'][$i]['workingHours'] = $employee->full_or_part_time;
                $employeeData['employees'][$i]['email'] = $employee->email;
                $employeeData['employees'][$i]['workPhone'] = $employee->ddi;
                $employeeData['employees'][$i]['personalMobile'] = $employee->personal_mobile;
                $employeeData['employees'][$i]['homeTelephone'] = $employee->home_telephone;
                $employeeData['employees'][$i]['birthday'] = $employee->dob;
                $i++;
            }
        }

        $nextLink = $request->getHeader('Link');
        $nextLinkSplit = explode(',', $nextLink[0]);

        $pageination = array();

        foreach($nextLinkSplit as $data) {
            $split = explode(';', $data);
            preg_match('/"(.*?)"/', $split[1], $keyMatch);
            $key = isset($keyMatch[1]) ? $keyMatch[1] : FALSE;
            $number = substr($split[0], -2, 1);

            $pageination[$key] = $number;
        }

        array_push($employeeData['pagination'], $pageination);

        return $employeeData;
    }

}

The API call works correctly via Postman and from a browser, but the result of running PHPUnit from the command line is the following

RuntimeException: Error creating resource: [message] fopen(): Unable to find the wrapper "https" - did you forget to enable it when you configured PHP?

[message] fopen(https://api.breathehr.com/v1/employees?page=1): failed to open stream: No such file or directory

I have googled the error message and came across this SO post Unable to find the wrapper "https" - did you forget to enable it when you configured PHP?

Making these changes has made no difference. It's worth noting this is on localhost, running MAMP.

Any ideas?

Thanks


Source: (StackOverflow)

Guzzlehttp - how do I work with / get my expected response?

I'm trying to write a wrapper around an api my company is developing. It's restful, and using Postman I can send a post request to an endpoint like http://subdomain.dev.myapi.com/api/v1/auth/ with a username and password as POST data and I am given back a token. All works as expected. Now, when I try and do the same from PHP I get back a GuzzleHttp\Psr7\Response object, but can't seem to find the token anywhere inside it as I did with the Postman request.

The relevant code looks like:

$client = new Client(['base_uri' => 'http://companysub.dev.myapi.com/']);
$response = $client->post('api/v1/auth/', [
    'form_params' => [
        'username' => $user,
        'password' => $password
    ]
]);

var_dump($response); //or $resonse->getBody(), etc...

The output of the code above looks something like (warning, incoming wall of text):

object(guzzlehttp\psr7\response)#36 (6) {
  ["reasonphrase":"guzzlehttp\psr7\response":private]=>
  string(2) "ok"
  ["statuscode":"guzzlehttp\psr7\response":private]=>
  int(200)
  ["headers":"guzzlehttp\psr7\response":private]=>
  array(9) {
    ["connection"]=>
    array(1) {
      [0]=>
      string(10) "keep-alive"
    }
    ["server"]=>
    array(1) {
      [0]=>
      string(15) "gunicorn/19.3.0"
    }
    ["date"]=>
    array(1) {
      [0]=>
      string(29) "sat, 30 may 2015 17:22:41 gmt"
    }
    ["transfer-encoding"]=>
    array(1) {
      [0]=>
      string(7) "chunked"
    }
    ["content-type"]=>
    array(1) {
      [0]=>
      string(16) "application/json"
    }
    ["allow"]=>
    array(1) {
      [0]=>
      string(13) "post, options"
    }
    ["x-frame-options"]=>
    array(1) {
      [0]=>
      string(10) "sameorigin"
    }
    ["vary"]=>
    array(1) {
      [0]=>
      string(12) "cookie, host"
    }
    ["via"]=>
    array(1) {
      [0]=>
      string(9) "1.1 vegur"
    }
  }
  ["headerlines":"guzzlehttp\psr7\response":private]=>
  array(9) {
    ["connection"]=>
    array(1) {
      [0]=>
      string(10) "keep-alive"
    }
    ["server"]=>
    array(1) {
      [0]=>
      string(15) "gunicorn/19.3.0"
    }
    ["date"]=>
    array(1) {
      [0]=>
      string(29) "sat, 30 may 2015 17:22:41 gmt"
    }
    ["transfer-encoding"]=>
    array(1) {
      [0]=>
      string(7) "chunked"
    }
    ["content-type"]=>
    array(1) {
      [0]=>
      string(16) "application/json"
    }
    ["allow"]=>
    array(1) {
      [0]=>
      string(13) "post, options"
    }
    ["x-frame-options"]=>
    array(1) {
      [0]=>
      string(10) "sameorigin"
    }
    ["vary"]=>
    array(1) {
      [0]=>
      string(12) "cookie, host"
    }
    ["via"]=>
    array(1) {
      [0]=>
      string(9) "1.1 vegur"
    }
  }
  ["protocol":"guzzlehttp\psr7\response":private]=>
  string(3) "1.1"
  ["stream":"guzzlehttp\psr7\response":private]=>
  object(guzzlehttp\psr7\stream)#27 (7) {
    ["stream":"guzzlehttp\psr7\stream":private]=>
    resource(40) of type (stream)
    ["size":"guzzlehttp\psr7\stream":private]=>
    null
    ["seekable":"guzzlehttp\psr7\stream":private]=>
    bool(true)
    ["readable":"guzzlehttp\psr7\stream":private]=>
    bool(true)
    ["writable":"guzzlehttp\psr7\stream":private]=>
    bool(true)
    ["uri":"guzzlehttp\psr7\stream":private]=>
    string(10) "php://temp"
    ["custommetadata":"guzzlehttp\psr7\stream":private]=>
    array(0) {
    }
  }
}

The output from Postman was something like:

{
    "data" : {
        "token" "fasdfasf-asfasdfasdf-sfasfasf"
    }
}

Clearly I'm missing something about working with the response objects in Guzzle. The Guzzle response indicates a 200 status code on the request, so I'm not sure exactly what I need to do to retrieve the returned data.


Source: (StackOverflow)

PHP: How to check for timeout exception in Guzzle 4?

Guzzle throws an exception if an error occured during the request. Unfortunately, there does not seem to be an error specific to timeouts - which is important for me as I know that those can ocassionally occur. I'd like to retry the corresponding request and need to able to tell if the error occured due to a timeout.

From the docs:

// Timeout if a server does not return a response in 3.14 seconds.
$client->get('/delay/5', ['timeout' => 3.14]);
// PHP Fatal error:  Uncaught exception 'GuzzleHttp\Exception\RequestException'

The RequestException has the info in itsmessage property:

"cURL error 28: Operation timed out after 3114 milliseconds with 0 bytes received"

So I could evaluate the message pattern but this feels kinda wrong, because those messages could easily be changed in the future.

Is there a better/more stable way to check for timeouts when using guzzle 4?


Source: (StackOverflow)

Can't seem to upload large files with php Guzzle

I'm having issues uploading large files using Guzzle ( 5.2.0 )

I added the progress event listener and got this output:

Downloaded 0 of 0 Uploaded 966656 of 1467594
Downloaded 0 of 0 Uploaded 983040 of 1467594
Downloaded 0 of 0 Uploaded 999424 of 1467594
Downloaded 0 of 0 Uploaded 1015808 of 1467594
Downloaded 0 of 0 Uploaded 1032192 of 1467594
Downloaded 0 of 0 Uploaded 1048576 of 1467594
Downloaded 0 of 0 Uploaded 1064960 of 1467594
Downloaded 0 of 0 Uploaded 1081344 of 1467594
Downloaded 0 of 0 Uploaded 1097728 of 1467594
Downloaded 0 of 0 Uploaded 1114112 of 1467594
Downloaded 0 of 0 Uploaded 1130496 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594
Downloaded 0 of 0 Uploaded 1146880 of 1467594

It appears to get stuck at 1146880 bytes every time, hangs and then hits the curl timeout.

Here's how I'm formatting the guzzle request:

$client = new \GuzzleHttp\Client();
$endpoint = 'http://myendpoint.com'

$file = new splfileobject( '/path/to/file' )

$options = [
    "body" => [
        "file" => fopen( $file->getRealPath(), 'r' )
    ]
]

$client->post( $endpoint, $options );

When I switch to using raw curl, I'm able to upload the image using the '@filename' syntax.

Any ideas? thank you !


Source: (StackOverflow)

Moving Curl client ssl to Guzzle

I'm using Guzzle v3.9.2 with both php 5.3 and php 5.5.

I have the following working curl code that uses an ssl client certificate:

$url = "https://example.com/";
$cert_file = '/path/to/certificate.pem';

$ch = curl_init();
$options = array(
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_URL => $url ,
  CURLOPT_SSLCERT => $cert_file ,
);

curl_setopt_array($ch , $options);
$output = curl_exec($ch);

if (!$output) {
  echo "Curl Error : " . curl_error($ch);
}
else {
  echo htmlentities($output);
}

I have tried to move it to Guzzle:

require '/var/www/vendor/autoload.php';
use Guzzle\Http\Client;
$client = new Client();
$request = $client->get($url, array('cert' => $cert_file));
$response = $client->send($request);
echo $response . PHP_EOL;
print 'HI' . PHP_EOL;

When I run it using curl I get a 200 response. When I use Guzzle I get a 403.


Source: (StackOverflow)

Symfony2 ReST Client Structure

I am trying to establish a best-practice pattern for ReST clients in Symfony 2, as this is a very common job for us at my company, where we have Symfony apps on the frontend edge talking to Java based backends over HTTP/ReST.

My thinking is this, these services fill the "Repository" role in DDD for the particular domain in question . Based on the conventions specified by Doctrine, these would go in Repository classes that return Entity objects.

I think that same convention can work here as well, ReST client implement a Repository class using a library like Guzzle or just straight Curl, doesn't matter how, and then the code there does basic transformations from XML or JSON from and back to Entity objects for the upstream developer to manipulate. This is consistent with the patterns in other Symfony 2 use-cases and makes sense from a DDD standpoint.

Does anyone see a problem with this or a better way to do it?


Source: (StackOverflow)

Copy remote file using Guzzle

I'm trying to copy a remote file (image PNG, GIF, JPG ...) to my server. I use Guzzle since I sometimes get 404 with copy() even if the file exists and I also need to do a basic auth. This script is within a long script launched in command triggered by a cron job. I'm pretty new to Guzzle and I successfully copy the image but my files have wrong mime type. I must be doing something wrong here. Please suggest me a good way to do this (including checking success/failure of copy and mime type check). If file has no mime type I would pop an error with details informations.

Here is the code:

$remoteFilePath = 'http://example.com/path/to/file.jpg';
$localFilePath = '/home/www/path/to/file.jpg';
try {
    $client = new Guzzle\Http\Client();
    $response = $client->send($client->get($remoteFilePath)->setAuth('login', 'password'));
    if ($response->getBody()->isReadable()) {
        if ($response->getStatusCode()==200) {
            // is this the proper way to retrieve mime type?
            //$mime = array_shift(array_values($response->getHeaders()->get('Content-Type')));
            file_put_contents ($localFilePath , $response->getBody()->getStream());
            return true;
        }
    }
} catch (Exception $e) {
    return $e->getMessage();
}

When I do this my mime type is set to application/x-empty

Also it looks like when status is different from 200 Guzzle will automatically throw an exception. How can I stop this behaviour and check status myself so I can custom error message?

EDIT: This was for Guzzle 3.X Now this is how you can do it using Guzzle v 4.X

$client = new \GuzzleHttp\Client();
$client->get(
    'http://path.to/remote.file',
    [
        'headers' => ['key'=>'value'],
        'query'   => ['param'=>'value'],
        'auth'    => ['username', 'password'],
        'save_to' => '/path/to/local.file',
    ]);

Or using Guzzle stream:

use GuzzleHttp\Stream;

$original = Stream\create(fopen('https://path.to/remote.file', 'r')); 
$local = Stream\create(fopen('/path/to/local.file', 'w')); 
$local->write($original->getContents());

This looks great. Is there better/proper solution when using Guzzle 4?


Source: (StackOverflow)

Catching exceptions from Guzzle

I'm trying to catch exceptions from a set of tests I'm running on an API I'm developing and I'm using Guzzle to consume the API methods. I've got the tests wrapped in a try/catch block but it is still throwing unhandled exception errors. Adding an event listener as described in their docs doesn't seem to do anything. I need to be able to retrieve the responses that have HTTP codes of 500, 401, 400, in fact anything that isn't 200 as the system will set the most appropriate code based on the result of the call if it didn't work.

Current code example

foreach($tests as $test){

        $client = new Client($api_url);
        $client->getEventDispatcher()->addListener('request.error', function(Event $event) {        

            if ($event['response']->getStatusCode() == 401) {
                $newResponse = new Response($event['response']->getStatusCode());
                $event['response'] = $newResponse;
                $event->stopPropagation();
            }            
        });

        try {

            $client->setDefaultOption('query', $query_string);
            $request = $client->get($api_version . $test['method'], array(), isset($test['query'])?$test['query']:array());


          // Do something with Guzzle.
            $response = $request->send();   
            displayTest($request, $response);
        }
        catch (Guzzle\Http\Exception\ClientErrorResponseException $e) {

            $req = $e->getRequest();
            $resp =$e->getResponse();
            displayTest($req,$resp);
        }
        catch (Guzzle\Http\Exception\ServerErrorResponseException $e) {

            $req = $e->getRequest();
            $resp =$e->getResponse();
            displayTest($req,$resp);
        }
        catch (Guzzle\Http\Exception\BadResponseException $e) {

            $req = $e->getRequest();
            $resp =$e->getResponse();
            displayTest($req,$resp);
        }
        catch( Exception $e){
            echo "AGH!";
        }

        unset($client);
        $client=null;

    }

Even with the specific catch block for the thrown exception type I am still getting back

Fatal error: Uncaught exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 401 [reason phrase] Unauthorized [url]

and all execution on the page stops, as you'd expect. The addition of the BadResponseException catch allowed me to catch 404s correctly, but this doesn't seem to work for 500 or 401 responses. Can anyone suggest where I am going wrong please.


Source: (StackOverflow)

How to perform multiple Guzzle requests at the same time?

I can perform single requests using Guzzle and I'm very pleased with Guzzle's performance so far however, I read in the Guzzle API something about MultiCurl and Batching.

Could someone explain to me how to make multiple requests at the same time? Async if possible. I don't know if that is what they mean with MultiCurl. Sync would also be not a problem. I just want to do multiple requests at the same time or very close (short space of time).


Source: (StackOverflow)

Building query string progammatically in Guzzle?

In my PHP Guzzle client code, I have something like

$c = new Client('http://test.com/api/1.0/function');

$request = $c->get('?f=4&l=2&p=3&u=5');

but instead I want to have something like:

$request->set('f', 4);
$request->set('l', 2);
$request->set('p', 3);
$request->set('u', 5);

Is it possible in Guzzle? From the documentation and random googling it would seem it is, but I can't find exactly how.


Source: (StackOverflow)

Handle Guzzle exception and get HTTP body

I would like to handle errors from Guzzle when the server returns 4xx and 5xx status codes. I make a request like this:

$client = $this->getGuzzleClient();
$request = $client->post($url, $headers, $value);
try {
    $response = $request->send();
    return $response->getBody();
} catch (\Exception $e) {
    // How can I get the response body?
}

$e->getMessage returns code info but not the body of the HTTP response. How can I get the response body?


Source: (StackOverflow)

Using Guzzle to consume SOAP

I'm loving the Guzzle framework that I just discovered. I'm using it to aggregate data across multiple API's using different response structures. It's worked find with JSON and XML, but one the services i need to consume uses SOAP. Is there a built-in way to consume SOAP services with Guzzle?


Source: (StackOverflow)

How can I use Guzzle to send a POST request in JSON?

Does anybody know the correct way to post JSON using Guzzle?

$request = $this->client->post(self::URL_REGISTER,array(
                'content-type' => 'application/json'
        ),array(json_encode($_POST)));

I get an “internal server error” response from the server. It works using Chrome Postman.


Source: (StackOverflow)

Guzzle 6: no more json() method for responses

Previously in Guzzle 5.3:

$response = $client->get('http://httpbin.org/get');
$array = $response->json(); // Yoohoo
var_dump($array[0]['origin']);

I could easily get a PHP array from a JSON response. Now In Guzzle 6, I don't know how to do. There seems to be no json() method anymore. I (quickly) read the doc from the latest version and don't found anything about JSON responses. I think I missed something, maybe there is a new concept that I don't understand (or maybe I did not read correctly).

Is this (below) new way the only way?

$response = $client->get('http://httpbin.org/get');
$array = json_decode($response->getBody()->getContents(), true); // :'(
var_dump($array[0]['origin']);

Or is there an helper or something like that?


Source: (StackOverflow)

How to autoload Guzzle in Laravel 4?

How can I autoload Guzzle in Laravel 4?

I am encountering the following error when I try to create a new GuzzleHttp/Client:

Symfony \ Component \ Debug \ Exception \ FatalErrorException
Class 'GuzzleHttp\Client' not found

I have the following set up in my composer.json autoload section:

autoload: {
    "psr-0": {
        "Guzzle\\": "src/"
    }
}

Source: (StackOverflow)