简体   繁体   English

防止网站范围内的双重提交

[英]Preventing a site-wide double submit

I was having a hard time figuring out a good title for this question, so I hope this is clear. 我很难找到这个问题的好标题,所以我希望这很清楚。 I am currently using the TwitterOauth module on one of my sites to post a tweet. 我目前在一个网站上使用TwitterOauth模块发布推文。 While this works, I need to set a limit to the amount of tweets submitted; 在此过程中,我需要对提交的推文数量设置一个限制; just one each hour . 每小时只有一个

Note: I do not have the option to use a database. 注意:我没有使用数据库的选项。 This is paramount for the question. 这对这个问题至关重要。

I have incorporated this as follows, in the PHP file that handles the actual posting to the Twitter API: 我已将以下内容合并到处理实际发布到Twitter API的PHP文件中:

# Save the timestamp, make sure lastSentTweet exists and is writeable
function saveTimestamp(){
    $myFile = "./lastSentTweet.inc";
    $fh = fopen($myFile, 'w');
    $stringData = '<?php function getLastTweetTimestamp() { return '.time().';}';
    fwrite($fh, $stringData);
    fclose($fh);
}

# Include the lastSentTweet time
include('./lastSentTweet.inc');

# Define the delay
define('TWEET_DELAY', 3600);

# Check for the last tweet
if (time() > getLastTweetTimestamp() + TWEET_DELAY) {
    // Posting to Twitter API here
} else {
    die("No.");
}

(initial) contents of the lastSentTweet.inc file (chmod 777): lastSentTweet.inc文件(chmod 777)的(初始)内容:

<?php function getLastTweetTimestamp() { return 1344362207;}

The problem is that while this works; 问题是,尽管这可行; it allows for accidental double submits; 它允许意外的两次提交; if multiple users (and the site this script runs on is currently extremely busy) trigger this script, it happens that 2 submits (or more, though this has not occurred yet) to Twitter slip through, instead of just the 1. My first thought is the (although minute) delay in opening, writing and closing the file, but I could be wrong. 如果有多个用户(此脚本运行的站点当前非常繁忙)触发了此脚本,则可能有2个提交到Twitter的提交(或更多,尽管尚未发生),而不仅仅是1个。是打开,写入和关闭文件的(尽管是一分钟)延迟,但我可能是错的。

Does anyone have an idea what allows for the accidental double submits (and how to fix this)? 有谁知道导致意外两次提交的原因(以及解决方法)?

You're getting race conditions. 您正在获得比赛条件。 You will need to implement locking on your file while you're making changes, but you need to enclose both the read (the include statement) and the update inside the lock; 你将需要实现锁定在你的文件,而你正在做的改变,但你需要附上两个读取(在include语句)和锁内更新; what is critical is to ensure nobody else (eg another HTTP request) is using the file, while you read its current value and then update it with the new timestamp. 至关重要的是在您读取文件的当前值然后使用新的时间戳对其进行更新时,确保没有其他人(例如,另一个HTTP请求)正在使用该文件。

This would be fairly ineffective. 这将是相当无效的。 You have other options which might be available in your PHP installation, here are some: 您还可以在PHP安装中使用其他选项,以下是一些选项:

  1. You can use a database even if you don't have a database server: SQLite 即使没有数据库服务器, 也可以使用数据库: SQLite
  2. You can store your timestamp in APC and use apc_cas() to detect if your last stored timestamp is still current when you update it. 您可以将时间戳存储在APC中,并在更新时使用apc_cas()来检测上次存储的时间戳是否仍然是最新的。

Update 更新

Your locking workflow needs to be something like this: 您的锁定工作流程必须是这样的:

  1. Acquire the lock on your stored timestamp. 获取您存储的时间戳记上的锁。 If you're working with files, you need to have the file open for reading and writing, and have called flock() on it. 如果你正在使用文件,你需要有开放的读取写入文件,并呼吁flock()就可以了。 flock() will hang if another process has the file locked, and will return only after it has acquired the lock, at which point other processes attempting to lock the file will hang. 如果另一个进程已将文件锁定,则flock()将挂起,并且仅在获得该锁定后才返回,此时其他试图锁定该文件的进程将挂起。
  2. Read the stored timestamp from the already locked file. 从已经锁定的文件中读取存储的时间戳。
  3. Check if the required time has passed since the stored timestamp. 检查从存储的时间戳记以来是否经过了所需的时间。
    • Only if it has passed, send the tweet and save the current timestamp to the file; 在通过后,发送推文并将当前时间戳保存到文件; otherwise you don't touch the stored timestamp. 否则,您不会触摸存储的时间戳。
  4. Release the lock (just closing the file is enough). 释放锁(仅关闭文件就足够了)。

This would ensure that no other process would update the timestamp after you have read and tested it but before you have stored the new timestamp. 这样可以确保在您阅读并测试了时间戳之后,但在存储新时间戳之前,没有其他进程可以更新该时间戳。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM