troydavisson / PHRETS

PHP client library for interacting with a RETS server to pull real estate listings, photos and other data made available from an MLS system
http://troda.com
MIT License
449 stars 235 forks source link

RFC: Enabling cookie files throughout a RETS session #90

Open mariano opened 8 years ago

mariano commented 8 years ago

I have a wrapper on top of your library and librets that allows me to connect to different RETS server using the same framework. I did this since I originally integrated the (binary) librets, but then decided to support PHRETS.

For almost every MLS both libraries worked. However just yesterday I hit a situation where I would see CRMLS working perfectly with librets, but not with PHRETS. Furthermore, your older PHRETS version (the one you use at retsmd.com) was also working. After battling through ghosts and zombies, I narrowed it down to one difference: cookie files.

I tried enabling cookie support in Guzzle through different means, most promising being FileCookieJar. Assuming $this->session is an instance of PHRETS\Session, this is what I tried:

$jar = new \GuzzleHttp\Cookie\FileCookieJar(tempnam(null, 'phrets'));
$this->session->setCookieJar($jar);

It would still fail, though. I ended up with the following solution, which customizes CURL's cookie jar file directly:

$this->session->getClient()->setDefaultOption('config', [
    'curl' => [
        CURLOPT_COOKIEFILE => tempnam(null, 'phrets')
    ]
]);

This fixed the issue, and it's a generic solution which didn't affect any of the other MLS connections.

I thought I left this here since other people may be battling with the same. If you think it's worth integrating this into the main session configuration somehow, I can work on a PR.

callcolor commented 8 years ago

I was getting a 401 Unauthorized response from a RETS server that required digest authentication. I added this to Session.php, __construct:

    $this->client->setDefaultOption(
            'config', 
            [
                'curl' => [
                    CURLOPT_COOKIEFILE => tempnam(null, 'phrets')
                ]
            ]
    );

I believe this issue has been corrected in the latest version of Guzzle.

mariano commented 8 years ago

@callcolor why would you modify Session.php? The way I detailed above achieves the same without needing to alter code.

Could you do it from your own code as explained and see if that works?

Also did you try the latest Guzzle version to see if it indeed fixes it?

callcolor commented 8 years ago

@mariano Your solution works wonderfully, thank you for providing it. I assumed this was a bug in phrets, but it's starting to look like a guzzle bug?

I was able to get the latest version of guzzle (6.1.1) working by modifying the phrets Session class and several of the parsers to use GuzzleHttp\Psr7\Response instead of GuzzleHttp\Message\ResponseInterface. The latest version of guzzle does not fix this issue.

It appears that guzzle is still relying on curl (https://github.com/guzzle/guzzle/blob/master/src/Client.php#L340) to do the digest authentication, but is not passing curl a cookie file to use. If the server requires a session cookie be passed back with the second half of the digest authentication, the authentication fails.

gruler commented 8 years ago

I need to make the above modifications to my code so I can use the PHRETS code to access CRMLS. I am having difficulty implementing it. Can somebody tell me how I should go about doing that? Here is a snippet that I tried, but this isn't right.

$rets = new \PHRETS\Session($config); $rets->session->getClient()->setDefaultOption('config', [ 'curl' => [ CURLOPT_COOKIEFILE => tempnam(null, 'phrets') ] ]);

How should I make this call?

Thanks for your help. Jim

mike503 commented 8 years ago

Having the same issue. $rets->session doesn't exist. Editing the Session.php did (in the comment by @callcolor) worked. If it has no real bad impact, it would be nice to just roll that into PHRETS Session.php just in case. :)

wonkyoc commented 7 years ago

@gruler Basically, $rets = new \PHTRES\Session($config); is a session itself so you don't need to try $rests->session again.

Here is the example for connection if someone get trouble with connection.

$config = new \PHRETS\Configuration;
$config->setLoginUrl('your URL')->setUsername('your username')->setPassword('your password');
$rets = new \PHRETS\Session($config); 
$rets->getClient()->setDefaultOption('config', [
    'curl' => [
        CURLOPT_COOKIEFILE => tempnam(null, 'phrets')
    ]
]);
$connect = $rets->Login();
alfchee commented 6 years ago

@skia92 I'm having the same problem of having error 401 when making multiple calls to Search. I tried using your coniguration for CURL but I'm getting another error... what can I do?

PHP Fatal error:  Uncaught exception 'GuzzleHttp\Exception\ConnectException' with message 'cURL error 6: Could not resolve host: config (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)' in /home/aggs/agg/php-agg/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php:186
Stack trace:
#0 /home/aggs/agg/php-agg/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(150): GuzzleHttp\Handler\CurlFactory::createRejection(Object(GuzzleHttp\Handler\EasyHandle), Array)
#1 /home/aggs/agg/php-agg/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(103): GuzzleHttp\Handler\CurlFactory::finishError(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
#2 /home/aggs/agg/php-agg/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php(43): GuzzleHttp\Handler\CurlFactory::finish(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
#3 /home/aggs/agg/php-agg/vendor/guzzle in /home/aggs/agg/php-agg/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php on line 186
carenamaemanzano commented 6 years ago

Hi @mariano,

Can you help me out, please. I got this code:

$rets = new \PHRETS\Session($config); $rets->getClient()->setDefaultOption('config', [ 'curl' => [ CURLOPT_COOKIEFILE => tempnam('/tmp', 'phrets') ] ]); $rets->Login();

And I am trying to run url with secure HTTP, I read this thread and hoping that it can help me with my 401 authorization error.

Thanks :)

sluvitz commented 6 years ago

Hi @carenamaemanzano,

Any resolution yet? I have the exact same issue.

Thanks

carenamaemanzano commented 6 years ago

Hi @sluvitz ,

Yes. Make sure to add the $config->setHttpAuthenticationMethod(); That will fix.

Thanks

cbbov-rf commented 6 years ago

I tried adding this block $rets->getClient()->setDefaultOption('config', [ 'curl' => [ CURLOPT_COOKIEFILE => tempnam(null, 'phrets') ] ]);

but wind up with this error:

cURL error 6: Could not resolve host: config (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

andreinastasa commented 5 years ago

The fix is not working with Guzzle >= 6.0 as far as I can see. Is there any way to make it work with this version of Guzzle?

ConnectGrid commented 4 years ago

I'm still battling with this issue.

(Latest versions of all packages, and I know there are Guzzle 6.x issues, but I'd rather sort them out instead of downgrade)

In my application, multiple requests can come into the same application (in parallel) running phRETS and I want to be re-using existing connections rather than opening a separate connection for each request. This is to support on-demand object fetching, such as multiple photos for a property, with each photo being a separate request.

My MLS vendor is limiting how many simultaneous Logins that we are allowed (obviously), and I'm hoping that by re-using the same cookie each time, it will not be seen as a separate login. (Correct me if I have this wrong, because these would still be several requests in parallel, all sharing the same cookie).

I've slightly modified my own fork of phRETS to enable configuration of the CURL_COOKIEFILE item, but it's still not working. I'm trying to establish if the issue is in phRETS or in Guzzle. I expected to see my cookie file being created on the filesystem, but it is not.

Related to this, I can't see anywhere in phRETS where the $this->cookie_jar property is even being used. I don't see it being given to Guzzle in any way. Is this an oversight? A feature still in development?

Thanks for any light you can shed on this mystery. I thought the upgrade to phRETS 2.x would go more smoothly, since v1.x seems to handle cookies more predictably. 🍪

acmwallace commented 2 years ago

I'm having the same issue here, what - a year later? I'm trying to get the code above with cookies to work.. we are at Guzzle 6.5.5. The code above calls:

  $this->rets_session->getClient()->setDefaultOption('config', . . . 

But I can actually not find that function (setDefaultOption) anywhere. It's not in the phrets codebase, it's not in Guzzle.. guzzle actually has a comment "GuzzleHttp\ClientInterface::setDefaultOption has been removed."

How do I set cookie information in PHRETS?