Slim 3 Framework + Cookies - php

I've been using Slim Framework 2 for a while but want to switch to the newest version 3. When reading the upgrade guide, I was a bit bummed about them simply stating that "cookies has been removed from the core" and referring to the FIG Cookies github repo that contains code snippets that simply don't work with Slim.
Could anyone share some working code snippets that set and get some dummy cookies using Slim 3? Thanks.

If you don't want to use the tested PSR-7 library FIG Cookies you can use this:
namespace Your\App;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class Cookie
{
/**
* #param Response $response
* #param string $key
* #param string $value
* #return Response
*/
public function deleteCookie(Response $response, $key)
{
$cookie = urlencode($key).'='.
urlencode('deleted').'; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; secure; httponly';
$response = $response->withAddedHeader('Set-Cookie', $cookie);
return $response;
}
/**
* #param Response $response
* #param string $cookieName
* #param string $cookieValue
* #return Response
*/
public function addCookie(Response $response, $cookieName, $cookieValue)
{
$expirationMinutes = 10;
$expiry = new \DateTimeImmutable('now + '.$expirationMinutes.'minutes');
$cookie = urlencode($cookieName).'='.
urlencode($cookieValue).'; expires='.$expiry->format(\DateTime::COOKIE).'; Max-Age=' .
$expirationMinutes * 60 . '; path=/; secure; httponly';
$response = $response->withAddedHeader('Set-Cookie', $cookie);
return $response;
}
/**
* #param Request $request
* #param string $cookieName
* #return string
*/
public function getCookieValue(Request $request, $cookieName)
{
$cookies = $request->getCookieParams();
return isset($cookies[$cookieName]) ? $cookies[$cookieName] : null;
}
}

Slim 3 has Cookies class. you are not forced to use external library for setting cookie:
$setcookies = new Slim\Http\Cookies();
$setcookies->set('auth',['value' => $jwt, 'expires' => time() + $expire, 'path' => '/','domain' => 'example.com','httponly' => true,'hostonly' => false,'secure' => true,'samesite' => 'lax']);
$setcookies->set('tracking', "$value");
$response = $response->withHeader('Set-Cookie', $setcookies->toHeaders());
And for getting cookie :
$jwt = $request->getCookieParam('auth');

I'was experiencing the same problem but, after a few tries, i figured out!
First you need to use :
$cookies = Dflydev\FigCookies\Cookies::fromRequest($request);
To get all the cookies sent by the client.
Or:
$cookie = FigRequestCookies::get($request, $cookiename);
To get a single cookie.
But the 'strange' part is how to set a cookie, so here's a little example:
function setCookie($response, $name, $value){
$response = FigResponseCookies::set($response, SetCookie::create($name)
->withValue($value)
->rememberForever()
);
return $response;
}
With :
$response = FigResponseCookies::set($response, SetCookie::create($name)
->withValue($value)
->rememberForever()
);
You'll add a new cookie to the request, this method returns a new request object with the new cookie in it.
So for all the other operations, you need to use the new request not the old one.
I hope this will help.
if you want post your code and we'll try to debug it.

I know I was asked to answer for cookies on slim 3, but since I could not find anywhere how to do this on slim 4, I was telling how to do it in case it could be useful to someone else.
If you are using Slim 4 with slim/psr7 you can set cookies from inside a middleware or a router, in this way:
To SET a cookie (put a cookie on a browser):
$cookies = new \Slim\Psr7\Cookies();
$cookies->setDefaults(['hostonly' => true, 'secure' => true, 'httponly' => true, 'samesite' => 'Lax']);
$cookies->set('MyCookieName', ['value' => '', 'samesite' => 'Strict']); // this way I can ovveride the samesite attribute for this cookie only
$response=$response->withHeader('Set-Cookie', $cookies->toHeaders());
unset($cookies);
To unset a cookie (delete a cookie from a browser)
$cookies = new \Slim\Psr7\Cookies();
$cookies->setDefaults(['hostonly' => true, 'secure' => true, 'httponly' => true, 'samesite' => 'Lax']);
$cookies->set('MyCookieName', ['value' => '', 'expires' => 1); // this way I can delete this cookie, setting it already expired the first sec in 1970
$response=$response->withHeader('Set-Cookie', $cookies->toHeaders());
unset($cookies);
To get the cookie (get the cookie sent from the browser)
$cookies = new \Slim\Psr7\Cookies($request->getCookieParams());
echo "cookie value is: " . $cookies->get('MyCookieName');

The easiest way I found to do this is as follows.
use Dflydev\FigCookies\SetCookie;
use Dflydev\FigCookies\FigResponseCookies;
$app->post('/login', function ($request, $response, $args) {
// Here you may check request data
$token = '123'; // Here you may use something like JWT::encode
return $this->response = FigResponseCookies::set($response, SetCookie::create('token')
->withValue($token)
->withDomain($_SERVER['HTTP_HOST'])
->withPath('/')
)->withJson([
'description' => 'Here goes your Json Body'
]);
});

Install vendor solution:
composer require sunrise/http-header-kit
Set the session cookie:
use Sunrise\Http\Header\HeaderSetCookie;
$header = new HeaderSetCookie('name', 'value', new \DateTime('+1 day'), [
'path' => '/',
'secure' => true,
'httponly' => true,
]);
$response = $header->addToMessage($response);
See the source code to learn more:
HTTP Header Kit for PHP 7.2+ based on PSR-7

I would recommend NOT using dflydev/dflydev-fig-cookies. It's broken and the documentation is either wrong or missing.
Based on LUXS's and Norman's answers, here's a working example with comments, for Slim 3:
/**
* Fig-cookies.
*
* Mind the required classes; mind the fact that (because PSR-7) this sets the
* cookie by modifying the response before returning it.
*
* Kudos to https://stackoverflow.com/a/55288070/1717535 and
* https://stackoverflow.com/a/42065030/1717535 for providing working examples.
*
* Memo about cookines in general:
* - if you don't set an expire date, it'll be a session cookie.
* - dot or no dot before the domain?
* - if no domain is specified, the cookie will be set without a dot.
* - if a domain is specified, it'll be the dotted version.
* - if both are set, seems the one set more recently will be used on read.
* - Seems the dotted/sub-domains version comes recommended.
* - But it forces to turn https://example.org into example.org, for all
* of local dev, ngrok, production, for no obvious benefit. So screw it.
* - Reconsider the day we'll use subdomains.
* - See https://stackoverflow.com/a/39708227/1717535
*
* Can use `->withDomain` to set the domain, without URL scheme and without
* trailing slash. e.g.: `->withDomain('clickandspeak.localhost')`
*/
use Dflydev\FigCookies\FigResponseCookies;
use Dflydev\FigCookies\SetCookie;
use Dflydev\FigCookies\FigRequestCookies;
$app->get('/tests/fig-cookies/set/', function ($request, $response, $args) {
$response = FigResponseCookies::set(
$response,
SetCookie::create('foo')
->withValue('bar')
->rememberForever()
->withPath('/')
);
// Do whatever else you need to do in your route…
// Then return the response.
return $response;
});
$app->get('/tests/fig-cookies/get/', function ($request, $response, $args) {
$cookie = FigRequestCookies::get($request, 'foo');
// but this is long and ugly and I would recommend Slim's (undocumented) built-in function instead:
// $request->getCookieParam('foo')
echo $cookie->getValue();
});
As for deleting/removing a cookie… Well:
$app->get('/tests/fig-cookies/delete/', function ($request, $response, $args) {
// $request = FigRequestCookies::remove($request, 'foo');
// $response = FigResponseCookies::expire($response, 'foo');
// Works. The cookie gets deleted.
// $response = FigResponseCookies::set(
// $response,
// SetCookie::create('foo')
// ->withExpires(new DateTime('-5 years'))
// ->withPath('/') // MUST use the same path as that used when creating the cookie.
// );
/**
* This is the example given in the README. But it does NOT work.
* It won't work because the path is missing; there's no option to set it!
* See https://github.com/dflydev/dflydev-fig-cookies/issues/23
*/
// $response = FigResponseCookies::expire($response, 'foo');
return $response;
});

I don't know if it will help anyone 4 years later but...
You can use the FIG Cookies library, turning it into a class with static functions. Like this:
namespace YourApp\Cookies;
use Dflydev\FigCookies\FigResponseCookies;
use Dflydev\FigCookies\SetCookie;
use Dflydev\FigCookies\FigRequestCookies;
use Dflydev\FigCookies\Modifier\SameSite;
use Carbon\Carbon; // I used Carbon as well
class Cookie
{
static function get(&$req, $key, $default = null)
{
$cookie = FigRequestCookies::get($req, $key, $default);
if (!$cookie->getValue()) {
return null;
}
return $cookie->getValue();
}
static function set(&$res, $key, $val, $expire_val, $expire_unit)
{
$now = Carbon::now();
$offset = Carbon::now()->add($expire_val, $expire_unit);
$res = FigResponseCookies::set($res, SetCookie::create($key)
->withValue($val)
->withExpires($offset->toCookieString())
->withMaxAge($offset->diffInSeconds($now))
->withPath('/')
->withDomain('appdomain.com')
->withSecure(false)
->withHttpOnly(true)
->withSameSite(SameSite::lax())
// You can learn more about the available options on the official GitHub page
);
return $res;
}
static function remove(&$res, $key)
{
$offset = Carbon::now()->sub(10, 'years');
$res = FigResponseCookies::set($res, SetCookie::create($key)
->withExpires($offset->toCookieString())
->withMaxAge(0)
->withPath('/')
->withDomain('appdomain.com')
);
return $res;
}
}
This way, it becomes really easy to deal with cookies.
You can use it like this:
use YourApp\Cookies\Cookie;
Cookie::set($response, 'name', 'value', 1, 'month') // To create a cookie
Cookie::get($request, 'name') // To get the value of a cookie
Cookie::remove($response, 'name') // To remove it
Or, if you prefer, like this:
\YourApp\Cookies\Cookie::set($response, 'name', 'value', 1, 'month')
\YourApp\Cookies\Cookie::get($request, 'name')
\YourApp\Cookies\Cookie::remove($response, 'name')
That's the way I use it.

Related

GuzzleHttp and Memcached key

I'm playing around with the GuzzleHttp client, GuzzleCacheMiddleware and Memcached.
The setup is calling the same url with different parameters.
This results in one! memcached hit, so I think the memcached key is created from the url and only the url.
Can I somehow change this behaviour, so the key includes a md5 of the parameters?
You would have to create your own CacheStrategy class. For example you can extend PrivateCacheStrategy class and override getCacheKey method which is responsible for creating the cache key.
https://github.com/Kevinrob/guzzle-cache-middleware/blob/master/src/Strategy/PrivateCacheStrategy.php#L123
You are right that it creates storage key based on only the URL and request method.
Decided to look into it. You are right that it needs GreedyCacheStrategy because it literally caches everything regardless of any RFC standards.
Custom class for cache key creating.
class ParamsGreedyCacheStrategy extends GreedyCacheStrategy
{
/**
* Ignoring any headers, just straight up cache key based on method, URI, request body/params
*
* #param RequestInterface $request
* #param KeyValueHttpHeader|null $varyHeaders
* #return string
*/
protected function getCacheKey(RequestInterface $request, KeyValueHttpHeader $varyHeaders = null)
{
return hash(
'sha256',
'greedy' . $request->getMethod() . $request->getUri() . $request->getBody()
);
}
}
Creating requests. I used Laravel caching here, you can use memcached. I also allow POST HTTP method to be cached, because by default only GET is being cached!
$handlerStack = HandlerStack::create();
$cacheMiddleware = new CacheMiddleware(
new ParamsGreedyCacheStrategy(
new LaravelCacheStorage(
Cache::store('file')
),
10
)
);
// Not documented, but if you look at the source code they have methods for setting allowed HTTP methods. By default, only GET is allowed (per standards).
$cacheMiddleware->setHttpMethods(['GET' => true, 'POST' => true]);
$handlerStack->push(
$cacheMiddleware,
'cache'
);
$client = new Client([
'base_uri' => 'https://example.org',
'http_errors' => false,
'handler' => $handlerStack
]);
for($i = 0; $i < 4; $i++) {
$response = $client->post('/test', [
'form_params' => ['val' => $i]
]);
// Middleware attaches 'X-Kevinrob-Cache' header that let's us know if we hit the cache or not!
dump($response->getHeader('X-Kevinrob-Cache'));
}

Symfony cookie not sent (but in Response Header)

I can't understand why my cookie isn't sent.
I've check all the thread about it and it seems that I'm doing it right.
I can't see the cookies in the Symfony debug, but not on my browser.
public function indexAction(Request $request)
{
$response = new Response();
$userID = $request->cookies->get('myCookie123');
if (empty($userID)) {
$uniqueID = $this->generateIDUtil();
$response->headers->setCookie(new Cookie('myCookie123', $uniqueID, 2147483647));
$response->sendHeaders();
}else{
var_dump('USER ALREADY KNOW <br>' );
}
var_dump($response->headers->getCookies()); //GIVES CORRECT COOKIE OBJECT
var_dump('<br>');
var_dump($request->cookies->all()); //GIVES ONLY PHPSESSID, BUT NOT THE ONE CREATED
var_dump('<br>');
var_dump($request->cookies->get('myCookie123')); //GIVES NULL
return $response->setContent($this->render('MyBundle:Core:index.html.twig'));
}
So here a working piece of code for anyone that want to get a userId from a cookie. With all the use statement and the twig rendering template.
The problem with the solution above is that it will give you a blank page as you send the header without rendering the view.
As it's really badly documented, here is a working solution.
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class tempController extends Controller
{
public function indexAction(Request $request)
{
$user = $request->cookies->get('myCookie'); // $user is a string (the userID) or null if there is no cookie.
if (!empty($user)) {
//Fetch user data in the DB
}
// some code ...
$response = new Response();
if ($user instanceof User) {
// do some stuff like pre fill a form
}else{
// We don't know the user we send a cookie.
$cookie = new Cookie('myCookie', $this->generateIDUtil(), time() + (365 * 24 * 60 * 60)); // Expires 1 years
$response->headers->setCookie($cookie);
$response->sendHeaders();
}
//Render the view WITH the response (It's very important to put $response as 3rd parameter)
return $this->render('MyBundle:Core:index.html.twig', array(/* view param */), $response);
}
}
Here is how you properly create a cookie and send as a Response to a client:
$res = new Response();
$cookie = new Cookie(
'my_cookie',
$student->getStuId(),
time() + ( 2 * 365 * 24 * 60 * 60) // Expires 2 years.
);
$res->headers->setCookie( $cookie );
$res->send();
I use it all the time, so please let us know if you still have problems.

Setting dynamic amounts securely with Paypal payments with a redirection and not button?

Ok, I haven't worked with hosted buttons before, but it makes sense as they are a lot more secure.
I have looked around and been reading the docs (which aren't all that helpful) and best help I have found so far is here; though I am still confused on where exactly to put that code?
Also, I technically don't want a "button", but the idea behind them seems what I want.
All I want to do is use the same query vars every time but just want to change the price - the price is dynamic depending on what the user selects in the form.
Additionally, I don't want a button per se, I would much prefer to redirect the user to paypal with the appropriate data but not sure how to go about doing that whilst setting a dynamic price?
If I didn't have to set a dynamic price I know I could just append the query vars for a hosted button onto a URL and then redirect to that URL, but I need to change the price and hence my question...
Ok, I finally found out that not only does the response from the BMUpdateButton API return the HTML to create a form, it also returns other data as well within the returned array.
Once you make the request it will return an array with three keys as per the BMUpdateButton Response section on the API page linked above.
These are:
WEBSITECODE
HTML code for web pages
EMAILLINK
This is what I was looking for; a plain link you can redirect users to
HOSTEDBUTTONID
The id of the button.
Be advised when altering the contents of a hosted button you need to pass all the details of the button to it as when you created it; so as an example, if you leave out passing it an item name the item name will be blank and Paypal will allow the user to set it.
Also, an important note is that when you update the button details, it isn't just updated for that users session, it updates it within your paypal account - so the new name/price etc will affect all users that attempt to use it.
If you still would like to update the details of the button you can do that with the below:
I personally started with this class:
<?php
class Paypal
{
/**
* Last error message(s)
* #var array
*/
protected $_errors = array();
/**
* API Credentials
* Use the correct credentials for the environment in use (Live / Sandbox)
* #var array
*/
protected $_credentials = array(
'USER' => 'seller_1297608781_biz_api1.lionite.com',
'PWD' => '1297608792',
'SIGNATURE' => 'A3g66.FS3NAf4mkHn3BDQdpo6JD.ACcPc4wMrInvUEqO3Uapovity47p',
);
/**
* API endpoint
* Live - https://api-3t.paypal.com/nvp
* Sandbox - https://api-3t.sandbox.paypal.com/nvp
* #var string
*/
protected $_endPoint = 'https://api-3t.sandbox.paypal.com/nvp';
/**
* API Version
* #var string
*/
protected $_version = '74.0';
/**
* Make API request
*
* #param string $method string API method to request
* #param array $params Additional request parameters
* #return array / boolean Response array / boolean false on failure
*/
public function request($method, $params = array())
{
$this->_errors = array();
if (empty($method)) { //Check if API method is not empty
$this->_errors = array('API method is missing');
return false;
}
//Our request parameters
$requestParams = array(
'METHOD' => $method,
'VERSION' => $this->_version
) + $this->_credentials;
//Building our NVP string
$request = http_build_query($requestParams + $params);
//cURL settings
$curlOptions = array(
CURLOPT_URL => $this->_endPoint,
CURLOPT_VERBOSE => 1,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem', //CA cert file
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $request
);
$ch = curl_init();
curl_setopt_array($ch, $curlOptions);
//Sending our request - $response will hold the API response
$response = curl_exec($ch);
//Checking for cURL errors
if (curl_errno($ch)) {
$this->_errors = curl_error($ch);
curl_close($ch);
return false;
//Handle errors
} else {
curl_close($ch);
$responseArray = array();
parse_str($response, $responseArray); // Break the NVP string to an array
return $responseArray;
}
}
}
?>
Credit: https://www.smashingmagazine.com/2011/09/getting-started-with-the-paypal-api/
Then I did the below:
include(dirname(__FILE__) . '/includes/paypal.class.php');
$paypal = new Paypal();
// Set our method
$method = 'BMUpdateButton';
// Set our params
$params = array(
'HOSTEDBUTTONID' => 'your_button_id',
'BUTTONTYPE' => 'BUYNOW',
'BUTTONSUBTYPE' => 'SERVICES',
'L_BUTTONVAR0' => 'item_name=Your Description',
'L_BUTTONVAR1' => 'amount=999.00',
'L_BUTTONVAR2' => 'currency_code=AUD',
'L_BUTTONVAR3' => 'cancel_return=http://www.example.com/cancel.html',
'L_BUTTONVAR4' => 'return=http://www.example.com/success.html'
);
// Make request to change button details
$result = $paypal->request($method, $params);
Note that while Paypal say that BUTTONSUBTYPE is optional, you will likely get an error if you don't include it.
You need to use their button designer if you're going to do hosted buttons.
https://www.paypal.com/us/cgi-bin/webscr?cmd=_button-designer
The security comes from IPN verification after the transaction.
See:
https://www.paypal.com/us/cgi-bin/webscr?cmd=p/acc/ipn-info-outside
Validate that IPN call is from PayPal?
The answer on this post is a better way to do it:
Dynamic PayPal button generation - isn't it very insecure?
Button code is HTML form tags based so you would easily convert it to a string query and assemble your dynamic payloads with this format:
https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=yourAccount#email.com&item_name=itemNameTest&item_number=123&amount=1&currency_code=USD&no_shipping=1
Customize it and append vars per the varliables listed HERE, and use it with your redirection method.
Button manager API is more comprehensive except it won't return you a query string URL like this, though the idea behind is identical to an HTML form code snippet

Symfony2 Cookies not being set in controller

I can't seem to get cookies set from my controller.
code:
/**
* #Route("", name="wx_exchange_default_index")
* #Template("WXExchangeBundle:Default:index.html.twig")
* #Method({"GET"})
*/
public function indexAction(Request $request)
{
$returnArray['parents'] = self::getCategories();
$cookieLocationSession = $request->cookies->get('locationidsession', 0);
$cookieLocation = $request->cookies->get('locationid', 0);
$securityContext = $this->container->get('security.context');
$hashids = $this->get("wxexchange_hashids_service");
if ($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED'))
{
$user = $securityContext->getToken()->getUser();
$returnArray['user'] = $user;
$location = $user->getTblProfile()->getTblLocation();
if(!$cookieLocation || $cookieLocation != $hashids->encrypt($location->getId()))
{
$cookieLocation = $hashids->encrypt($location->getId());
//TODO: cookies are not being set figure out whys
$response = new Response();
$response->headers->setCookie(new Cookie("locationid", $cookieLocation, 365, '/', null, false, false));
$response->sendHeaders();
}
}
if (!$cookieLocation && !$cookieLocationSession)
{
return $returnArray;
}
if ($cookieLocationSession)
{
$cookieLocation = $cookieLocationSession;
}
if (!isset($location) || $cookieLocationSession)
{
$locationService = $this->get("wxexchange_location_service");
$locationId = $hashids->decrypt($cookieLocation);
if(count($locationId) >= 1)
$location = $locationService->getLocationById($locationId[0]);
}
if(isset($location))
return $this->redirect($this->generateUrl('wx_exchange_location', array('slug' => $location->getSlug(), 'locationid' => $cookieLocation)));
return $returnArray;
}
Do I have to return the response? If I do how do I keep processing (I have a redirect further down in my code)?
Edit: Interestingly enough if the same cookie is already set (via JQuery) running the code above deletes it, but it won't set it.
Edit: Action code posted.
The cookie object has httpOnly set to true by default, http://api.symfony.com/2.0/Symfony/Component/HttpFoundation/Cookie.html
This means that the browser should not make the cookie visible to client-side scripts. If you need to see the cookie in your scripts you can pass the 7th parameter as false when you create the cookie.
$response->headers->setCookie(new Cookie('foo', 'bar',time() + 60, '/', null, false, false));
If you just need to view the cookie for debugging purposes you can use Chrome Dev tools. They are available under the 'Resources' tab.
Edit : Try $response->sendHeaders();
Oops, Sorry everyone.
It's my error.
In my javascript I'm using a Jquery cookie plugin and when you set a new cookie you tell it the number of days before expiry:
$.cookie('locationid', value, { expires: 365, path: '/' });
Unfortunately I used a part of this syntax in my controller:
$cookie = new Cookie("locationid", $cookieLocation, 365, '/', null, false, false);
The problem is the third parameter is supposed to be a DateTime so while I thought I was telling it to expire in 365 days I probably created a cookie that expired almost instantly after creation.
Thanks for all the answers and time spent on your part, this is why I love SO.

Not able to store the session for the second client request using Zend_Http_Client

I'm sending multiple requests to same client. zend_Http_Client not able to redirect because our site giving a javascript redirect. And from that javascript I'm getting the redirect url and again calling the client , now I'm getting access denied. This is beacuse I'm not able to store the session from the first client request.
I'm using the following code..
$client = new Zend_Http_Client(
$loginUrl,
array(
'keepalive' => true,
'timeout' => 1000
)
);
$response = $client->request()->getBody();
$redirectUrl = $this->_getResponseRedirectUrl($response);
$client->resetParameters();
$client->setUri($redirectUrl);
$response = $client->request()->getBody();
$resultUrl = $this->_getResponseRedirectUrl($response);
Can anybody tell me how to store the session for the second request.
Before trying the following steps make sure your server authentication is based on session cookies.
Solution Worked for me:
You need to add cookies from the first repose to the second request. In this case server consider your second request as authenticated one.In the response after login to the site your cookie will be having following set of values like cookie-name,cookie-value,Expiration Date, Path, Secure and HTTPOnly. From the cookie string explode cookie-name and cookie-value
Example Session Cookie after login response:
"JSESSIONID=DQl3NKXXmy3yntp3NW2GMlcn8pLn9PR9rl0lnR6vbtfdVpyHWdnq!598502565; path=/"
"CK_LanguageID_252085=1; expires=Friday, 23-Mar-2012 05:31:03 GMT; path=/; secure"
"CK_TimeZone_252085=4; expires=Friday, 23-Mar-2012 05:31:03 GMT; path=/; secure"
Create new cookie string for further server communication in the following pattern:
"JSESSIONID=DQl3NKXXmy3yntp3NW2GMlcn8pLn9PR9rl0lnR6vbtfdVpyHWdnq!598502565; CK_LanguageID_252085=1; CK_TimeZone_252085=4"
Adding a handy method to create cookie string from zend_http_client "Set-cookie" array.
/**
* Get clean cookie string with only name,value pair
* This method filer all the follwoing cookie information
* Expiration Date, Path, Secure and HTTPOnly
* #access public
* #param {Array} $cookies
* #return {String} $cookieString
*/
public function getCookieString(array $cookies){
$cookieString = null;
foreach($cookies as $cookie){
$part = explode(';',$cookie);
$cookieString = ($cookieString == null)? $part[0] : $cookieString . '; ' . $part[0];
}
return $cookieString;
}
Using Zend_Http_Client making consecutive requests:
//Login
$client = new Zend_Http_Client($loginUrl);
$response = $client->request();
//Get Header from response
$headers = $response->getHeaders();
//Create second header
$header = array("Cookie" => $this->getCookieString($headers["Set-cookie"]));
$client->setHeaders($header);
//Second request
$client->setUri($redirectUrl);
$response = $client->request();
Here I am removing "$client->resetParameters();" because you are not setting any GET Params using "$client->setParameterGet()"(Same for POST as well)
If using "$client->setParameterGet()" or "$client->setParameterPost()" use "$client->resetParameters();" before setting second uri.
$client->resetParameters() accepts boolean values:
FALSE : This is the default value which reset POST and GET Params only.
TRUE : Reset all the params including headers,last request and last response.
Actuall, Zend_Http_Client provides a very simple way to do what you've done, no need to reinvent the wheel here.
$client = new Zend_Http_Client(
$loginUrl,
array(
'keepalive' => true,
'timeout' => 1000
)
);
// this is the magic line...
$client->setCookieJar();
$response = $client->request()->getBody();
$redirectUrl = $this->_getResponseRedirectUrl($response);
$client->resetParameters();
$client->setUri($redirectUrl);
$response = $client->request()->getBody();
$resultUrl = $this->_getResponseRedirectUrl($response);
Read more here: http://framework.zend.com/manual/en/zend.http.cookies.html

Categories