Managing browser cookies in Symfony Panther sessions is essential for maintaining authentication, preserving session state, and handling user preferences during web scraping and browser automation.
Setting Up a Panther Client
First, create a Panther client instance to interact with web pages:
use Symfony\Component\Panther\PantherTestCase;
use Symfony\Component\BrowserKit\Cookie;
// For testing environments
$client = PantherTestCase::createPantherClient();
// For standalone applications
$client = \Symfony\Component\Panther\Client::createChromeClient();
Cookie Operations
Getting Cookies
Retrieve all cookies from the current session:
// Get all cookies
$cookies = $client->getCookieJar()->all();
foreach ($cookies as $cookie) {
echo sprintf(
"Name: %s, Value: %s, Domain: %s, Path: %s\n",
$cookie->getName(),
$cookie->getValue(),
$cookie->getDomain(),
$cookie->getPath()
);
}
// Get a specific cookie by name
$specificCookie = $client->getCookieJar()->get('session_id');
if ($specificCookie) {
echo "Session ID: " . $specificCookie->getValue();
}
Setting Cookies
Create new cookies or modify existing ones:
// Basic cookie
$client->getCookieJar()->set(new Cookie('user_preference', 'dark_mode'));
// Cookie with additional attributes
$client->getCookieJar()->set(new Cookie(
'auth_token',
'abc123xyz',
time() + 3600, // expires in 1 hour
'/', // path
'example.com', // domain
true, // secure (HTTPS only)
true // HTTP only
));
// Session cookie (no expiry)
$client->getCookieJar()->set(new Cookie('temp_data', 'value123'));
Removing Cookies
Remove cookies from the session:
// Remove a specific cookie
$client->getCookieJar()->expire('cookie_name');
// Clear all cookies for the current domain
$client->getCookieJar()->clear();
Practical Examples
Authentication Flow Example
use Symfony\Component\Panther\PantherTestCase;
use Symfony\Component\BrowserKit\Cookie;
class AuthenticatedScrapingTest extends PantherTestCase
{
public function testLoginAndScrape()
{
$client = static::createPantherClient();
// Navigate to login page
$crawler = $client->request('GET', 'https://example.com/login');
// Fill and submit login form
$form = $crawler->selectButton('Login')->form();
$form['username'] = 'your_username';
$form['password'] = 'your_password';
$client->submit($form);
// Check if authentication cookie was set
$authCookie = $client->getCookieJar()->get('auth_session');
if ($authCookie) {
echo "Authenticated with session: " . $authCookie->getValue();
}
// Now scrape protected content
$protectedPage = $client->request('GET', 'https://example.com/dashboard');
$data = $protectedPage->filter('.user-data')->text();
return $data;
}
}
Cookie Persistence Across Sessions
class CookiePersistenceExample
{
private $cookieFile = 'cookies.json';
public function saveCookies($client)
{
$cookies = $client->getCookieJar()->all();
$cookieData = [];
foreach ($cookies as $cookie) {
$cookieData[] = [
'name' => $cookie->getName(),
'value' => $cookie->getValue(),
'domain' => $cookie->getDomain(),
'path' => $cookie->getPath(),
'expires' => $cookie->getExpiresTime(),
'secure' => $cookie->isSecure(),
'httpOnly' => $cookie->isHttpOnly()
];
}
file_put_contents($this->cookieFile, json_encode($cookieData));
}
public function loadCookies($client)
{
if (!file_exists($this->cookieFile)) {
return;
}
$cookieData = json_decode(file_get_contents($this->cookieFile), true);
foreach ($cookieData as $data) {
$cookie = new Cookie(
$data['name'],
$data['value'],
$data['expires'],
$data['path'],
$data['domain'],
$data['secure'],
$data['httpOnly']
);
$client->getCookieJar()->set($cookie);
}
}
}
Working with CSRF Tokens
public function handleCsrfProtectedForm()
{
$client = static::createPantherClient();
// Navigate to form page
$crawler = $client->request('GET', 'https://example.com/form');
// Extract CSRF token from meta tag or hidden input
$csrfToken = $crawler->filter('meta[name="csrf-token"]')->attr('content');
// Set CSRF token as cookie if required
$client->getCookieJar()->set(new Cookie('csrf_token', $csrfToken));
// Submit form with CSRF protection
$form = $crawler->selectButton('Submit')->form();
$form['_token'] = $csrfToken;
$client->submit($form);
}
Best Practices
Cookie Validation and Error Handling
public function validateAndSetCookie($client, $name, $value, $domain = null)
{
try {
// Validate cookie name and value
if (empty($name) || empty($value)) {
throw new InvalidArgumentException('Cookie name and value cannot be empty');
}
// Create and set cookie
$cookie = new Cookie($name, $value, 0, '/', $domain);
$client->getCookieJar()->set($cookie);
// Verify cookie was set
$setCookie = $client->getCookieJar()->get($name);
if (!$setCookie) {
throw new RuntimeException("Failed to set cookie: {$name}");
}
return true;
} catch (Exception $e) {
error_log("Cookie error: " . $e->getMessage());
return false;
}
}
Cookie Debugging
public function debugCookies($client)
{
$cookies = $client->getCookieJar()->all();
echo "=== Cookie Debug Information ===\n";
echo "Total cookies: " . count($cookies) . "\n";
foreach ($cookies as $cookie) {
echo sprintf(
"Cookie: %s = %s [Domain: %s, Path: %s, Expires: %s, Secure: %s, HttpOnly: %s]\n",
$cookie->getName(),
$cookie->getValue(),
$cookie->getDomain() ?: 'current',
$cookie->getPath() ?: '/',
$cookie->getExpiresTime() ? date('Y-m-d H:i:s', $cookie->getExpiresTime()) : 'session',
$cookie->isSecure() ? 'yes' : 'no',
$cookie->isHttpOnly() ? 'yes' : 'no'
);
}
}
Important Considerations
- Domain Scope: Cookies are domain-specific. Setting a cookie for one domain won't affect requests to other domains
- Session Isolation: Each Panther client instance maintains its own cookie jar. Cookies don't persist between different client instances
- Security: Always use secure cookies (HTTPS) and HttpOnly flags when handling sensitive data
- Expiration: Session cookies are automatically cleared when the client is destroyed
- Privacy Compliance: Ensure compliance with privacy regulations (GDPR, CCPA) when handling user cookies