ho the download_id and version_id is.
$this->dlm_logging->log( $download,
$version,
'completed',
false,
$referrer );
// At this point the $correct_path should have a value of the file path as the verification was made prior to this check
// If there are symbolik links the return of the function will be an URL, so the last replace will not be taken into consideration.
$file_path = download_monitor()->service( 'file_manager' )
->check_symbolic_links( $file_path,
true );
$file_path = str_replace( trailingslashit( $correct_path ),
'',
$file_path );
header( "X-Accel-Redirect: /$file_path" );
exit;
} elseif ( stristr( getenv( 'SERVER_SOFTWARE' ),
'LiteSpeed' )
) {
// Log this way as the js doesn't know who the download_id and version_id is.
$this->dlm_logging->log( $download,
$version,
'completed',
false,
$referrer );
header( "X-LiteSpeed-Location: $file_path" );
exit;
}
}
$safe_remote = wp_safe_remote_head( $file_path );
$safe = true;
if ( $remote_file && is_wp_error( $safe_remote ) ) {
$safe = false;
}
if ( ! $safe ) {
// IF XHR, send error header.
if ( $this->check_for_xhr() ) {
header( 'X-DLM-Error: security_error' );
$restriction_type = 'security_error';
$this->set_no_access_modal( __( 'Something is wrong with the file path.',
'download-monitor' ),
$download,
$restriction_type );
exit;
}
$this->dlm_logging->log( $download,
$version,
'failed',
false,
$referrer );
wp_die( esc_html__( 'Something is wrong with the file path.',
'download-monitor' ) . ' '
. esc_html__( 'Go to homepage →',
'download-monitor' ) . '',
esc_html__( 'Download Error', 'download-monitor' ),
array( 'response' => 404 ) );
}
// multipart-download and download resuming support - http://www.phpgang.com/force-to-download-a-file-in-php_112.html.
if ( isset( $_SERVER['HTTP_RANGE'] ) && $version->get_filesize() ) {
// phpcs:ignore
list( $a, $range ) = explode( "=", $_SERVER['HTTP_RANGE'], 2 );
list( $range ) = explode( ",", $range, 2 );
list( $range, $range_end ) = explode( "-", $range );
$range = intval( $range );
$range_end_modified = false;
if ( ! $range_end || $range_end > $version->get_filesize() ) {
$range_end = $version->get_filesize() - 1;
$range_end_modified = true;
} else {
$range_end = intval( $range_end );
}
if ( $range_end_modified ) {
$new_length = ( $range_end - $range ) + 1;
} else {
$new_length = $range_end - $range;
}
header( $_SERVER['SERVER_PROTOCOL'] . ' 206 Partial Content' );
header( "Content-Length: $new_length" );
header( "Content-Range: bytes {$range}-{$range_end}/{$version->get_filesize()}" );
} else {
$range = false;
}
// Adding contents to an object will trigger error on big files.
if ( $this->readfile_chunked( $file_path, false, $range ) ) {
// Log the download.
if ( ! $this->check_for_xhr() ) {
$this->dlm_logging->log( $download,
$version,
'completed',
false,
$referrer );
}
} elseif ( $remote_file ) {
// Redirect - we can't track if this completes or not.
if ( $this->check_for_xhr() ) {
header( 'X-DLM-Redirect: ' . $file_path );
exit;
}
header( 'Location: ' . $file_path );
$this->dlm_logging->log( $download,
$version,
'redirected',
false,
$referrer );
} else {
// IF XHR, send error header.
if ( $this->check_for_xhr() ) {
header( 'X-DLM-Error: file_not_found' );
$restriction_type = 'file_not_found';
$this->set_no_access_modal( __( 'File not found.',
'download-monitor' ),
$download,
$restriction_type );
exit;
}
$this->dlm_logging->log( $download,
$version,
'failed',
false,
$referrer );
wp_die( esc_html__( 'File not found.', 'download-monitor' )
. ' '
. esc_html__( 'Go to homepage →',
'download-monitor' ) . '',
esc_html__( 'Download Error', 'download-monitor' ),
array( 'response' => 404 ) );
}
exit;
}
/**
* Send cache headers to browser. No cache pelase.
*/
private function cache_headers() {
global $is_IE;
if ( $is_IE && is_ssl() ) {
// IE bug prevents download via SSL when Cache Control and Pragma no-cache headers set.
header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
header( 'Cache-Control: private' );
} else {
nocache_headers();
}
}
/**
* Output download headers
*
* @param string $file_path
* @param DLM_Download $download
* @param DLM_Download_Version $version
*/
private function download_headers( $file_path, $download, $version, $remote_file ) {
// Get Mime Type
$mime_type = 'application/octet-stream';
foreach ( get_allowed_mime_types() as $mime => $type ) {
$mimes = explode( '|', $mime );
if ( in_array( $version->get_filetype(), $mimes ) ) {
$mime_type = $type;
break;
}
}
// Get file name
$file_name = urldecode( DLM_Utils::basename( $file_path ) );
if ( strstr( $file_name, '?' ) ) {
$file_name = current( explode( '?', $file_name ) );
}
// Environment + headers
if ( ! ini_get( 'safe_mode' ) ) {
@set_time_limit( 0 );
}
if ( version_compare( PHP_VERSION, '7.4.0', '<' )
&& function_exists( 'get_magic_quotes_runtime' )
&& get_magic_quotes_runtime()
) {
@set_magic_quotes_runtime( 0 );
}
if ( function_exists( 'apache_setenv' ) ) {
@apache_setenv( 'no-gzip', 1 );
}
@session_write_close();
@ini_set( 'zlib.output_compression', 'Off' );
@error_reporting( 0 );
/**
* Prevents errors, for example: transfer closed with 3 bytes remaining to read
*/
@ob_end_clean(); // Clear the output buffer
// Zip corruption fix
while ( ob_get_level() > 0 ) {
@ob_end_clean();
}
$headers = array();
// We use this method to encode the filename so that file names with characters like
// chinese or persian can be named correctly after the download in Safari.
$file_name = rawurlencode( sanitize_file_name( $file_name ) );
if ( $this->check_for_xhr() ) {
$headers['Content-Disposition']
= "attachment; filename=\"{$file_name}\";";
$headers['X-DLM-File-Name'] = "{$file_name}";
} else {
$headers['Content-Disposition']
= "attachment; filename*=UTF-8''{$file_name};";
}
$headers['X-Robots-Tag'] = 'noindex, nofollow';
$headers['Content-Type'] = $mime_type;
$headers['Content-Description'] = 'File Transfer';
$headers['Content-Transfer-Encoding'] = 'binary';
$headers['Cache-Control']
= 'no-store, no-cache, must-revalidate, no-transform, max-age=0';
if ( $remote_file ) {
$file = wp_remote_head( $file_path );
if ( ! is_wp_error( $file )
&& ! empty( $file['headers']['content-length'] )
) {
$file_size = $file['headers']['content-length'];
}
} else {
$file_size = filesize( $file_path );
}
if ( isset( $file_size ) && $file_size ) {
// Replace the old way ( getting the filesize from the DB ) in case the user has replaced the file directly using cPanel,
// FTP or other File Manager, or sometimes using an optimization service it may cause unwanted results.
$headers['Content-Length'] = $file_size;
$headers['Accept-Ranges'] = 'bytes';
}
$headers = apply_filters( 'dlm_download_headers',
$headers,
$file_path,
$download,
$version );
foreach ( $headers as $key => $value ) {
header( $key . ': ' . $value );
}
}
/**
* Set required XHR download headers
*
* @param DLM_Download $download DLM Download object.
* @param DLM_Download_Version $version DLN Version object.
*/
private function set_required_xhr_headers( $download, $version ) {
$headers = array();
$headers['X-DLM-Download-ID'] = $download->get_id();
$headers['X-DLM-Version-ID'] = $version->get_id();
$headers['X-DLM-Nonce'] = wp_create_nonce( 'dlm_ajax_nonce' );
foreach ( $headers as $key => $value ) {
header( $key . ': ' . $value );
}
}
/**
* Set extra XHR download headers
*
* @param DLM_Download $download DLM Download object.
* @param DLM_Download_Version $version DLN Version object.
* @param string $file_path The file path.
*/
private function set_extra_xhr_headers(
$file_path,
$download,
$version
) {
$headers = apply_filters( 'dlm_xhr_download_headers',
array(),
$file_path,
$download,
$version,
$_REQUEST );
if ( ! empty( $headers ) ) {
foreach ( $headers as $key => $value ) {
header( $key . ': ' . $value );
}
}
}
/**
* readfile_chunked
*
* Reads file in chunks so big downloads are possible without changing PHP.INI - http://codeigniter.com/wiki/Download_helper_for_large_files/
*
* @access public
*
* @param string $file
* @param boolean $retbytes return bytes of file
* @param boolean $range if HTTP RANGE to seek
*
* @return mixed
*/
public function readfile_chunked(
$file,
$retbytes = true,
$range = false
) {
$chunksize = 1 * ( 1024 * 1024 );
$buffer = '';
$cnt = 0;
$handle = fopen( $file, 'rb' );
if ( $handle === false ) {
return false;
}
if ( $range ) {
fseek( $handle, $range );
}
while ( ! feof( $handle ) ) {
$buffer = fread( $handle, $chunksize );
// phpcs:ignore
echo $buffer;
if ( $retbytes ) {
$cnt += strlen( $buffer );
}
}
$status = fclose( $handle );
if ( $retbytes && $status ) {
return $cnt;
}
return $status;
}
/**
* Check if this is an XHR request or not
*
* @return bool
*/
private function check_for_xhr() {
return defined( 'DLM_DOING_XHR' ) && DLM_DOING_XHR;
}
/**
* Set headers for Modal opening
*
* @param string $text The text to be displayed.
* @param object $download The download object.
* @param string $restriction_type The restriction type.
*
* @return void
* @since 4.7.4
*/
public function set_no_access_modal(
$text,
$download,
$restriction_type
) {
$access_modal = absint( get_option( 'dlm_no_access_modal', 0 ) );
header( 'X-DLM-No-Access: true' );
header( 'X-DLM-No-Access-Modal: '
. apply_filters( 'do_dlm_xhr_access_modal',
$access_modal,
$download ) );
header( 'X-DLM-No-Access-Restriction: ' . $restriction_type );
if ( ! empty( $text ) ) {
header( 'X-DLM-No-Access-Modal-Text: '
. apply_filters( 'do_dlm_xhr_access_modal_text',
$text,
$download,
$restriction_type ) );
}
header( 'X-DLM-Nonce: ' . wp_create_nonce( 'dlm_ajax_nonce' ) );
}
}
}