如何防止另一个文件读取由带有GET参数的phpmailer发送的link

how to prevent that a link which is send by phpmailer with GET parameters is read by another file

对于一个简单的邮件列表,我使用 phpmailer 向订阅者发送一条消息,其中包含 "unsubscribe link"。 link 里面是 GET 参数。 我还有一个取消订阅订阅者的文件:unsubscribe.php。 我发送带有取消订阅 link 的电子邮件的文件名为 admin.php。两个文件都在同一目录中。

这是我如何通过取消订阅发送电子邮件的代码的一部分 link (admin.php):

$mail->AddAddress($recipients_email, $recipients_name);     //Adds a "To" address               
// send email with unsubscribe link             
try {
    $mail->Body = $_POST["message"].'<br /><br />'.'<a href="'.$unsubscribe_path.'unsubscribe.php?id='.urlencode(base64_encode($recipients_id)).'&email='.urlencode(base64_encode($recipients_email)).'&token='.$recipients_token.'">Unsubscribe</a>';  
    $mail->Send();  
    $result = '<div class="alert alert-success">Newsletter sent to subscribers of:<b> '.$recipients_category.'</b></div>';                  

} catch (Exception $e) {
    $result = '<div class="alert alert-danger">Mailer Error (' . htmlspecialchars($recipients_email) . ') ' . $mail->ErrorInfo . '</div>';
    $mail->smtp->reset(); // reset SMTP connection
}

$mail->clearAddresses(); // Clear all addresses for the next iteration

我的 unsubscribe.php 看起来像这样:

$id = $_GET['id'];
$email = $_GET['email'];
// decode the id and email string
$id_decode = base64_decode(urldecode($id));
$email_decode = base64_decode(urldecode($email));

$url = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
if ( parse_url($url, PHP_URL_QUERY) != NULL ) { // check if there is a url string with name and email               
    $filename = 'subscribers/'.$id_decode.'.txt';   
    // delete subscribers entry
    if(file_exists($filename)) { 
        unlink($filename);  
        echo '<div class="alert alert-success"><b>'.$email_decode.'</b> is successfully removed from our mailinglist!</div>';       
    }
    else {
        echo '<div class="alert alert-danger">Email not found or you already have unsubscribed from our mailinglist!</div>';
    }       
}

发生了什么:出于某种奇怪的原因,每次我向订阅者发送电子邮件时,unsubscribe.php unlinks 列表中的订阅者。 而文件 unsubscribe.php 仅在有人点击电子邮件中的 link 时才会使用!

我在删除文件时想通了 unsubscribe.php。如果我再发送一封电子邮件,订阅者就不再是 unlinked 了。 如果我只发送邮件正文中没有 link 的消息,订阅者也不会被删除!所以问题是 link 与 unsubscribe.php 文件

的结合

我该如何预防?

据此:How to check if a request if coming from the same server or different server?

这可以解决您的问题:

$id = $_GET['id'];
$email = $_GET['email'];
// decode the id and email string
$id_decode = base64_decode(urldecode($id));
$email_decode = base64_decode(urldecode($email));

if ((isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER']))) {
    if (strtolower(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)) != strtolower($_SERVER['HTTP_HOST'])) {

/* ALL CODE BELOW WILL BE EXECUTED IF NOT FROM YOUR OWN SERVER*/
        $filename = 'subscribers/'.$id_decode.'.txt';   
        // delete subscribers entry
        if(file_exists($filename)) { 
            unlink($filename);  
            echo '<div class="alert alert-success"><b>'.$email_decode.'</b> is successfully removed from our mailinglist!</div>';       
        }
        else {
            echo '<div class="alert alert-danger">Email not found or you already have unsubscribed from our mailinglist!</div>';
        }
    }
} 

取消订阅link真的打开了吗?您可以通过向取消订阅脚本添加一些日志记录来跟踪是否发生这种情况:

file_put_contents('unsublog.txt', date('Y-m-d h:i:s') . ',' . $id . ',' . $email . ',' . $_SERVER['REMOTE_ADDR'] . "\n", FILE_APPEND | LOCK_EX);

可能发生的情况是,接收服务器可能在实际读取邮件之前打开了邮件中的所有 link - 这在一些大型提供商(如 gmail)中变得非常普遍。这样做是为了检查 link 目标是否存在恶意软件,但当然这也会导致您立即取消订阅。

解决这个问题的方法是不立即处理退订请求,而是让退订页面先请求确认,也就是说,它需要第二次请求实际上取消订阅。

另一种方法(您可以与手动方法同时使用)是支持 List-Unsubscribe 消息 header,以及关联的 List-Unsubscribe-Post header 一键式功能。这些分别在 RFC2369 and RFC8058 中定义。如果您搜索这些术语,您会发现很多教程和其他资源来帮助您进行设置。