检查是否启用了Cookies

86

我正在处理一个需要使用JavaScript和会话的页面。我已经有代码来警告用户如果JavaScript被禁用了。现在,我想处理禁用cookie的情况,因为会话ID存储在cookie中。

我想到了几个方法:

  1. 将会话ID嵌入链接和表单中
  2. 警告用户必须启用cookie(需要帮助检测是否禁用了cookie)

如何最好地解决这个问题?谢谢

编辑

根据所提供的文章,我得出了自己的方法,并认为我应该分享一下,可能有人需要,也许我会得到一些评论。(假设您的PHP会话存储在名为PHPSESSID的cookie中)

<div id="form" style="display:none">Content goes here</div>
<noscript>Sorry, but Javascript is required</noscript>
<script type="text/javascript"><!--
if(document.cookie.indexOf('PHPSESSID')!=-1)
   document.getElementById('form').style.display='';
else
   document.write('<p>Sorry, but cookies must be enabled</p>');
--></script>

3
将会话 ID 嵌入链接中是可行的,但比较混乱。这意味着您正在向搜索引擎展示会话 ID。这也意味着分享链接的人可能会登录到相同的会话中。 - TRiG
你能否将问题的标题更新为类似于“使用JavaScript检查是否启用了Cookie”? - imme
那不是问题的关键, 请阅读整个问题。JavaScript只是回答问题的方式。 - steveo225
10个回答

102

JavaScript

在 JavaScript 中,您可以简单地测试cookieEnabled属性,在所有主要浏览器中都受支持。如果您使用的是旧版浏览器,可以设置一个 cookie 并检查其是否存在。(引用自Modernizer):

if (navigator.cookieEnabled) return true;

// set and read cookie
document.cookie = "cookietest=1";
var ret = document.cookie.indexOf("cookietest=") != -1;

// delete cookie
document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";

return ret;

PHP

在PHP中,这相当“复杂”,因为你必须刷新页面或者重定向到另一个脚本。这里我将使用两个脚本:

somescript.php

<?php
session_start();
setcookie('foo', 'bar', time()+3600);
header("location: check.php");

check.php

<?php echo (isset($_COOKIE['foo']) && $_COOKIE['foo']=='bar') ? 'enabled' : 'disabled';

16
如果您能扩展您的回答并解释一些那些链接另一端的技术,同时保留链接供参考,那将非常有帮助。如果不这样做,答案就有可能因为链接失效而失去作用,而且这些类型的链接通常会突然消失。谢谢。 - Kev
1
不需要重定向,请参见我下面的答案。您可以在“不重新加载”的情况下检查启用了哪些cookie。 - Codebeat
第二个链接里面有恶意软件吗?“PHP和Cookies,完美搭配!”为什么它要求我安装一个可怕的浏览器扩展程序? - Miguel Valencia
@MiguelValencia:这个网站似乎已经不存在了,我已经删除了链接。 - Sascha Galley
感谢您清晰简明的回答。现在Modernizer建议不再使用navigator.cookieenabled:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cookies.js - joshterrell805
注意:当浏览器配置为阻止第三方cookie时,在第三方iframe内调用navigator.cookieEnabled,Safari、Edge Spartan和IE将返回true(在此情况下尝试设置cookie会失败)。而Firefox和基于Chromium的浏览器则返回false。https://developer.mozilla.org/en-US/docs/Web/API/Navigator/cookieEnabled - csandreas1

17

如果使用isset($_COOKIE["cookie"])来检查是否启用了cookie,你需要进行页面刷新才能得到结果。 我是这样做的(基于cookie的会话):)

session_start();
$a = session_id();
session_destroy();

session_start();
$b = session_id();
session_destroy();

if ($a == $b)
    echo"Cookies ON";
else
    echo"Cookies OFF";

2
这是目前为止最简单和最好的例子!一个注释:在执行此操作之前,首先检查会话是否已启动,并在测试完成时保持其启用。 - Codebeat
请查看我在此页面上修改并更加健壮的答案! - Codebeat
11
只有在刷新后才能起作用!在第一次加载时,它总是显示“关闭Cookie” ,因为没有办法在不至少与浏览器交换一个请求的情况下测试Cookie是否启用。 Cookie作为每个请求的头部信息的一部分出现,而Cookie操作则是通过响应头部完成的。这是无法避免的。 - Pavel

11

回答一个老问题,这篇新帖子发布于2013年4月4日。

为了补充@misza的答案,这里提供一种高级方法来检查是否启用了cookie而不需要重新加载页面。@misza的问题在于,当php ini设置session.use_cookies不为真时,它并不总是有效。此外,该解决方案还未检查会话是否已经启动。

我编写了这个函数,并在不同的情况下多次测试,它可以很好地完成任务。

    function suGetClientCookiesEnabled() // Test if browser has cookies enabled
    {
      // Avoid overhead, if already tested, return it
      if( defined( 'SU_CLIENT_COOKIES_ENABLED' ))
       { return SU_CLIENT_COOKIES_ENABLED; }

      $bIni = ini_get( 'session.use_cookies' ); 
      ini_set( 'session.use_cookies', 1 ); 

      $a = session_id();
      $bWasStarted = ( is_string( $a ) && strlen( $a ));
      if( !$bWasStarted )
      {
        @session_start();
        $a = session_id();
      }

   // Make a copy of current session data
  $aSesDat = (isset( $_SESSION ))?$_SESSION:array();
   // Now we destroy the session and we lost the data but not the session id 
   // when cookies are enabled. We restore the data later. 
  @session_destroy(); 
   // Restart it
  @session_start();

   // Restore copy
  $_SESSION = $aSesDat;

   // If no cookies are enabled, the session differs from first session start
  $b = session_id();
  if( !$bWasStarted )
   { // If not was started, write data to the session container to avoid data loss
     @session_write_close(); 
   }

   // When no cookies are enabled, $a and $b are not the same
  $b = ($a === $b);
  define( 'SU_CLIENT_COOKIES_ENABLED', $b );

  if( !$bIni )
   { @ini_set( 'session.use_cookies', 0 ); }

  //echo $b?'1':'0';
  return $b;
    }

使用方法:

if( suGetClientCookiesEnabled())
 { echo 'Cookies are enabled!'; }
else { echo 'Cookies are NOT enabled!'; }

重要提示: 当PHP没有正确的设置时,该函数会暂时修改PHP的ini设置,并在未启用时还原它。这只是为了测试是否启用了cookie。如果您启动会话并且php ini设置session.use_cookies具有不正确的值,则可能会出现问题。为确保会话正常工作,请在启动会话之前检查和/或设置它,例如:

   if( suGetClientCookiesEnabled())
     { 
       echo 'Cookies are enabled!'; 
       ini_set( 'session.use_cookies', 1 ); 
       echo 'Starting session';
       @start_session(); 

     }
    else { echo 'Cookies are NOT enabled!'; }

Erwinus,您能否详细解释一下您所说的“当您启动会话并且php ini设置session.use_cookies具有不正确的值时,可能会出现问题”是什么意思?哪个值可能是不正确的?我正在尝试实现您的想法,但不确定我需要将我的php ini设置为什么...谢谢! - Sebastian
2
@Sebastian:如果您在检查cookie是否启用之前启动了会话,并且例如session.use_cookies为FALSE,则可能会失败。为确保其正常工作,您必须在启动任何会话之前先调用testfunction suGetClientCookiesEnabled()进行测试。您理解清楚吗?希望能帮到您。 - Codebeat
不幸的是,第一次调用网站时它不起作用,例如在隐身模式下尝试。在第一次调用网站之后,您可以期望$_COOKIE['PHPSESSID']被设置并证明启用了cookie,但在第一次调用时它为空 - 使用您的方法仍然会每次获得新的会话ID,这并不能证明任何事情。 - Rob
@Rob:我认为你做错了一些事情。在开始任何其他会话之前,您必须检查是否启用了cookie。请参见对Sebastian的评论以及答案中的“重要提示”。出于安全原因,最好将会话名称重命名为:ini_set('session.name','your name')和ini_set('session.use_only_cookies',true); 和ini_set('session.use_trans_sid',false); - Codebeat
3
你没有尝试吗?为了证明我所说的,请尝试:
  1. 创建一个包含你回答中的代码的 php 文件。
  2. 在 Chrome 中打开一个新的“隐身窗口”。
  3. 直接浏览到 php 测试文件。
第一次调用会显示:“未启用 Cookie!”。 第二次调用会显示:“已启用 Cookie!”。我只是在指出这一点。不幸的是,这使得你的代码有点浪费时间,因为在第二次调用时,你可以检查 $_COOKIE['PHPSESSID'] 是否被填充-如果被填充了,则说明 Cookie 已启用。
- Rob

9
一个透明、干净、简单的方法,使用PHP检查cookie是否可用,并利用AJAX透明重定向,因此不会触发页面重新加载。它也不需要会话。
客户端代码(JavaScript):
function showCookiesMessage(cookiesEnabled) {
    if (cookiesEnabled == 'true')
        alert('Cookies enabled');
    else
        alert('Cookies disabled');
}

$(document).ready(function() {
    var jqxhr = $.get('/cookiesEnabled.php');
    jqxhr.done(showCookiesMessage);
});

(JQuery的AJAX调用可以用纯JavaScript的AJAX调用来代替)

服务器端代码(PHP)

if (isset($_COOKIE['cookieCheck'])) {
    echo 'true';
} else {
    if (isset($_GET['reload'])) {
        echo 'false';
    } else {
        setcookie('cookieCheck', '1', time() + 60);
        header('Location: ' . $_SERVER['PHP_SELF'] . '?reload');
        exit();
    }
}

第一次调用脚本时,设置了 cookie 并告诉浏览器重定向到自身。浏览器会透明地执行此操作。由于在 AJAX 调用范围内完成,因此不会发生页面重新加载。 第二次调用时,如果收到 cookie,则脚本响应 HTTP 200(带有字符串“true”),因此调用showCookiesMessage函数。
如果脚本被第二次调用(通过“reload”参数标识),并且未收到 cookie,则响应带有字符串“false”的 HTTP 200,并调用showCookiesMessage函数。

1
这种方法适用于大多数设备,但如果禁用了JavaScript,它将变得不稳定。 - ppp

6

在同一页面的加载过程中,您不能设置和检查cookie,必须执行重新加载页面:

  • PHP在服务器上运行;
  • Cookie在客户端上。
  • 只有在页面加载期间,才会向服务器发送Cookie。
  • 刚创建的Cookie尚未发送到服务器,并且仅在下一页加载时发送。

可以的,看我的回答。 - Codebeat
谢谢Martijn。我正在学习中,感谢您的确认。由于您的第一点,我发现在PHP脚本中设置或读取cookie的整个想法非常令人困惑。按照PHP手册的说法,只要在<html>标签之前执行setcookie(),它就会在你立即读取一行代码后出现,这对我来说似乎几乎不可能,除非我漏掉了什么重要的东西。坦率地说,您最后一点发生的机制仍然是一个谜团。我希望我能找到一个明确的解释,说明这是如何工作的。 - Randy

2
你可以进行Ajax调用(注意:此解决方案需要JQuery):
例子.php
<?php
    setcookie('CookieEnabledTest', 'check', time()+3600);
?>

<script type="text/javascript">

    CookieCheck();

    function CookieCheck()
    {
        $.post
        (
            'ajax.php',
            {
                cmd: 'cookieCheck'
            },
            function (returned_data, status)
            {
                if (status === "success")
                {
                    if (returned_data === "enabled")
                    {
                        alert ("Cookies are activated.");
                    }
                    else
                    {
                        alert ("Cookies are not activated.");
                    }
                }
            }
        );
    }
</script>

ajax.php

$cmd = filter_input(INPUT_POST, "cmd");

if ( isset( $cmd ) && $cmd == "cookieCheck" )
{
    echo (isset($_COOKIE['CookieEnabledTest']) && $_COOKIE['CookieEnabledTest']=='check') ? 'enabled' : 'disabled';
}

作为结果,会出现一个警报框,展示cookies是否被启用。当然,您不必显示警报框,您可以采取其他措施来处理已停用的cookies。

1

JavaScript

您可以使用JavaScript创建一个cookie并检查它是否存在:

//Set a Cookie`
document.cookie="testcookie"`

//Check if cookie exists`
cookiesEnabled=(document.cookie.indexOf("testcookie")!=-1)? true : false`

或者你可以使用 jQuery Cookie 插件

//Set a Cookie`
$.cookie("testcookie", "testvalue")

//Check if cookie exists`
cookiesEnabled=( $.cookie("testcookie") ) ? true : false`

Php

setcookie("testcookie", "testvalue");

if( isset( $_COOKIE['testcookie'] ) ) {

}

不确定 Php 是否有效,因为我无法测试它。


2
PHP代码无法工作。您需要重新加载页面,以便浏览器发送第二个HTTP请求。如果第二个HTTP请求具有从第一个HTTP请求设置的cookie,则启用了cookie。 - Dave Jarvis

0

这里有一个非常有用且轻量级的 JavaScript 插件可以帮助您实现此功能: js-cookie

Cookies.set('cookieName', 'Value');
      setTimeout(function(){
        var cookieValue =  Cookies.get('cookieName');
        if(cookieValue){
           console.log("Test Cookie is set!");
        } else {
           document.write('<p>Sorry, but cookies must be enabled</p>');
        }
        Cookies.remove('cookieName');
      }, 1000);

适用于所有浏览器,接受任何字符。


0

检测 cookie 是否启用很容易:

  1. 设置一个 cookie。
  2. 获取 cookie。

如果您可以获取到您设置的 cookie,则 cookie 已启用,否则未启用。

顺便说一下:将会话 ID 嵌入链接和表单是个不好的主意,这对 SEO 不利。在我看来,人们不想启用 cookie 的情况并不是非常普遍。


1
你可能会感到惊讶,我有一个 Firefox 插件,可以阻止除白名单域名以外的所有 cookie,并注意到许多用户也在效仿。实际上,这就是引发问题的原因:一开始我无法使用表单,也无法弄清楚为什么,哈哈。 - steveo225
什么意思不能使用表单?无法将JSESSIONID嵌入表单中吗? - James.Xu
表单是一个多提交系统,在没有启用cookies的情况下,页面一直重新开始而不是继续,因为会话无法设置。 - steveo225
在欧洲,有一项新的Cookie法律,它让很多人害怕启用Cookie,因为网站必须要求接受Cookie。这个问题会让访问者感到非常烦恼,因此他们会完全关闭Cookie。你说:“不是很普遍”,这是真的,因为他们不知道这个问题存在。由于这个愚蠢的法律,更多的人知道了如何关闭Cookie。 - Codebeat

0

Cookie 是客户端的,无法使用 PHP 进行适当的测试。

这是基础问题,每个解决方案都是对这个问题的包装。

也就是说,如果你正在寻找 Cookie 问题的解决方案,那么你走错了路。不要使用 PHP,而是使用像 JavaScript 这样的客户端语言。

你能在 PHP 中使用 Cookies 吗?可以,但是你必须重新加载才能使设置对 PHP “可见”。

例如:是否可以使用纯 PHP 进行浏览器 Cookies 设置测试?唯一正确的答案是“否”。

你可以读取已经设置的 Cookies:“是”,使用预定义的 $_COOKIE(在启动 PHP 应用程序之前的设置的副本)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接