Skip to content

Ever wanted to force a file download in PHP or in WordPress?

Wordpress logo

It’s a more common problem than you think. You want to prompt the user with a download dialog box to download a file to their computer rather than render it in the browser. WordPress (and PHP) the majority of the time make this difficult as if you’ve got specific PHP ini values set and you happen to have sent even 1 byte of text over to the browser, sometimes you just cannot get the dialog box to appear, especially when changing the content type of the download.

However, after some tinkering on our part, we have the very solution. This solution focuses on the downloading of attachments attached to a specific post.

$fid = mysql_real_escape_string($_GET["ID"]);
	$ftype = mysql_real_escape_string($_GET["ftype"]);
	switch($ftype){
		case "thumbnail":
			$ssize = "thumbnail";
		break;
		case "medium":
			$ssize = "medium";
		break;
		case "large":
		case "full":
			$ssize = "full";
		break;
	}
	$args = array('post_type' => 'attachment','numberposts' => '45','post_status' => null,'post_parent' => '104');
	$attachments = get_posts($args);
	if ($attachments) {
		foreach ($attachments as $attachment) {

  			if ($attachment->ID == $fid){
  				$filename = wp_get_attachment_link($attachment->ID, $ssize, $permalink = false, $icon = false);
  				$newfilename = split("'",$filename);
  				$newfilename2 = str_replace("http://www.cr38.net",getcwd(),$newfilename[1]);
  				switch(substr($newfilename2, -3, 3)){
  					case "bmp":
						$conttype = "image/bmp";
					break;
					case "gif":
						$conttype = "image/gif";
					break;
					case "png":
						$conttype = "image/png";
					break;
					case "jpg":
						$conttype = "image/jpeg";
					break;
  				}
				if (ob_get_length()){
    			    @ob_flush();
    			    @flush();
    			    @ob_end_flush();
    			}
    			@ob_start();
    			header("Pragma: public");
  				header("Expires: 0");
  				header("Pragma: no-cache");
  				header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
  				header("Content-Type: application/force-download");
  				header("Content-Type: application/octet-stream");
  				header("Content-Type: application/download");
  				header('Content-disposition: attachment; filename=' . basename($newfilename2));
  				header("Content-Type: " . $conttype);
  				header("Content-Transfer-Encoding: binary");
  				header('Content-Length: ' . filesize($newfilename2));
  				@readfile($newfilename2);
  				exit(0);
  			}
 		}
	}

With this example we pass in to the page the type of image we want and the attachment id of the attachment we want to server up. The attachments have to be attached to the specific post id or else this example won’t work.

You can easily add more content types to detect, but for this example we’re serving up images for an image gallery. The key part to notice is the flushing of content, and setting the page to expire. This works round the fact that WordPress has already sent header information if this file is included within a theme. You could easily adapt what’s been written here for non WordPress situations too.

Enjoy!

Leave a Reply

You may use basic HTML in your comments. Your email address will not be published.

Subscribe to this comment feed via RSS