mirror of
https://github.com/phpbb/phpbb.git
synced 2025-05-13 19:15:20 +02:00
[ticket/14285] Move functions from functions_download to controller
PHPBB3-14285
This commit is contained in:
parent
8dcf8a4ddb
commit
2f043cdb61
@ -96,6 +96,7 @@ services:
|
|||||||
- '@auth'
|
- '@auth'
|
||||||
- '@cache'
|
- '@cache'
|
||||||
- '@config'
|
- '@config'
|
||||||
|
- '@content.visibility'
|
||||||
- '@dbal.conn'
|
- '@dbal.conn'
|
||||||
- '@dispatcher'
|
- '@dispatcher'
|
||||||
- '@request'
|
- '@request'
|
||||||
|
@ -43,136 +43,6 @@ function wrap_img_in_html($src, $title)
|
|||||||
echo '</html>';
|
echo '</html>';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send file to browser
|
|
||||||
*/
|
|
||||||
function send_file_to_browser($attachment, $category)
|
|
||||||
{
|
|
||||||
global $user, $db, $phpbb_dispatcher, $request, $phpbb_container;
|
|
||||||
|
|
||||||
$storage = $phpbb_container->get('storage.attachment');
|
|
||||||
|
|
||||||
$filename = $attachment['physical_filename'];
|
|
||||||
|
|
||||||
if (!$storage->exists($filename))
|
|
||||||
{
|
|
||||||
send_status_line(404, 'Not Found');
|
|
||||||
trigger_error('ERROR_NO_ATTACHMENT');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Correct the mime type - we force application/octetstream for all files, except images
|
|
||||||
// Please do not change this, it is a security precaution
|
|
||||||
if ($category != ATTACHMENT_CATEGORY_IMAGE || strpos($attachment['mimetype'], 'image') !== 0)
|
|
||||||
{
|
|
||||||
$attachment['mimetype'] = (strpos(strtolower($user->browser), 'msie') !== false || strpos(strtolower($user->browser), 'opera') !== false) ? 'application/octetstream' : 'application/octet-stream';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (@ob_get_length())
|
|
||||||
{
|
|
||||||
@ob_end_clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now send the File Contents to the Browser
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$file_info = $storage->file_info($filename);
|
|
||||||
$size = $file_info->size;
|
|
||||||
}
|
|
||||||
catch (\Exception $e)
|
|
||||||
{
|
|
||||||
$size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event to alter attachment before it is sent to browser.
|
|
||||||
*
|
|
||||||
* @event core.send_file_to_browser_before
|
|
||||||
* @var array attachment Attachment data
|
|
||||||
* @var int category Attachment category
|
|
||||||
* @var string filename Path to file, including filename
|
|
||||||
* @var int size File size
|
|
||||||
* @since 3.1.11-RC1
|
|
||||||
*/
|
|
||||||
$vars = array(
|
|
||||||
'attachment',
|
|
||||||
'category',
|
|
||||||
'filename',
|
|
||||||
'size',
|
|
||||||
);
|
|
||||||
extract($phpbb_dispatcher->trigger_event('core.send_file_to_browser_before', compact($vars)));
|
|
||||||
|
|
||||||
// To correctly display further errors we need to make sure we are using the correct headers for both (unsetting content-length may not work)
|
|
||||||
|
|
||||||
// Check if headers already sent or not able to get the file contents.
|
|
||||||
if (headers_sent())
|
|
||||||
{
|
|
||||||
send_status_line(500, 'Internal Server Error');
|
|
||||||
trigger_error('UNABLE_TO_DELIVER_FILE');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the database record for the filesize is correct
|
|
||||||
if ($size > 0 && $size != $attachment['filesize'] && strpos($attachment['physical_filename'], 'thumb_') === false)
|
|
||||||
{
|
|
||||||
// Update database record
|
|
||||||
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
|
|
||||||
SET filesize = ' . (int) $size . '
|
|
||||||
WHERE attach_id = ' . (int) $attachment['attach_id'];
|
|
||||||
$db->sql_query($sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now the tricky part... let's dance
|
|
||||||
header('Cache-Control: private');
|
|
||||||
|
|
||||||
// Send out the Headers. Do not set Content-Disposition to inline please, it is a security measure for users using the Internet Explorer.
|
|
||||||
header('Content-Type: ' . $attachment['mimetype']);
|
|
||||||
|
|
||||||
header('X-Content-Type-Options: nosniff');
|
|
||||||
|
|
||||||
if (empty($user->browser) || ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7)))
|
|
||||||
{
|
|
||||||
header('Content-Disposition: attachment; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'], ENT_COMPAT)));
|
|
||||||
if (empty($user->browser) || (strpos(strtolower($user->browser), 'msie 6.0') !== false))
|
|
||||||
{
|
|
||||||
header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'], ENT_COMPAT)));
|
|
||||||
if (phpbb_is_greater_ie_version($user->browser, 7) && (strpos($attachment['mimetype'], 'image') !== 0))
|
|
||||||
{
|
|
||||||
header('X-Download-Options: noopen');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_modified_headers($attachment['filetime'], $user->browser))
|
|
||||||
{
|
|
||||||
if ($size)
|
|
||||||
{
|
|
||||||
header("Content-Length: $size");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to deliver in chunks
|
|
||||||
@set_time_limit(0);
|
|
||||||
|
|
||||||
$fp = $storage->read_stream($filename);
|
|
||||||
|
|
||||||
// Close the db connection before sending the file etc.
|
|
||||||
file_gc(false);
|
|
||||||
|
|
||||||
if ($fp !== false)
|
|
||||||
{
|
|
||||||
$output = fopen('php://output', 'w+b');
|
|
||||||
stream_copy_to_stream($fp, $output);
|
|
||||||
fclose($fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a browser friendly UTF-8 encoded filename
|
* Get a browser friendly UTF-8 encoded filename
|
||||||
*/
|
*/
|
||||||
@ -193,149 +63,14 @@ function header_filename($file)
|
|||||||
return "filename*=UTF-8''" . rawurlencode($file);
|
return "filename*=UTF-8''" . rawurlencode($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if downloading item is allowed
|
|
||||||
*/
|
|
||||||
function download_allowed()
|
|
||||||
{
|
|
||||||
global $config, $user, $db, $request;
|
|
||||||
|
|
||||||
if (!$config['secure_downloads'])
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = htmlspecialchars_decode($request->header('Referer'), ENT_COMPAT);
|
|
||||||
|
|
||||||
if (!$url)
|
|
||||||
{
|
|
||||||
return ($config['secure_allow_empty_referer']) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split URL into domain and script part
|
|
||||||
$url = @parse_url($url);
|
|
||||||
|
|
||||||
if ($url === false)
|
|
||||||
{
|
|
||||||
return ($config['secure_allow_empty_referer']) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$hostname = $url['host'];
|
|
||||||
unset($url);
|
|
||||||
|
|
||||||
$allowed = ($config['secure_allow_deny']) ? false : true;
|
|
||||||
$iplist = array();
|
|
||||||
|
|
||||||
if (($ip_ary = @gethostbynamel($hostname)) !== false)
|
|
||||||
{
|
|
||||||
foreach ($ip_ary as $ip)
|
|
||||||
{
|
|
||||||
if ($ip)
|
|
||||||
{
|
|
||||||
$iplist[] = $ip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for own server...
|
|
||||||
$server_name = $user->host;
|
|
||||||
|
|
||||||
// Forcing server vars is the only way to specify/override the protocol
|
|
||||||
if ($config['force_server_vars'] || !$server_name)
|
|
||||||
{
|
|
||||||
$server_name = $config['server_name'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preg_match('#^.*?' . preg_quote($server_name, '#') . '.*?$#i', $hostname))
|
|
||||||
{
|
|
||||||
$allowed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get IP's and Hostnames
|
|
||||||
if (!$allowed)
|
|
||||||
{
|
|
||||||
$sql = 'SELECT site_ip, site_hostname, ip_exclude
|
|
||||||
FROM ' . SITELIST_TABLE;
|
|
||||||
$result = $db->sql_query($sql);
|
|
||||||
|
|
||||||
while ($row = $db->sql_fetchrow($result))
|
|
||||||
{
|
|
||||||
$site_ip = trim($row['site_ip']);
|
|
||||||
$site_hostname = trim($row['site_hostname']);
|
|
||||||
|
|
||||||
if ($site_ip)
|
|
||||||
{
|
|
||||||
foreach ($iplist as $ip)
|
|
||||||
{
|
|
||||||
if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_ip, '#')) . '$#i', $ip))
|
|
||||||
{
|
|
||||||
if ($row['ip_exclude'])
|
|
||||||
{
|
|
||||||
$allowed = ($config['secure_allow_deny']) ? false : true;
|
|
||||||
break 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$allowed = ($config['secure_allow_deny']) ? true : false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($site_hostname)
|
|
||||||
{
|
|
||||||
if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_hostname, '#')) . '$#i', $hostname))
|
|
||||||
{
|
|
||||||
if ($row['ip_exclude'])
|
|
||||||
{
|
|
||||||
$allowed = ($config['secure_allow_deny']) ? false : true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$allowed = ($config['secure_allow_deny']) ? true : false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$db->sql_freeresult($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the browser has the file already and set the appropriate headers-
|
|
||||||
* @returns false if a resend is in order.
|
|
||||||
*/
|
|
||||||
function set_modified_headers($stamp, $browser)
|
|
||||||
{
|
|
||||||
global $request;
|
|
||||||
|
|
||||||
// let's see if we have to send the file at all
|
|
||||||
$last_load = $request->header('If-Modified-Since') ? strtotime(trim($request->header('If-Modified-Since'))) : false;
|
|
||||||
|
|
||||||
if ($last_load !== false && $last_load >= $stamp)
|
|
||||||
{
|
|
||||||
send_status_line(304, 'Not Modified');
|
|
||||||
// seems that we need those too ... browsers
|
|
||||||
header('Cache-Control: private');
|
|
||||||
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Garbage Collection
|
* Garbage Collection
|
||||||
*
|
*
|
||||||
* @param bool $exit Whether to die or not.
|
* @param bool $exit Whether to die or not.
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
|
*
|
||||||
|
* @deprecated: 3.3.0-dev (To be removed: 4.0.0)
|
||||||
*/
|
*/
|
||||||
function file_gc($exit = true)
|
function file_gc($exit = true)
|
||||||
{
|
{
|
||||||
@ -354,287 +89,6 @@ function file_gc($exit = true)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* HTTP range support (RFC 2616 Section 14.35)
|
|
||||||
*
|
|
||||||
* Allows browsers to request partial file content
|
|
||||||
* in case a download has been interrupted.
|
|
||||||
*
|
|
||||||
* @param int $filesize the size of the file in bytes we are about to deliver
|
|
||||||
*
|
|
||||||
* @return mixed false if the whole file has to be delivered
|
|
||||||
* associative array on success
|
|
||||||
*/
|
|
||||||
function phpbb_http_byte_range($filesize)
|
|
||||||
{
|
|
||||||
// Only call find_range_request() once.
|
|
||||||
static $request_array;
|
|
||||||
|
|
||||||
if (!$filesize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($request_array))
|
|
||||||
{
|
|
||||||
$request_array = phpbb_find_range_request();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (empty($request_array)) ? false : phpbb_parse_range_request($request_array, $filesize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches for HTTP range request in request headers.
|
|
||||||
*
|
|
||||||
* @return mixed false if no request found
|
|
||||||
* array of strings containing the requested ranges otherwise
|
|
||||||
* e.g. array(0 => '0-0', 1 => '123-125')
|
|
||||||
*/
|
|
||||||
function phpbb_find_range_request()
|
|
||||||
{
|
|
||||||
global $request;
|
|
||||||
|
|
||||||
$value = $request->header('Range');
|
|
||||||
|
|
||||||
// Make sure range request starts with "bytes="
|
|
||||||
if (strpos($value, 'bytes=') === 0)
|
|
||||||
{
|
|
||||||
// Strip leading 'bytes='
|
|
||||||
// Multiple ranges can be separated by a comma
|
|
||||||
return explode(',', substr($value, 6));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Analyses a range request array.
|
|
||||||
*
|
|
||||||
* A range request can contain multiple ranges,
|
|
||||||
* we however only handle the first request and
|
|
||||||
* only support requests from a given byte to the end of the file.
|
|
||||||
*
|
|
||||||
* @param array $request_array array of strings containing the requested ranges
|
|
||||||
* @param int $filesize the full size of the file in bytes that has been requested
|
|
||||||
*
|
|
||||||
* @return mixed false if the whole file has to be delivered
|
|
||||||
* associative array on success
|
|
||||||
* byte_pos_start the first byte position, can be passed to fseek()
|
|
||||||
* byte_pos_end the last byte position
|
|
||||||
* bytes_requested the number of bytes requested
|
|
||||||
* bytes_total the full size of the file
|
|
||||||
*/
|
|
||||||
function phpbb_parse_range_request($request_array, $filesize)
|
|
||||||
{
|
|
||||||
$first_byte_pos = -1;
|
|
||||||
$last_byte_pos = -1;
|
|
||||||
|
|
||||||
// Go through all ranges
|
|
||||||
foreach ($request_array as $range_string)
|
|
||||||
{
|
|
||||||
$range = explode('-', trim($range_string));
|
|
||||||
|
|
||||||
// "-" is invalid, "0-0" however is valid and means the very first byte.
|
|
||||||
if (count($range) != 2 || $range[0] === '' && $range[1] === '')
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Substitute defaults
|
|
||||||
if ($range[0] === '')
|
|
||||||
{
|
|
||||||
$range[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($range[1] === '')
|
|
||||||
{
|
|
||||||
$range[1] = $filesize - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($last_byte_pos >= 0 && $last_byte_pos + 1 != $range[0])
|
|
||||||
{
|
|
||||||
// We only support contiguous ranges, no multipart stuff :(
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($range[1] && $range[1] < $range[0])
|
|
||||||
{
|
|
||||||
// The requested range contains 0 bytes.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return bytes from $range[0] to $range[1]
|
|
||||||
if ($first_byte_pos < 0)
|
|
||||||
{
|
|
||||||
$first_byte_pos = (int) $range[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
$last_byte_pos = (int) $range[1];
|
|
||||||
|
|
||||||
if ($first_byte_pos >= $filesize)
|
|
||||||
{
|
|
||||||
// Requested range not satisfiable
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust last-byte-pos if it is absent or greater than the content.
|
|
||||||
if ($range[1] === '' || $last_byte_pos >= $filesize)
|
|
||||||
{
|
|
||||||
$last_byte_pos = $filesize - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($first_byte_pos < 0 || $last_byte_pos < 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'byte_pos_start' => $first_byte_pos,
|
|
||||||
'byte_pos_end' => $last_byte_pos,
|
|
||||||
'bytes_requested' => $last_byte_pos - $first_byte_pos + 1,
|
|
||||||
'bytes_total' => $filesize,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increments the download count of all provided attachments
|
|
||||||
*
|
|
||||||
* @param \phpbb\db\driver\driver_interface $db The database object
|
|
||||||
* @param array|int $ids The attach_id of each attachment
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
function phpbb_increment_downloads($db, $ids)
|
|
||||||
{
|
|
||||||
if (!is_array($ids))
|
|
||||||
{
|
|
||||||
$ids = array($ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
|
|
||||||
SET download_count = download_count + 1
|
|
||||||
WHERE ' . $db->sql_in_set('attach_id', $ids);
|
|
||||||
$db->sql_query($sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles authentication when downloading attachments from a post or topic
|
|
||||||
*
|
|
||||||
* @param \phpbb\db\driver\driver_interface $db The database object
|
|
||||||
* @param \phpbb\auth\auth $auth The authentication object
|
|
||||||
* @param int $topic_id The id of the topic that we are downloading from
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
|
|
||||||
{
|
|
||||||
global $phpbb_container;
|
|
||||||
|
|
||||||
$sql_array = array(
|
|
||||||
'SELECT' => 't.topic_visibility, t.forum_id, f.forum_name, f.forum_password, f.parent_id',
|
|
||||||
'FROM' => array(
|
|
||||||
TOPICS_TABLE => 't',
|
|
||||||
FORUMS_TABLE => 'f',
|
|
||||||
),
|
|
||||||
'WHERE' => 't.topic_id = ' . (int) $topic_id . '
|
|
||||||
AND t.forum_id = f.forum_id',
|
|
||||||
);
|
|
||||||
|
|
||||||
$sql = $db->sql_build_query('SELECT', $sql_array);
|
|
||||||
$result = $db->sql_query($sql);
|
|
||||||
$row = $db->sql_fetchrow($result);
|
|
||||||
$db->sql_freeresult($result);
|
|
||||||
|
|
||||||
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
|
|
||||||
|
|
||||||
if ($row && !$phpbb_content_visibility->is_visible('topic', $row['forum_id'], $row))
|
|
||||||
{
|
|
||||||
send_status_line(404, 'Not Found');
|
|
||||||
trigger_error('ERROR_NO_ATTACHMENT');
|
|
||||||
}
|
|
||||||
else if ($row && $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']))
|
|
||||||
{
|
|
||||||
if ($row['forum_password'])
|
|
||||||
{
|
|
||||||
// Do something else ... ?
|
|
||||||
login_forum_box($row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
send_status_line(403, 'Forbidden');
|
|
||||||
trigger_error('SORRY_AUTH_VIEW_ATTACH');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles authentication when downloading attachments from PMs
|
|
||||||
*
|
|
||||||
* @param \phpbb\db\driver\driver_interface $db The database object
|
|
||||||
* @param \phpbb\auth\auth $auth The authentication object
|
|
||||||
* @param int $user_id The user id
|
|
||||||
* @param int $msg_id The id of the PM that we are downloading from
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id)
|
|
||||||
{
|
|
||||||
global $phpbb_dispatcher;
|
|
||||||
|
|
||||||
if (!$auth->acl_get('u_pm_download'))
|
|
||||||
{
|
|
||||||
send_status_line(403, 'Forbidden');
|
|
||||||
trigger_error('SORRY_AUTH_VIEW_ATTACH');
|
|
||||||
}
|
|
||||||
|
|
||||||
$allowed = phpbb_download_check_pm_auth($db, $user_id, $msg_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event to modify PM attachments download auth
|
|
||||||
*
|
|
||||||
* @event core.modify_pm_attach_download_auth
|
|
||||||
* @var bool allowed Whether the user is allowed to download from that PM or not
|
|
||||||
* @var int msg_id The id of the PM to download from
|
|
||||||
* @var int user_id The user id for auth check
|
|
||||||
* @since 3.1.11-RC1
|
|
||||||
*/
|
|
||||||
$vars = array('allowed', 'msg_id', 'user_id');
|
|
||||||
extract($phpbb_dispatcher->trigger_event('core.modify_pm_attach_download_auth', compact($vars)));
|
|
||||||
|
|
||||||
if (!$allowed)
|
|
||||||
{
|
|
||||||
send_status_line(403, 'Forbidden');
|
|
||||||
trigger_error('ERROR_NO_ATTACHMENT');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether a user can download from a particular PM
|
|
||||||
*
|
|
||||||
* @param \phpbb\db\driver\driver_interface $db The database object
|
|
||||||
* @param int $user_id The user id
|
|
||||||
* @param int $msg_id The id of the PM that we are downloading from
|
|
||||||
*
|
|
||||||
* @return bool Whether the user is allowed to download from that PM or not
|
|
||||||
*/
|
|
||||||
function phpbb_download_check_pm_auth($db, $user_id, $msg_id)
|
|
||||||
{
|
|
||||||
// Check if the attachment is within the users scope...
|
|
||||||
$sql = 'SELECT msg_id
|
|
||||||
FROM ' . PRIVMSGS_TO_TABLE . '
|
|
||||||
WHERE msg_id = ' . (int) $msg_id . '
|
|
||||||
AND (
|
|
||||||
user_id = ' . (int) $user_id . '
|
|
||||||
OR author_id = ' . (int) $user_id . '
|
|
||||||
)';
|
|
||||||
$result = $db->sql_query_limit($sql, 1);
|
|
||||||
$allowed = (bool) $db->sql_fetchfield('msg_id');
|
|
||||||
$db->sql_freeresult($result);
|
|
||||||
|
|
||||||
return $allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the browser is internet explorer version 7+
|
* Check if the browser is internet explorer version 7+
|
||||||
*
|
*
|
||||||
|
@ -16,6 +16,7 @@ namespace phpbb\storage\controller;
|
|||||||
use phpbb\auth\auth;
|
use phpbb\auth\auth;
|
||||||
use phpbb\cache\service;
|
use phpbb\cache\service;
|
||||||
use phpbb\config\config;
|
use phpbb\config\config;
|
||||||
|
use phpbb\content_visibility;
|
||||||
use phpbb\db\driver\driver_interface;
|
use phpbb\db\driver\driver_interface;
|
||||||
use phpbb\event\dispatcher;
|
use phpbb\event\dispatcher;
|
||||||
use phpbb\request\request;
|
use phpbb\request\request;
|
||||||
@ -27,17 +28,17 @@ class attachment extends controller
|
|||||||
/** @var auth */
|
/** @var auth */
|
||||||
protected $auth;
|
protected $auth;
|
||||||
|
|
||||||
/** @var service */
|
|
||||||
protected $cache;
|
|
||||||
|
|
||||||
/** @var config */
|
/** @var config */
|
||||||
protected $config;
|
protected $config;
|
||||||
|
|
||||||
|
/** @var content_visibility */
|
||||||
|
protected $content_visibility;
|
||||||
|
|
||||||
/** @var driver_interface */
|
/** @var driver_interface */
|
||||||
protected $db;
|
protected $db;
|
||||||
|
|
||||||
/** @var dispatcher */
|
/** @var dispatcher */
|
||||||
protected $phpbb_dispatcher;
|
protected $dispatcher;
|
||||||
|
|
||||||
/** @var request */
|
/** @var request */
|
||||||
protected $request;
|
protected $request;
|
||||||
@ -48,13 +49,14 @@ class attachment extends controller
|
|||||||
/** @var user */
|
/** @var user */
|
||||||
protected $user;
|
protected $user;
|
||||||
|
|
||||||
public function __construct(auth $auth, service $cache, config $config, driver_interface $db, dispatcher $phpbb_dispatcher, request $request, storage $storage, user $user)
|
public function __construct(auth $auth, service $cache, config $config, $content_visibility, driver_interface $db, dispatcher $dispatcher, request $request, storage $storage, user $user)
|
||||||
{
|
{
|
||||||
$this->auth = $auth;
|
$this->auth = $auth;
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
$this->content_visibility = $content_visibility;
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
$this->phpbb_dispatcher = $phpbb_dispatcher;
|
$this->dispatcher = $dispatcher;
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
$this->storage = $storage;
|
$this->storage = $storage;
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
@ -62,20 +64,16 @@ class attachment extends controller
|
|||||||
|
|
||||||
public function handle($file)
|
public function handle($file)
|
||||||
{
|
{
|
||||||
global $phpbb_root_path, $phpEx, $phpbb_container;
|
|
||||||
require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx);
|
|
||||||
|
|
||||||
$attach_id = $file;
|
$attach_id = $file;
|
||||||
$mode = $this->request->variable('mode', '');
|
$mode = $this->request->variable('mode', '');
|
||||||
$thumbnail = $this->request->variable('t', false);
|
$thumbnail = $this->request->variable('t', false);
|
||||||
|
global $phpbb_container;
|
||||||
|
|
||||||
// Start session management, do not update session page.
|
// Start session management, do not update session page.
|
||||||
$this->user->session_begin(false);
|
$this->user->session_begin(false);
|
||||||
$this->auth->acl($this->user->data);
|
$this->auth->acl($this->user->data);
|
||||||
$this->user->setup('viewtopic');
|
$this->user->setup('viewtopic');
|
||||||
|
|
||||||
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
|
|
||||||
|
|
||||||
if (!$this->config['allow_attachments'] && !$this->config['allow_pm_attach'])
|
if (!$this->config['allow_attachments'] && !$this->config['allow_pm_attach'])
|
||||||
{
|
{
|
||||||
send_status_line(404, 'Not Found');
|
send_status_line(404, 'Not Found');
|
||||||
@ -100,10 +98,10 @@ class attachment extends controller
|
|||||||
send_status_line(404, 'Not Found');
|
send_status_line(404, 'Not Found');
|
||||||
trigger_error('ERROR_NO_ATTACHMENT');
|
trigger_error('ERROR_NO_ATTACHMENT');
|
||||||
}
|
}
|
||||||
else if (!download_allowed())
|
else if (!$this->download_allowed())
|
||||||
{
|
{
|
||||||
send_status_line(403, 'Forbidden');
|
send_status_line(403, 'Forbidden');
|
||||||
trigger_error($user->lang['LINKAGE_FORBIDDEN']);
|
trigger_error($this->user->lang['LINKAGE_FORBIDDEN']);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -133,7 +131,7 @@ class attachment extends controller
|
|||||||
{
|
{
|
||||||
if (!$attachment['in_message'])
|
if (!$attachment['in_message'])
|
||||||
{
|
{
|
||||||
phpbb_download_handle_forum_auth($this->db, $this->auth, $attachment['topic_id']);
|
$this->phpbb_download_handle_forum_auth($attachment['topic_id']);
|
||||||
|
|
||||||
$sql = 'SELECT forum_id, post_visibility
|
$sql = 'SELECT forum_id, post_visibility
|
||||||
FROM ' . POSTS_TABLE . '
|
FROM ' . POSTS_TABLE . '
|
||||||
@ -142,7 +140,7 @@ class attachment extends controller
|
|||||||
$post_row = $this->db->sql_fetchrow($result);
|
$post_row = $this->db->sql_fetchrow($result);
|
||||||
$this->db->sql_freeresult($result);
|
$this->db->sql_freeresult($result);
|
||||||
|
|
||||||
if (!$post_row || !$phpbb_content_visibility->is_visible('post', $post_row['forum_id'], $post_row))
|
if (!$post_row || !$this->content_visibility->is_visible('post', $post_row['forum_id'], $post_row))
|
||||||
{
|
{
|
||||||
// Attachment of a soft deleted post and the user is not allowed to see the post
|
// Attachment of a soft deleted post and the user is not allowed to see the post
|
||||||
send_status_line(404, 'Not Found');
|
send_status_line(404, 'Not Found');
|
||||||
@ -153,7 +151,7 @@ class attachment extends controller
|
|||||||
{
|
{
|
||||||
// Attachment is in a private message.
|
// Attachment is in a private message.
|
||||||
$post_row = array('forum_id' => false);
|
$post_row = array('forum_id' => false);
|
||||||
phpbb_download_handle_pm_auth($this->db, $this->auth, $this->user->data['user_id'], $attachment['post_msg_id']);
|
$this->phpbb_download_handle_pm_auth( $attachment['post_msg_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$extensions = array();
|
$extensions = array();
|
||||||
@ -180,10 +178,10 @@ class attachment extends controller
|
|||||||
{
|
{
|
||||||
$attachment['physical_filename'] = 'thumb_' . $attachment['physical_filename'];
|
$attachment['physical_filename'] = 'thumb_' . $attachment['physical_filename'];
|
||||||
}
|
}
|
||||||
else if ($display_cat == ATTACHMENT_CATEGORY_NONE && !$attachment['is_orphan'] && !phpbb_http_byte_range($attachment['filesize']))
|
else if ($display_cat == ATTACHMENT_CATEGORY_NONE && !$attachment['is_orphan'])
|
||||||
{
|
{
|
||||||
// Update download count
|
// Update download count
|
||||||
phpbb_increment_downloads($this->db, $attachment['attach_id']);
|
$this->phpbb_increment_downloads($attachment['attach_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$redirect = '';
|
$redirect = '';
|
||||||
@ -212,7 +210,7 @@ class attachment extends controller
|
|||||||
'thumbnail',
|
'thumbnail',
|
||||||
'redirect',
|
'redirect',
|
||||||
);
|
);
|
||||||
extract($this->phpbb_dispatcher->trigger_event('core.download_file_send_to_browser_before', compact($vars)));
|
extract($this->dispatcher->trigger_event('core.download_file_send_to_browser_before', compact($vars)));
|
||||||
|
|
||||||
if (!empty($redirect))
|
if (!empty($redirect))
|
||||||
{
|
{
|
||||||
@ -220,10 +218,393 @@ class attachment extends controller
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
send_file_to_browser($attachment, $display_cat);
|
$this->send_file_to_browser($attachment, $display_cat);
|
||||||
}
|
}
|
||||||
|
|
||||||
file_gc();
|
$this->file_gc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send file to browser
|
||||||
|
*/
|
||||||
|
protected function send_file_to_browser($attachment, $category)
|
||||||
|
{
|
||||||
|
$filename = $attachment['physical_filename'];
|
||||||
|
|
||||||
|
if (!$this->storage->exists($filename))
|
||||||
|
{
|
||||||
|
send_status_line(404, 'Not Found');
|
||||||
|
trigger_error('ERROR_NO_ATTACHMENT');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct the mime type - we force application/octetstream for all files, except images
|
||||||
|
// Please do not change this, it is a security precaution
|
||||||
|
if ($category != ATTACHMENT_CATEGORY_IMAGE || strpos($attachment['mimetype'], 'image') !== 0)
|
||||||
|
{
|
||||||
|
$attachment['mimetype'] = (strpos(strtolower($this->user->browser), 'msie') !== false || strpos(strtolower($this->user->browser), 'opera') !== false) ? 'application/octetstream' : 'application/octet-stream';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@ob_get_length())
|
||||||
|
{
|
||||||
|
@ob_end_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now send the File Contents to the Browser
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$file_info = $this->storage->file_info($filename);
|
||||||
|
$size = $file_info->size;
|
||||||
|
}
|
||||||
|
catch (\Exception $e)
|
||||||
|
{
|
||||||
|
$size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event to alter attachment before it is sent to browser.
|
||||||
|
*
|
||||||
|
* @event core.send_file_to_browser_before
|
||||||
|
* @var array attachment Attachment data
|
||||||
|
* @var int category Attachment category
|
||||||
|
* @var string filename Path to file, including filename
|
||||||
|
* @var int size File size
|
||||||
|
* @since 3.1.11-RC1
|
||||||
|
*/
|
||||||
|
$vars = array(
|
||||||
|
'attachment',
|
||||||
|
'category',
|
||||||
|
'filename',
|
||||||
|
'size',
|
||||||
|
);
|
||||||
|
extract($this->dispatcher->trigger_event('core.send_file_to_browser_before', compact($vars)));
|
||||||
|
|
||||||
|
// To correctly display further errors we need to make sure we are using the correct headers for both (unsetting content-length may not work)
|
||||||
|
|
||||||
|
// Check if headers already sent or not able to get the file contents.
|
||||||
|
if (headers_sent())
|
||||||
|
{
|
||||||
|
send_status_line(500, 'Internal Server Error');
|
||||||
|
trigger_error('UNABLE_TO_DELIVER_FILE');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the database record for the filesize is correct
|
||||||
|
if ($size > 0 && $size != $attachment['filesize'] && strpos($attachment['physical_filename'], 'thumb_') === false)
|
||||||
|
{
|
||||||
|
// Update database record
|
||||||
|
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
|
||||||
|
SET filesize = ' . (int) $size . '
|
||||||
|
WHERE attach_id = ' . (int) $attachment['attach_id'];
|
||||||
|
$this->db->sql_query($sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now the tricky part... let's dance
|
||||||
|
header('Cache-Control: public');
|
||||||
|
|
||||||
|
// Send out the Headers. Do not set Content-Disposition to inline please, it is a security measure for users using the Internet Explorer.
|
||||||
|
header('Content-Type: ' . $attachment['mimetype']);
|
||||||
|
|
||||||
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
|
||||||
|
if ($category == ATTACHMENT_CATEGORY_FLASH && $this->request->variable('view', 0) === 1)
|
||||||
|
{
|
||||||
|
// We use content-disposition: inline for flash files and view=1 to let it correctly play with flash player 10 - any other disposition will fail to play inline
|
||||||
|
header('Content-Disposition: inline');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'])));
|
||||||
|
|
||||||
|
if (strpos($attachment['mimetype'], 'image') !== 0)
|
||||||
|
{
|
||||||
|
header('X-Download-Options: noopen');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->set_modified_headers($attachment['filetime'], $this->user->browser))
|
||||||
|
{
|
||||||
|
if ($size)
|
||||||
|
{
|
||||||
|
header("Content-Length: $size");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to deliver in chunks
|
||||||
|
@set_time_limit(0);
|
||||||
|
|
||||||
|
$fp = $this->storage->read_stream($filename);
|
||||||
|
|
||||||
|
// Close the db connection before sending the file etc.
|
||||||
|
$this->file_gc(false);
|
||||||
|
|
||||||
|
if ($fp !== false)
|
||||||
|
{
|
||||||
|
$output = fopen('php://output', 'w+b');
|
||||||
|
stream_copy_to_stream($fp, $output);
|
||||||
|
fclose($fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles authentication when downloading attachments from a post or topic
|
||||||
|
*
|
||||||
|
* @param int $topic_id The id of the topic that we are downloading from
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
protected function phpbb_download_handle_forum_auth($topic_id)
|
||||||
|
{
|
||||||
|
$sql_array = array(
|
||||||
|
'SELECT' => 't.topic_visibility, t.forum_id, f.forum_name, f.forum_password, f.parent_id',
|
||||||
|
'FROM' => array(
|
||||||
|
TOPICS_TABLE => 't',
|
||||||
|
FORUMS_TABLE => 'f',
|
||||||
|
),
|
||||||
|
'WHERE' => 't.topic_id = ' . (int) $topic_id . '
|
||||||
|
AND t.forum_id = f.forum_id',
|
||||||
|
);
|
||||||
|
|
||||||
|
$sql = $this->db->sql_build_query('SELECT', $sql_array);
|
||||||
|
$result = $this->db->sql_query($sql);
|
||||||
|
$row = $this->db->sql_fetchrow($result);
|
||||||
|
$this->db->sql_freeresult($result);
|
||||||
|
|
||||||
|
if ($row && !$this->content_visibility->is_visible('topic', $row['forum_id'], $row))
|
||||||
|
{
|
||||||
|
send_status_line(404, 'Not Found');
|
||||||
|
trigger_error('ERROR_NO_ATTACHMENT');
|
||||||
|
}
|
||||||
|
else if ($row && $this->auth->acl_get('u_download') && $this->auth->acl_get('f_download', $row['forum_id']))
|
||||||
|
{
|
||||||
|
if ($row['forum_password'])
|
||||||
|
{
|
||||||
|
// Do something else ... ?
|
||||||
|
login_forum_box($row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
send_status_line(403, 'Forbidden');
|
||||||
|
trigger_error('SORRY_AUTH_VIEW_ATTACH');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles authentication when downloading attachments from PMs
|
||||||
|
*
|
||||||
|
* @param int $msg_id The id of the PM that we are downloading from
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
protected function phpbb_download_handle_pm_auth($msg_id)
|
||||||
|
{
|
||||||
|
if (!$this->auth->acl_get('u_pm_download'))
|
||||||
|
{
|
||||||
|
send_status_line(403, 'Forbidden');
|
||||||
|
trigger_error('SORRY_AUTH_VIEW_ATTACH');
|
||||||
|
}
|
||||||
|
|
||||||
|
$allowed = $this->phpbb_download_check_pm_auth($msg_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event to modify PM attachments download auth
|
||||||
|
*
|
||||||
|
* @event core.modify_pm_attach_download_auth
|
||||||
|
* @var bool allowed Whether the user is allowed to download from that PM or not
|
||||||
|
* @var int msg_id The id of the PM to download from
|
||||||
|
* @var int user_id The user id for auth check
|
||||||
|
* @since 3.1.11-RC1
|
||||||
|
*/
|
||||||
|
$vars = array('allowed', 'msg_id', 'user_id');
|
||||||
|
extract($this->dispatcher->trigger_event('core.modify_pm_attach_download_auth', compact($vars)));
|
||||||
|
|
||||||
|
if (!$allowed)
|
||||||
|
{
|
||||||
|
send_status_line(403, 'Forbidden');
|
||||||
|
trigger_error('ERROR_NO_ATTACHMENT');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a user can download from a particular PM
|
||||||
|
*
|
||||||
|
* @param int $msg_id The id of the PM that we are downloading from
|
||||||
|
*
|
||||||
|
* @return bool Whether the user is allowed to download from that PM or not
|
||||||
|
*/
|
||||||
|
protected function phpbb_download_check_pm_auth($msg_id)
|
||||||
|
{
|
||||||
|
$user_id = $this->user->data['user_id'];
|
||||||
|
|
||||||
|
// Check if the attachment is within the users scope...
|
||||||
|
$sql = 'SELECT msg_id
|
||||||
|
FROM ' . PRIVMSGS_TO_TABLE . '
|
||||||
|
WHERE msg_id = ' . (int) $msg_id . '
|
||||||
|
AND (
|
||||||
|
user_id = ' . (int) $user_id . '
|
||||||
|
OR author_id = ' . (int) $user_id . '
|
||||||
|
)';
|
||||||
|
$result = $this->db->sql_query_limit($sql, 1);
|
||||||
|
$allowed = (bool) $this->db->sql_fetchfield('msg_id');
|
||||||
|
$this->db->sql_freeresult($result);
|
||||||
|
|
||||||
|
return $allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the download count of all provided attachments
|
||||||
|
*
|
||||||
|
* @param array|int $ids The attach_id of each attachment
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
protected function phpbb_increment_downloads($ids)
|
||||||
|
{
|
||||||
|
if (!is_array($ids))
|
||||||
|
{
|
||||||
|
$ids = array($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
|
||||||
|
SET download_count = download_count + 1
|
||||||
|
WHERE ' . $this->db->sql_in_set('attach_id', $ids);
|
||||||
|
$this->db->sql_query($sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if downloading item is allowed
|
||||||
|
*/
|
||||||
|
protected function download_allowed()
|
||||||
|
{
|
||||||
|
if (!$this->config['secure_downloads'])
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = htmlspecialchars_decode($this->request->header('Referer'));
|
||||||
|
|
||||||
|
if (!$url)
|
||||||
|
{
|
||||||
|
return ($this->config['secure_allow_empty_referer']) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split URL into domain and script part
|
||||||
|
$url = @parse_url($url);
|
||||||
|
|
||||||
|
if ($url === false)
|
||||||
|
{
|
||||||
|
return ($this->config['secure_allow_empty_referer']) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostname = $url['host'];
|
||||||
|
unset($url);
|
||||||
|
|
||||||
|
$allowed = ($this->config['secure_allow_deny']) ? false : true;
|
||||||
|
$iplist = array();
|
||||||
|
|
||||||
|
if (($ip_ary = @gethostbynamel($hostname)) !== false)
|
||||||
|
{
|
||||||
|
foreach ($ip_ary as $ip)
|
||||||
|
{
|
||||||
|
if ($ip)
|
||||||
|
{
|
||||||
|
$iplist[] = $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for own server...
|
||||||
|
$server_name = $this->user->host;
|
||||||
|
|
||||||
|
// Forcing server vars is the only way to specify/override the protocol
|
||||||
|
if ($this->config['force_server_vars'] || !$server_name)
|
||||||
|
{
|
||||||
|
$server_name = $this->config['server_name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('#^.*?' . preg_quote($server_name, '#') . '.*?$#i', $hostname))
|
||||||
|
{
|
||||||
|
$allowed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get IP's and Hostnames
|
||||||
|
if (!$allowed)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT site_ip, site_hostname, ip_exclude
|
||||||
|
FROM ' . SITELIST_TABLE;
|
||||||
|
$result = $this->db->sql_query($sql);
|
||||||
|
|
||||||
|
while ($row = $this->db->sql_fetchrow($result))
|
||||||
|
{
|
||||||
|
$site_ip = trim($row['site_ip']);
|
||||||
|
$site_hostname = trim($row['site_hostname']);
|
||||||
|
|
||||||
|
if ($site_ip)
|
||||||
|
{
|
||||||
|
foreach ($iplist as $ip)
|
||||||
|
{
|
||||||
|
if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_ip, '#')) . '$#i', $ip))
|
||||||
|
{
|
||||||
|
if ($row['ip_exclude'])
|
||||||
|
{
|
||||||
|
$allowed = ($this->config['secure_allow_deny']) ? false : true;
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$allowed = ($this->config['secure_allow_deny']) ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($site_hostname)
|
||||||
|
{
|
||||||
|
if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($site_hostname, '#')) . '$#i', $hostname))
|
||||||
|
{
|
||||||
|
if ($row['ip_exclude'])
|
||||||
|
{
|
||||||
|
$allowed = ($this->config['secure_allow_deny']) ? false : true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$allowed = ($this->config['secure_allow_deny']) ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->db->sql_freeresult($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the browser has the file already and set the appropriate headers-
|
||||||
|
* @returns false if a resend is in order.
|
||||||
|
*/
|
||||||
|
protected function set_modified_headers($stamp, $browser)
|
||||||
|
{
|
||||||
|
// let's see if we have to send the file at all
|
||||||
|
$last_load = $this->request->header('If-Modified-Since') ? strtotime(trim($this->request->header('If-Modified-Since'))) : false;
|
||||||
|
|
||||||
|
if ($last_load !== false && $last_load >= $stamp)
|
||||||
|
{
|
||||||
|
send_status_line(304, 'Not Modified');
|
||||||
|
// seems that we need those too ... browsers
|
||||||
|
header('Cache-Control: public');
|
||||||
|
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $stamp) . ' GMT');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
namespace phpbb\storage\controller;
|
namespace phpbb\storage\controller;
|
||||||
|
|
||||||
|
use phpbb\cache\service;
|
||||||
use phpbb\config\config;
|
use phpbb\config\config;
|
||||||
use phpbb\storage\storage;
|
use phpbb\storage\storage;
|
||||||
|
|
||||||
@ -23,8 +24,9 @@ class avatar extends controller
|
|||||||
|
|
||||||
protected $allowed_extensions = ['png', 'gif', 'jpg', 'jpeg'];
|
protected $allowed_extensions = ['png', 'gif', 'jpg', 'jpeg'];
|
||||||
|
|
||||||
public function __construct(config $config, storage $storage)
|
public function __construct(service $cache, config $config, storage $storage)
|
||||||
{
|
{
|
||||||
|
$this->cache = $cache;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->storage = $storage;
|
$this->storage = $storage;
|
||||||
}
|
}
|
||||||
|
@ -13,37 +13,38 @@
|
|||||||
|
|
||||||
namespace phpbb\storage\controller;
|
namespace phpbb\storage\controller;
|
||||||
|
|
||||||
|
|
||||||
|
use phpbb\cache\service;
|
||||||
use phpbb\storage\storage;
|
use phpbb\storage\storage;
|
||||||
|
|
||||||
class controller
|
class controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/** @var service */
|
||||||
|
protected $cache;
|
||||||
|
|
||||||
/** @var storage */
|
/** @var storage */
|
||||||
protected $storage;
|
protected $storage;
|
||||||
|
|
||||||
public function __construct(storage $storage)
|
public function __construct(service $cache, storage $storage)
|
||||||
{
|
{
|
||||||
|
$this->cache = $cache;
|
||||||
$this->storage = $storage;
|
$this->storage = $storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle($file)
|
public function handle($file)
|
||||||
{
|
{
|
||||||
if (!function_exists('file_gc'))
|
|
||||||
{
|
|
||||||
global $phpbb_root_path, $phpEx;
|
|
||||||
require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->is_allowed($file))
|
if (!$this->is_allowed($file))
|
||||||
{
|
{
|
||||||
send_status_line(403, 'Forbidden');
|
send_status_line(403, 'Forbidden');
|
||||||
file_gc();
|
$this->file_gc();
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->file_exists($file))
|
if (!$this->file_exists($file))
|
||||||
{
|
{
|
||||||
send_status_line(404, 'Not Found');
|
send_status_line(404, 'Not Found');
|
||||||
file_gc();
|
$this->file_gc();
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,12 +63,6 @@ class controller
|
|||||||
|
|
||||||
protected function send($file)
|
protected function send($file)
|
||||||
{
|
{
|
||||||
if (!function_exists('file_gc'))
|
|
||||||
{
|
|
||||||
global $phpbb_root_path, $phpEx;
|
|
||||||
require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!headers_sent())
|
if (!headers_sent())
|
||||||
{
|
{
|
||||||
header('Cache-Control: public');
|
header('Cache-Control: public');
|
||||||
@ -95,7 +90,7 @@ class controller
|
|||||||
$fp = $this->storage->read_stream($file);
|
$fp = $this->storage->read_stream($file);
|
||||||
|
|
||||||
// Close db connection
|
// Close db connection
|
||||||
file_gc(false);
|
$this->file_gc(false);
|
||||||
|
|
||||||
$output = fopen('php://output', 'w+b');
|
$output = fopen('php://output', 'w+b');
|
||||||
|
|
||||||
@ -104,8 +99,29 @@ class controller
|
|||||||
fclose($fp);
|
fclose($fp);
|
||||||
fclose($output);
|
fclose($output);
|
||||||
|
|
||||||
// ??
|
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Garbage Collection
|
||||||
|
*
|
||||||
|
* @param bool $exit Whether to die or not.
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
protected function file_gc($exit = true)
|
||||||
|
{
|
||||||
|
if (!empty($this->cache))
|
||||||
|
{
|
||||||
|
$this->cache->unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->sql_close();
|
||||||
|
|
||||||
|
if ($exit)
|
||||||
|
{
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user