We wanted to provide a secure download feature to one of the sites I work on and it worked fine with smaller (< 1MB) files but when we tried large files (>550 MB) it would just output a empty file. After some troubleshooting (and a helpful post on php.net) it turns out that because output buffering was enabled it was running out of memory. This is the code that allows for the download to succeeded.

header('Content-type: application/x-gzip');
header('Content-Length: ' . filesize($filename));
header('Content-Disposition: attachment; filename="' . $file . '";' );

ob_end_flush();
readfile($filename);
exit;