PHP - setcookie(); 不起作用

15
我已经创建了一个登录功能,它会设置一个cookie,其值为输入的电子邮件地址。在global.php文件中,使用以下代码将用户数据存储到一个数组中:
$email = $_COOKIE["PeopleHub"];
$getuserdata = mysqli_query($con, "SELECT * FROM Earth WHERE email='$email'");
$userdata = mysqli_fetch_array($getuserdata, MYSQLI_ASSOC);

Cookie没有被设置,我知道这个原因是因为我制作了一个测试文件:

echo $_COOKIE["PeopleHub"];

它只是生成了一个空白页面。

登录代码(设置cookie的地方):

<?php 
include "global.php";    
?>
<h2>Login</h2>
<?php 
    echo "We currently have <b>" . $usercount . "</b> members, <b>" . $onlinecount . "</b> of which are online. "; 
?>
<br>
<br>
<?php 
    if(isset($_POST["email"])){ 
        $email = $_POST["email"];
        $password = sha1($_POST["password"]);
        $check = mysqli_query($con, "SELECT * FROM Earth WHERE `email`='$email' AND `password`='$password'");
        $check = mysqli_num_rows($check);
        if($check == 1){
        setcookie("PeopleHub", $email, 0, '/');
        echo "We logged you in!";
        }
        else { 
            echo "We couldn't log you in!";
        }
    }
?>
<form action="<?php echo $_SERVER['REQUEST_URI']; ?>" method="post">
    Email <input name="email" placeholder="Email Address" required="" type="text"><br>
    Password <input name="password" placeholder="Password" required="" type="password"><br>
    <input type="reset" value="Start Over">
    <input type="submit" value="Login">
</form>

3
仅仅是提醒一下,但是你应该对数据进行清洗,因为你放置在那里的代码极易受到SQL注入攻击。 - Youness
1
不,序列化数据并不是一个“好”的选择。考虑使用预处理语句或PDO。 - undefined
7个回答

45

在发送任何标头之前,您必须设置Cookie。

根据手册

setcookie()定义了一个Cookie,将与其他HTTP标头一起发送。与其他标头一样,Cookie必须在脚本的任何输出之前发送(这是协议限制)。这意味着您需要在任何输出之前,包括和标签以及任何空白处调用此函数。

这意味着如果您希望直接使用此代码,您将需要了解输出缓冲

<?php

ob_start();
echo "Hello\n";

setcookie("cookiename", "cookiedata");

ob_end_flush();

?>

根据global.php的内容,这个方法可能对你有用。我所做的只是在调用setcookie()之前删除了任何输出。如果global.php中包含任何空格或HTML输出,这个方法将不起作用。
<?php 
include "global.php";    

    if(isset($_POST["email"])){ 
        $email = $_POST["email"];
        $password = sha1($_POST["password"]);
        $check = mysqli_query($con, "SELECT * FROM Earth WHERE `email`='$email' AND `password`='$password'");
        $check = mysqli_num_rows($check);
        if($check == 1){
        setcookie("PeopleHub", $email, 0, '/');
        echo "We logged you in!";
        }
        else { 
            echo "We couldn't log you in!";
        }
    }
?>
<h2>Login</h2>
<?php 
    echo "We currently have <b>" . $usercount . "</b> members, <b>" . $onlinecount . "</b> of which are online. "; 
?>
<br>
<br>
<form action="<?php echo $_SERVER['REQUEST_URI']; ?>" method="post">
    Email <input name="email" placeholder="Email Address" required="" type="text"><br>
    Password <input name="password" placeholder="Password" required="" type="password"><br>
    <input type="reset" value="Start Over">
    <input type="submit" value="Login">
</form>

点击我给你的输出缓冲链接。有一个实际使用setcookie()的例子。 - John Conde
如果我在全局文件的顶部放置ob_start();,它会起作用吗? - user2999920
是的。只需确保在每个文件末尾调用ob_end_flush()函数即可。 - John Conde
1
在全局核心函数文件中定义一个自定义函数,例如function cookie_set(),其中包含setcookie(),并在HTML代码顶部使用该函数。如果您想要删除cookie,只需使用相同的方法unset($_COOKIE['cookiename'])和setcookie('cookiename',NULL,time()-3600, '/')。 - Karthikeyan Ganesan

9

我想指出一个问题,即setcookie不能正常工作。当我进一步调查文件时,发现它被编码为UTF-8带BOM。当我重新将其编码为UTF-8无BOM时,setcookie可以正常工作,因此在遇到我的第一个php标记之前,会写入BOM。我猜在我的php.ini文件中启用缓冲可能也会解决这个问题。

有人最终可能会发现这些信息很有帮助。


这就是你使用Notepad++的下场! :) - Christian
谢谢罗伯特!但是Notepad++默认使用UTF-8无BOM格式...你想表达什么,克里斯汀?我认为在我的情况下是Visual Studio Express添加了BOM。 - Nicolas
是的,Notepad++通常默认为UTF-8无BOM。然而,如果你或与你合作的人使用了其他工具,很容易出现看起来正常但PHP将发送BOM并破坏Cookie的文件。例如,我在一个异构环境中工作,有些IDE默认为带BOM的UTF-8。 - Robert

3

我也曾遇到过这个问题,后来发现它是由于我传递给函数的域名使用了自定义端口(这是不被允许的)。


1

我的情况稍微有些特殊:原来我的广告拦截器(我使用的是1Blocker)会屏蔽某些名称的Cookie。在我的情况下,这是一个以_login结尾的Cookie名称。我更改了名称后,它就可以正常工作了。


1

我使用setcookie函数更新cookie时遇到了另一个问题。

所以我使用php序列化功能将数组转换为cookie字符串。从那时起,我无法更新该cookie - setcookie函数根本不起作用,无论是设置序列化字符串还是任何其他简单字符串。

然后我使用新的cookie键设置了另一个cookie,这次数据使用json_encode函数进行编码。这次我能够设置并更新cookie :-)


0

只是想补充一下,当用户使用这样的网址https://mywebsite89898989.com访问我的网站时,setcookie对我来说无法正常工作。但是当网站网址更改为https://www.mywebsite89898989.com时,setcookie可以正常工作。

我离专家相距甚远,因此也许有更多知识渊博的人可以解释这种行为。

我只是记录这些信息,希望能够节省某些人的调试时间...


0
如果您正在使用XAMPP,您可能会发现这很有帮助:今天我试图找出一个cookie错误的原因。在我的本地XAMPP服务器上,setcookie()正常工作,但是一旦我将项目上传到我的Web托管中,它就停止工作了,cookie没有被设置。 XAMPP使用PHP v8.1.10,而Web托管使用PHP v8.1.16,因此版本差异不是错误的原因。
事实证明,我的错误是在调用setcookie()之前输出了一些文本(因此HTTP标头已经发送),但我不知道为什么它在localhost / XAMPP上工作。它真的不应该是这样的。

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