Одно возможное решение использует JavaScript на клиенте.
Клиентский алгоритм:
Алгоритм сервера:
Исходный код клиента (JavaScript):
function getCookie( name ) {
var parts = document.cookie.split(name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
function expireCookie( cName ) {
document.cookie =
encodeURIComponent(cName) + "=deleted; expires=" + new Date( 0 ).toUTCString();
}
function setCursor( docStyle, buttonStyle ) {
document.getElementById( "doc" ).style.cursor = docStyle;
document.getElementById( "button-id" ).style.cursor = buttonStyle;
}
function setFormToken() {
var downloadToken = new Date().getTime();
document.getElementById( "downloadToken" ).value = downloadToken;
return downloadToken;
}
var downloadTimer;
var attempts = 30;
// Prevents double-submits by waiting for a cookie from the server.
function blockResubmit() {
var downloadToken = setFormToken();
setCursor( "wait", "wait" );
downloadTimer = window.setInterval( function() {
var token = getCookie( "downloadToken" );
if( (token == downloadToken) || (attempts == 0) ) {
unblockSubmit();
}
attempts--;
}, 1000 );
}
function unblockSubmit() {
setCursor( "auto", "pointer" );
window.clearInterval( downloadTimer );
expireCookie( "downloadToken" );
attempts = 30;
}
Пример кода сервера (PHP):
$TOKEN = "downloadToken";
// Sets a cookie so that when the download begins the browser can
// unblock the submit button (thus helping to prevent multiple clicks).
// The false parameter allows the cookie to be exposed to JavaScript.
$this->setCookieToken( $TOKEN, $_GET[ $TOKEN ], false );
$result = $this->sendFile();
Где:
public function setCookieToken(
$cookieName, $cookieValue, $httpOnly = true, $secure = false ) {
// See: http://stackoverflow.com/a/1459794/59087
// See: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
// See: http://stackoverflow.com/a/3290474/59087
setcookie(
$cookieName,
$cookieValue,
2147483647, // expires January 1, 2038
"/", // your path
$_SERVER["HTTP_HOST"], // your domain
$secure, // Use true over HTTPS
$httpOnly // Set true for $AUTH_COOKIE_NAME
);
}
Причина в том, что наиболее подходящим типом для счетчика этого типа является регулярное signed
целое число, даже если этот счетчик никогда не станет ниже 0.
Почему счетчик должен быть unsigned
? Тот факт, что он не может стать отрицательным, вовсе не является оправданием для данного текущего реального значения из unsigned
для языка.
unsigned
для C ++ не означает «целое число, которое не может быть отрицательным». Чтобы понять, почему это определение просто не имеет смысла, рассмотрим, что
unsigned
составляет unsigned
unsigned
с signed
unsigned
unsigned
никогда не превышает -1 Ничто из вышеперечисленного не имеет никакого смысла, если считать unsigned
значением «неотрицательный» ».
Использование unsigned
для size_t
было ошибкой (см., Например, Почему size_t без знака? ), только частично * может быть исключено, потому что в 16-битной эпохе один дополнительный бит считался неправильным семантика, которую типы unsigned
имеют в C ++ для такого рода использования.
К сожалению, теперь ошибка size_t
не может быть исправлена (из-за обратной совместимости), но зачем повторять ту же ошибку в другой не связанной области?
Обратите внимание, что, вероятно, большая ошибка была сделана просто из-за выбора имя unsigned
(учитывая его реальное значение). Если бы этот тип был назван (более подходящим образом) modulo
, то, вероятно, было бы более очевидно, почему использование modulo int
для размера строки не имеет никакого смысла вообще.
Имя не имеет значения, то, что оно считает, является семантическим, и unsigned
просто имеет неправильную семантику для счетчика или размера.
(*) Лично я не думаю, что это было достаточно веской причиной даже тогда. Если 32767 не достаточно для размера сейчас, то 65535 не будет достаточно скоро. По моему мнению, только один бит (удвоенное значение) не был приемлемой ценой для такого изгиба семантики.
Я опубликовал видео , в котором более подробно обсуждаю, почему я считаю, что использование типа unsigned для size_t
было ошибкой проектирования в C ++.
Слайды можно загрузить с http://raksy.dyndns.org/unsigned.pdf