Settng PHP cookies while using custom header for Apache Indexes - php

I've searched everywhere, but was not able to find any info on this.
Here is the situation:
I am using a PHP file as "HeaderName" for my webspace:
.htaccess has the following:
Options +Indexes
HeaderName /.resource/header.php
in header.php I am including (first thing, before echoing any data) a small include that checks for presence of a parameter and sets a cookie:
if (isset($_GET['css_style']) && $_GET['css_style'] != "") {
$css_style = $_GET['css_style'];
if (setcookie('css_style', $css_style, 0, "/", "xxx.xxxx.xxx") !== false) {
echo "<!-- cookie set! ".$css_style." -->";
} else {
echo "<!-- cookie NOT set! ".$css_style." -->";
}
}
Now, I am using this snippet in other PHP pages on the same site, in any directory, the cookie always get set when I expect it to. It is listed in the Browser's cookie list and contains the desired value.
However, when the same script gets executed as part of the automatic indexing in header.php, I get the "cookie set" output, so I know that the correct conditions all apply, but the cookie is not present in the Browser's cookie list. if I call header.php directly, then the cookie gets set and is present on the browser's list.
So my question: Does Apache do something that might prevent a cookie from being dropped? The site is running on Apache in a hosted environment, but I don't have access to the central server config.
I've tried various different ways to set the cookie, with defaults, with an expire of 0 or time() + 3600*24, with and without a path and domain, no luck. I'm stumped. Especially since it works with a regular file placed in the same directory as the index I am looking at.

You want to decide by to Query Params if you want to sent a cookie
The mod_index creates text/* but no headers
You can use mod_headers for sending cookies:
http://httpd.apache.org/docs/current/mod/mod_headers.html
and mod_setenfif for conditional sending:
http://httpd.apache.org/docs/current/mod/mod_setenvif.html

Related

Cookie is present in browser, but php $_COOKIE is empty

I have a project that works on a local server but not on my production server, due to cookies not being seen by the server. I've made a minimal version of the code that reproduces the issue on that server:
<?php
if(!isset($_COOKIE['foo'])){
setcookie('foo', 'bar', time() + 7*24*60*60, '/');
echo "Cookie was not found, so we just created it.";
} else {
echo "Cookie was found!";
}
?>
No matter how many times I refresh this page, I always get the "not found" message. Whenever I try to log the $_COOKIE variable, I get an empty Array. However:
The cookie is present in the browser, and correctly sent with the request
The cookie is set and read in the same file (it's not an issue with the path)
There is no output before setcookie, and the file is encoded in UTF8 without BOM
I think this is a server configuration issue, since the code works locally, but I have no idea where to look. Has anyone seen this before, do you know what could cause this?
If you need more info, just tell me and I'll add it to my question. Thank you!
If there's a cache server or CDN involved, it may be filtering cookies based on a whitelist. This is to improve caching, since each request with a unique set of cookies would need to be regarded as different from other requests and could not be cached (you may receive a different reply from the server based on your cookies, so the cache server cannot serve you the cached response of a previous client). Since lots of services are setting cookies which may be sent to the server (e.g. analytics packages) but have absolutely no influence on the contents of the response, heeding all cookies by default would often completely subvert caching.
Configure the caching server in charge to specifically pay attention to your cookie and to forward it to the origin server. If you have a lot of different cookies, consider giving them a common prefix and whitelist that (e.g. foo-*).
I just dealt with the same issue, my production server was allowing me to create a browser cookie using setcookie('cookieNameHere', $cookieValueHere, time() + (86400 * 365), "/"), but the $_COOKIE variable was always an empty array.
The issue was that my production server blocked direct access to the$_COOKIE variable contents via PHP for security reasons.
My solution was to access the cookie value via JavaScript using the following function:
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
I continued to create/update the cookie via PHP.
FYI, I was working on a WordPress site hosted on WP-Engine. See this page for an in depth explanation, and for other options in the event you absolutely need to access a cookie value via PHP (ADMIN-AJAX calls, etc).
I've had similar problem, and it turned out to be HAProxy configuration issue. Do you have any load balancer between the server and the user?
I think your problem is the server time. Check your time with time() function and compare with local time. Maybe one of them is wrong.

PHP session not working when script included in SHTML pages

Just a newbie here so please pardon my mistakes.
I'm working on a website using .shtml pages (SSI).
I'm trying to include a PHP script into my .shtml page.
Up to this point everything is working fine:
PHP script gets included and it does what it was intended for.
Here is the actual example.
There is the home page (index.shtml) including a script called security_check.php with this directive:
<!--#include virtual="includes/security_check.php?idOp=000&idPage=0000" -->
This is the PHP code for security_check.php:
<?php
session_start();
include('config.php');
include('myfunctions.php');
include('security_functions.php');
$idOp = $_GET['idOp'];
$idPage = $_GET['idPage'];
$allowedReferer = array();
// Connection to the database (defined in myfunctions.php)
$link = DB_Connect($DBhost, $DBuser, $DBpass, 1, $DBname);
// Check if the PHP session already exists. If not, create one
// (that is insert a record in the DB and returns the id, which
// will be stored in the PHP session variable).
// user ID is 0 because not logged yet
if (!isset($_SESSION['idSess'])) {
$_SESSION['idUser'] = 0;
$_SESSION['idSess'] = create_session(); // security_functions.php
}
// Please note that create_session() correctly use $_SESSION['idUser']
// in order to do its work, even if it's not passed as a parameter
// (as it should be: $_SESSION is a superglobal!) and the same goes
// for activity_supervisor().
// Defined in security_functions.php:
// it uses both $_SESSION['idUser'] and $_SESSION['idSess']
activity_supervisor($idPage,$allowedReferer,2,$link);
mysql_close($link);
?>
At this point,
home page is correctly displayed and there is a 'Sign up' button
in it, calling sign.shtml.
This sign.shtml page include the very same security_check.php script
with the exact same include directive already seen above except for the value of idPage parameter which in this case is 0001.
I would expect the script to recognize the PHP session and therefore
not creating a new session, but indeed a new session gets created every time.
I already read every other post related to PHP sessions not working and I even tried the solutions proposed there.
- session_start() is written on top of every script because there is just one script
- session.save_path equals to /var/lib/php/session and is writeable by the web server
- I already tried to set session.gc_probability = 0 and restarting the web server (to no avail, so I got back to session.gc_probability = 1)
- I tried with different browsers (namely, Firefox and Chrome) with the same results
So I tried the following test (note those two empty lines BEFORE session_start(): I always space instructions this way to improve readability)
creating a simple test.php script
<?php
session_start();
if (!isset($_SESSION['foo'])) {
$_SESSION['foo'] = 1;
echo ('Value is '.$_SESSION['foo'].'<br/>');
echo ('Refresh');
}
else {
$_SESSION['foo']++;
echo ('Value is '.$_SESSION['foo'].'<br/>');
echo ('Refresh');
}
?>
Well, believe it or not, every time I hit 'Refresh', the value
is incremented, so PHP recognize the session (the test.php script is inside the same domain as the index.shtml and sign.shtml pages).
I even tried to make the PHP script to show a link to a .html file (not .shtml) which then show a link to test.php. It works correctly!
It really seems that the session is not correctly set only when the PHP script is included into the .shtml page, even if I don't see any reason for that. Maybe you know why and, above all, how to circumvent this boring behaviour? Is it a feature? Does it depend on a parameter setting in php.ini?
Final tips:
OS: CentOS 6.3 with 2.6.32-279.el6.x86_64 kernel
Server version: Apache/2.2.15 (Unix)
PHP 5.3.3
Server is mine so I can configure everything, if needed.
Thanks in advance and forgive me for the long post: I tried to make it
clear that PHP sessions do work perfectly in every other situation I know of.
I don't think this will work because the SSI will execute the PHP script, and then send out its output to the web server. You would need some way of rewriting URLs so that they do not rely on cookies, since cookies get "eaten" before the server gets to send them to the browser.
Try using
ini_set("session.use_cookies",0);
ini_set("session.use_trans_sid",1);
and then you'll need to send the SID in the outgoing URLs (and on POST pages, too). See this answer for example.
Specifically, you need to redirect the user not to sign.shtml but to something like
$sidkey = session_name();
$sidval = session_id();
print "sign up: here";
and include this in the SSI output.
UPDATE: the root of the problem is that the SSI cannot create a session (cannot send anything but plain HTML. Sessions that use cookies rely on headers, not HTML only). But if you create the session with a PHP script launched outside SSI, that is able to set a cookie, from that point onwards all PHP scripts (whether SSI or not) are able to read the cookie and therefore will be able to access and modify the session (which is a file/memory/Redis/other on the server identified by the session cookie's value).
You can check whether a cookie is set in SSI, and if it not, you can redirect to a pure PHP page that sets the session cookie and sends back to the original shtml using a HTTP Redirect.

Can cookies created by one php web page can be deleted by another php webpage?

I have created one php web page which creates a cookie. That web page redirects the user on another (second) php web page. On this second web page I'm trying to delete the cookie which is created by the first page. But cookie is not getting deleted. And the second web page shows an error like "can not modify header information"
My php code format for deleting that cookie is like:
if(isset($_COOKIE['cookieName']))
{
setCookie('cookieName','values',time()-3600,'/','example#domain.com',0);
}
I hope you are making use of unset()
Do like this
if(isset($_COOKIE['cookieName']))
{
unset($_COOKIE['cookieName']));
}
Can you try this,
unset($_COOKIE['cookieName']);
setcookie('cookieName', null, -1, '/');
Path:
The path on the server in which the cookie will be available on. If set to '/', the cookie will be available within the entire domain. If set to '/foo/', the cookie will only be available within the /foo/ directory and all sub-directories such as /foo/bar/ of domain. The default value is the current directory that the cookie is being set in.
Domain:
The domain that the cookie is available to. Setting the domain to 'www.example.com' will make the cookie available in the www subdomain and higher subdomains. Cookies available to a lower domain, such as 'example.com' will be available to higher subdomains, such as 'www.example.com'.
Setting cookies is done in the HTTP header. This header is sent before the actual content of the page. As a result, you can only (un)set the cookie of you have not yet sent any output.
This is also stated in the setcookie documentation:
Like other headers, cookies must be sent before any output from your
script (this is a protocol restriction). This requires that you place
calls to this function prior to any output, including and
tags as well as any whitespace.
For example:
<?php
if (isset($_COOKIE['cookieName'])) {
unset($_COOKIE['cookieName']);
setcookie("cookieName", "", time()-3600);
}
?>
<html>
....
</html>
(Also see the question Remove a cookie.)

PHP cannot read cookies from Chrome in certain cases

This issue appeared today and it seems to have something to do with webkit.
On pages that redirect via location [301/302] HTTP headers (404 error pages in this case) PHP cannot read the cookies - meaning the $_COOKIE is an empty array.
I'm aware of the webkit bug that using Set-Cookie and Location header in the same response breaks, but this is about reading not writing so it's supposed to be in the request headers.
I'm using the latest Chrome v26. On the backend I have PHP 5.3.10-1ubuntu3.6 on my home server, and the exact same on a production server (which i did not set up and it's not on default settings). On the production server I cannot read the cookies as I said before but on my home/dev server I can.
And it gets worse: On another server which runs PHP 5.3.3-7+squeeze14 I also can't read the cookies if the Content-Type header is not html, but text/plain.
I set the cookies the following way:
if (setcookie($name, $value, $expire, $path, null, isset($_SERVER['HTTPS']), $httponly))
{
$_COOKIE[$name] = $value;
return true;
}
return false;
$httponly is false
$path is '/'
the name consists of lowercase letters
the value consists of numbers and dashes
I can see the cookie in the Developer Tools / Resources tab and it works fine on simple html pages.
I appreciate any help.
Thanks.
the redirect page and the redirector page are at the same domain? Maybe this can being considered as a XSS attempt to stealing cookies. Try to send "Access-Control-Allow-Origin: *" header:
header("Access-Control-Allow-Origin: *" );
In my case, the problem was with session_set_cookie_params(), the parameter for the domain (the 3rd argument) was prefixed with a period ., such as ".localhost". When I removed the ., $_COOKIE variable was populated.

Cannot access cookies in Chrome, works properly in Firefox

Basic situation and basic relevant info:
I have a php code that executes before the opening <doctype> tag. The hope was to (if necessary) send a redirect based on user's browser's language preferences before anything else loads.
The script attempts to do two things based on highest supported language preference:
Use php: setcookie() to create a cookie with the two-letter language code.
Example cookie name = value: x_language = es
Use php: header("Location: " . $requestedSite); to redirect to a subdomain,
Example domain: es.domain.com
Example:
if (isset($_COOKIE['x_language'])) {
-Determine correct subdomain based on cookie value-
-If not currently on that subdomain, redirect to it-
} else {
setcookie('x_language','es',time() + 31536000 ,'/','.domain.com' );
header("Location: " . $requestedSite);
}
The problem:
Firefox works perfectly. Chrome (and other browsers) fail to recognize the cookies at all.
I've boiled it down to this:
print_r($_COOKIE) works properly in Firefox, and returns a lovely, populated array.
print_r($_COOKIE) fails in Chrome, and returns an empty array.
This is the core of the problem, my function doesn't recognize the existence of a cookie because Chrome doesn't.
I've made sure every browser accepts cookies.
I've checked dev tools to make sure the cookie is in place on all browsers, (it is).
I realize a cookie's value isn't available until the next page load, but that isn't an issue here. Even after it is set, it won't read.
There is no output above the initial setcookie();
So how do I get Chrome (and other browsers) to recognize its own cookies?! Does anyone know why this would all work flawlessly on Firefox but fail elsewhere?
On a lark I decided to try this. I created a file that only contains:
<?php
print_r($_COOKIE);
?>
Again, I see the cookie array in Firefox. Meanwhile, in Chrome, IE, Opera, Safari, I get an empty array. Could this be a server issue?
OP returns with answer:
Alright, I'm adding this as an 'Answer' in case anyone else comes across this (totally bizarre) behavior and lands here:
It turns out my hosting provider was doing some seriously aggressive caching with my WordPress site that I was unaware of.
At the time I posted my question, I didn't think being on WordPress was relevant, but apparently it was.
Basically it was doing this:
With a clean Cache:
Visitor 1 visits the site.
The php processes and produces output as expected.
Visitor 1 is served php output (based on his browser's parameters and such).
Visitor 2 visits the site. Visitor 2 sees *Visitor 1's version of the site.
The php is processed once and only once per Cache-clear.
This caching behavior meant that accessing cookies through php was simply not going to work right, but accessing them with Javascript WOULD work.
(Important note: It turns out the above-stated caching behavior is disabled for any user viewing the site while logged into wordpress, and this is common behavior for WordPress Cache plugins. That is why I was seeing different behavior in Firefox than I saw in other browsers, because I was actively logged in with Firefox. This could be a helpful piece of information for someone out there.)
My solution:
Use Javascript to run an AJAX query to a .php file which would process the language preferences of the visitor and return the output as a 2-character code, (i.e. 'en' 'es' 'pt' 'de', etc).
Using AJAX to call php allowed me to use php's server-side access to a browser's language preferences while circumventing the super-agro caching of my host.
I hope this helps someone! And thanks to everyone who tried to help me out with this.
I was not having this problem with the code below. I was able to go to example.com and be redirected immediately to en.example.com and see the cookie in $_COOKIES. If I used en.example.com?set=fr I would be redirected to fr.example.com every time I tried example.com. Hopes this is what you were looking for!
<?php
print_r($_COOKIE);
if(isset($_GET['nuke'])) {
setcookie('x_language','',time()-1000,'/','.example.com');
echo 'It has been nuked!';
exit;
} else if(isset($_GET['set'])) {
setcookie('x_language',$_GET['set'],time() + 31536000, '/','.example.com');
$_COOKIE['x_language'] = $_GET['set'];
}
if (isset($_COOKIE['x_language'])) {
$redirect = $_COOKIE['x_language'].'.example.com';
if($_SERVER['HTTP_HOST'] != $redirect)
header('Location: http://'.$redirect);
} else {
setcookie('x_language','en',time() + 31536000,'/','.example.com');
$redirect = 'http://en.example.com';
header('Location: '.$redirect);
}
echo '<br />Cookie: '.$_COOKIE['x_language'].' Domain: '.$_SERVER["HTTP_HOST"];
?>

Categories