Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>One <a href="http://gruffcode.com/2010/10/28/detecting-the-file-download-dialog-in-the-browser/" rel="noreferrer">possible solution</a> uses JavaScript on the client.</p> <p>The client algorithm:</p> <ol> <li>Generate a random unique token.</li> <li>Submit the download request, and include the token in a GET/POST field.</li> <li>Show the "waiting" indicator.</li> <li>Start a timer, and every second or so, look for a cookie named "fileDownloadToken" (or whatever you decide).</li> <li>If the cookie exists, and its value matches the token, hide the "waiting" indicator.</li> </ol> <p>The server algorithm:</p> <ol> <li>Look for the GET/POST field in the request.</li> <li>If it has a non-empty value, drop a cookie (e.g. "fileDownloadToken"), and set its value to the token's value.</li> </ol> <hr> <p>Client source code (JavaScript):</p> <pre><code>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; } </code></pre> <p>Example server code (PHP):</p> <pre><code>$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-&gt;setCookieToken( $TOKEN, $_GET[ $TOKEN ], false ); $result = $this-&gt;sendFile(); </code></pre> <p>Where:</p> <pre><code>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 ); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload