delight-im / php-cookie Goto Github PK
View Code? Open in Web Editor NEWModern cookie management for PHP
License: MIT License
Modern cookie management for PHP
License: MIT License
This would be useful for testing if the user is able to accept cookies before attempting to use them. Thisi can prevent a lot of confusion for a new developer and the user
Hello everybody,
Thank you all for your work.
Here's my contribution: As of PHP 7.4.3RC1, setcookie
calls rawurlencode
(instead of urlencode
) for encoding the
value
parameter; as a result, the following test:
\testCookie('greeting', '¡Buenos días!');
is failing:
[Set-Cookie: greeting=%C2%A1Buenos%20d%C3%ADas%21]
FAILED: [Set-Cookie: greeting=%C2%A1Buenos+d%C3%ADas%21] !== [Set-Cookie: greeting=%C2%A1Buenos%20d%C3%ADas%21]
Have a nice day!
Bye
Please add support for the recent addition of the "Partitioned" attribute.
https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies
Hi,
I would love to use this library but the current license is show stopper for me since I need to integrate it with an application under GPLv2.
Is it possible for you to re-license or double license the library with something that does not have the same restrictions?
Hello,
PHP-Cookie is not comaptible with https://wiki.php.net/rfc/automatic_csrf_protection .
It is not possible to set:
session_start(['csrf_rewrite'=>SESSION_CSRF_POST, 'csrf_validate'=>SESSION_CSRF_POST]);
Due to "Session already" started. Any workarounds?
These 3 tests fail on PHP 5.x:
testCookie(null);
testCookie(false);
testCookie('');
In all cases it seems that the expected value is Set-Cookie: =deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0
but the library returns a empty string.
I'm not sure what have introduced the change starting PHP 7, after quick look to the changelog this bug can be related: https://bugs.php.net/bug.php?id=69523
I'm not sure how to fix this issue. Either the tests should be fixed to expect the same value in PHP 7.x and 5.x or the library should returns what PHP does.
Personally, I'm more in favor of the first solution since PHP 5.x is not conform to the RFC.
What integration possibilities are there with HTTPFoundation? Is that something this project would like to explore?
Extend http://api.symfony.com/3.1/Symfony/Component/HttpFoundation/Cookie.html?
Have an alternate addHttpHeader method that accepts a \Symfony\Component\HttpFoundation\Response?
PSRs are no mandatory requirements, not even a recommendation for general PHP development. They're just for frameworks to ensure some degree of interoperability.
Anyway, reasonable code style guidelines are always a good idea, so changes that improve the code style in this repository, ideally agreed upon before, are always welcome.
However, some rules, such as "4 spaces instead of tabs" will definitely not be implemented, as they're just a matter of taste and good arguments can be made in favor of both options.
Two separate accessors, e.g.
Cookie::buildCookieHeaderName()
Cookie::buildCookieHeaderValue(...)
// or
$cookie->getHeaderName()
$cookie->getHeaderValue()
or similar, with the old accessor then composed of the new ones, would make the Cookie
class more modular and re-usable, as seen in #8.
Hi,
I'am unavailable to append data to existing session. Here is the code:
$order = [];
if (isset($_POST['order_subdomain']) && !empty($_POST)) {
$order['order']['subdomain'] = $_POST['subdomain'];
$order['order']['title'] = $_POST['title'];
$order['order']['category_id'] = $_POST['category'];
\Delight\Cookie\Session::set('order', $order);
}
if (isset($_POST['order_domain']) && !empty($_POST)) {
$order['order']['domain'] = $_POST['domain'];
$order['order']['title'] = $_POST['title'];
$order['order']['category_id'] = $_POST['category'];
\Delight\Cookie\Session::set('order', $order);
}
if (isset($_POST['register_account']) && !empty($_POST)) {
$order['user']['name'] = $_POST['name'];
$order['user']['email'] = $_POST['email'];
$order['user']['password'] = $_POST['password'];
$order['user']['password2'] = $_POST['password2'];
\Delight\Cookie\Session::set('order', $order);
}
if (\Delight\Cookie\Session::has('order')) {
echo '<pre>';
print_r(\Delight\Cookie\Session::get('order'));
echo '</pre>';
}
Hey there!
I'm actually coming from your auth class and was stuck thinking my site was in some sort of loop when I tried to get script A to use a cURL
request to script B to pull some markup. Both pages are authenticated using the (amazing!) Auth Class.
What I found was happening was that since the fetch for script B's content was happening during script A's execution, and both pages needed to be authenticated by the one user and their respective cookie, script A had not closed off it's access to the session file, and was therefor preventing script B from opening it.
As a quick and dirty workaround, I'm just using \session_write_close()
before the cURL
request, and it's working perfectly. I've only done this as I don't think there's (a) static-method(s) yet with this class to either a), close the session using \session_write_close()
or b), suspend and resume the session.
Wondering if these are methods you'd look to incorporate, or if I should just stick with PHP's native session close method? Cheers! :)
Hello,
I'm using this library to simplify my tests for cookies that have set the secure
and httpOnly
flags.
However, regarding this specification, only the cookiename=value
is required, all other directives are optional:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives
When I'm using:
$cookie = Cookie::parse("Set-Cookie: session=myCookie");
$cookie->isSecureOnly();
I get the following error:
Error: Call to a member function isSecureOnly() on null
Same with $cookie->isHttpOnly()
.
There is an error in this regex, I think:
https://github.com/delight-im/PHP-Cookie/blob/master/src/Cookie.php#L380
I've forked your project here with the following changes:
If you're interested, I can undo the fourth change and send our fork as a pull request, which could be a basis for a version 3.x branch.
It looks like simple task, but with this library I'am not sure how to do that. Here is my code:
if (is_array($text)) {
// what's the correct way to add array to a session? array_push?
} else {
\Delight\Cookie\Session::set('text', "$text");
}
In plain world you add array into session like this:
$_SESSION['names'] = array();
array_push($_SESSION['names'],$name);
The built-in session_id()
function takes an optional ID parameter; the Session::id()
wrapper method does not, so will break in some circumstances if you try to use Session::id
as a drop in replacement for session_id
.
The constructor's parameter list is mostly the same as setcookie(), with the exception of httpOnly and secureOnly, which are swapped. Would you consider swapping them in a future version so that they align with setcookie()?
I was porting some code that was using setcookie() to using the PHP-Cookie constructor and noticed that it's very easy to miss that.
Hi, great library!
Using PHP 5.6
, I had trouble setting SameSite=None
for the session cookie , so I'm documenting this workaround in case anyone else struggles.
If possible, please comment a more efficient way to do this.
Before sending out the login response, get the cookie and add SameSite=None
to it
\ini_set('session.cookie_httponly', 1);
\ini_set('session.cookie_secure', 1);
\ini_set('session.name', 'delight_session');
// https://stackoverflow.com/questions/3230133/accessing-cookie-immediately-after-setcookie#34465594
function getcookie($name) {
$cookies = [];
$headers = headers_list();
// see http://tools.ietf.org/html/rfc6265#section-4.1.1
foreach($headers as $header) {
if (strpos($header, 'Set-Cookie: ') === 0) {
$value = str_replace('&', urlencode('&'), substr($header, 12));
parse_str(current(explode(';', $value, 1)), $pair);
$cookies = array_merge_recursive($cookies, $pair);
}
}
return $cookies[$name];
}
function withoutSamesite($cookie) {
$samesitePattern = '/samesite=[^;]+;?/i';
return preg_replace($samesitePattern, '', $cookie);
}
function setcookieSamesite($cookieName, $samesiteValue) {
$existingCookie = getcookie($cookieName);
$cookie = withoutSamesite($existingCookie);
$cookieSamesite = "$cookie ; SameSite=$samesiteValue";
header("Set-Cookie: $cookieName=$cookieSamesite");
}
$auth->login($email, $password);
set_cookie_samesite("delight_session", "None");
✅The session cookie can now be sent across domains in Chrome browsers
It's awesome that PHP finally has (strict) scalar type hints since version 7.0.
But all applications still on version 5.6 don't have this feature yet, and that version still has support for about two years.
Even more critical, another large percentage of applications is still on version 5.5 or below, but you could argue that these are now running on unsupported PHP versions and so we shouldn't support them anymore, either.
Anyway, even ignoring that, there's that large percentage of applications on PHP 5.6, and it's especially those that need support by security-enhancing components, right? So we shouldn't just drop support for PHP 5.6. The code has been carefully annotated with PHPDoc comments that include scalar type declarations, which should be a reasonable workaround until we can happily turn on scalar type hints in PHP no later than 2 years from now on.
Application security, especially with this library, does not critically depend on these type hints. They are helpful and prevent some classes of bugs, but reading the documentation carefully and adding the correct method calls should be sufficient for now (although not perfect).
The Cookie class is defined as final, so it can't be extended anymore. We would like to extend the class with some custom methods but we need to "hack" the "final" declaration before we can do that.
Is there a solid reason the Cookie class is declared as final?
Tnx!
I know we can get cookie using $_COOKIE
, but it is much better we can get the cookie using this project. so we can manage all cookies using this library.
Hi, 'SID' in documentation not explained
I'm confused if everyone should be using that exact same string.
In an example where we want to have access to current cookie values, and store new ones along with them in the same group.
Or we can use any string.
Or we should replace that with the Session ID.
Or we should try and find what the current website is using as the Session ID key in the current Cookies.
Or, something else?
[Set-Cookie: hello=world; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0]
FAILED: [Set-Cookie: hello=world; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=-1496223363] !== [Set-Cookie: hello=world; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0]
php-7.0.19-1.fc25.x86_64
PHP Roadmap.
There are use cases where you'd want that. For example, mine is: I parse a cookie from a Set-Cookie:
header, and then, before saving it, I need to check if it has an expires
or not. Currently it is not possible with your library. It could look like this:
$cookie = Cookie::parse($setCookieHttpHeader);
if ($cookie->getExpires() == null) {
modifyCookieInSomeWay($cookie);
}
$cookie->save();
I get it that hiding data is a good OOP practice, but I think that data should not be hidden.
ResponseHeader::take
replaces all headers with the given name, not just the one with the given value prefix.
This presents a problem with the Set-Cookie
header in particular: Both Session::regenerate
and Session::start
use Session::rewriteCookieHeader
to replace the existing PHPSESSID cookie with the new session ID, which in turn uses ResponseHeader::take
to grab the Set-Cookie
header. That means that by resetting the session or starting a new one, all previous calls to set cookies vanish.
Put another way:
Cookie::setcookie('somecookie', 'somevalue', time()+60*60*24*365, '/', null, true, true, Cookie::SAME_SITE_RESTRICTION_NONE);
Session::start();
and
Session::start();
Cookie::setcookie('somecookie', 'somevalue', time()+60*60*24*365, '/', null, true, true, Cookie::SAME_SITE_RESTRICTION_NONE);
produce completely different responses from the server.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.