Compare commits

...

6 commits

Author SHA1 Message Date
Ruben
6a3459048a
Merge 4372962e1d into bdbd0be548 2025-05-02 07:16:19 +00:00
Marc Alexander
bdbd0be548
Merge branch '3.3.x' 2025-05-02 08:32:19 +02:00
Marc Alexander
1b2ac50cfd
Merge pull request #6810 from rxu/ticket/17504
[ticket/17504] Fix tests failure caused by ondrej/php PPA repo label changed
2025-04-28 21:17:23 +02:00
rxu
779bec5fcf
[ticket/17504] Run apt-get update on runner lever rather than in bash scripts
PHPBB-17504
2025-04-28 23:28:05 +07:00
rxu
f512af1823
[ticket/17504] Fix tests
Fix the following apt-get update issue with ondrej/php PPA repo:
Repository 'https://ppa.launchpadcontent.net/ondrej/php/ubuntu noble InRelease'
changed its 'Label' value from '***** The main PPA for supported PHP versions
with many PECL extensions *****' to 'PPA for PHP'

Alternative fix might be: sudo apt update && sudo apt full-upgrade -y

PHPBB-17504
2025-04-28 21:17:57 +07:00
Ruben Calvo
4372962e1d
[ticket/17447] Add http range requests to attachments downloads
PHPBB-17447
2025-04-02 16:57:51 +02:00
7 changed files with 100 additions and 31 deletions

View file

@ -10,5 +10,4 @@
#
set -e
sudo apt-get update
sudo apt-get install -y parallel libimage-exiftool-perl

View file

@ -11,7 +11,6 @@
set -e
set -x
sudo apt-get update
sudo apt-get install -q -y sphinxsearch
DIR=$(dirname "$0")

View file

@ -10,5 +10,4 @@
#
set -e
sudo apt-get update
sudo apt-get install -y expect-dev

View file

@ -11,7 +11,6 @@
set -e
set -x
sudo apt-get update
sudo apt-get install -y nginx coreutils
sudo service nginx stop

View file

@ -28,6 +28,10 @@ jobs:
name: PHP ${{ matrix.php }} - ${{ matrix.db }}
steps:
- name: Update Ubuntu package lists
run: |
sudo apt-get update -y --allow-releaseinfo-change
- name: Checkout repository
uses: actions/checkout@v4
with:
@ -169,6 +173,10 @@ jobs:
- 6379:6379
steps:
- name: Update Ubuntu package lists
run: |
sudo apt-get update -y --allow-releaseinfo-change
- name: Checkout repository
uses: actions/checkout@v4
@ -308,6 +316,10 @@ jobs:
- 6379:6379
steps:
- name: Update Ubuntu package lists
run: |
sudo apt-get update -y --allow-releaseinfo-change
- name: Checkout repository
uses: actions/checkout@v4
@ -412,6 +424,10 @@ jobs:
steps:
- name: Update Ubuntu package lists
run: |
sudo apt-get update -y --allow-releaseinfo-change
- name: Checkout repository
uses: actions/checkout@v4

View file

@ -4,6 +4,9 @@
*
* You should make a backup from your users table and the avatar directory in case something goes wrong
*/
use phpbb\storage\provider\local;
die("Please read the first lines of this script for instructions on how to enable it");
set_time_limit(0);
@ -30,7 +33,7 @@ if (!isset($config['avatar_salt']))
die('database not up to date');
}
if (!isset($config['storage\\avatar\\config\\path']) || $config['storage\\avatar\\config\\path'] !== 'phpbb\\storage\\provider\\local')
if (!isset($config['storage\\attachment\\provider']) || $config['storage\\attachment\\provider'] !== local::class)
{
die('use local provider');
}

View file

@ -24,8 +24,11 @@ use phpbb\exception\http_exception;
use phpbb\language\language;
use phpbb\mimetype\extension_guesser;
use phpbb\request\request;
use phpbb\storage\provider\local;
use phpbb\storage\storage;
use phpbb\user;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\HttpFoundation\Request as symfony_request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
@ -35,26 +38,41 @@ use Symfony\Component\HttpFoundation\StreamedResponse;
/**
* Controller for /download/attachment/{id} routes
*/
class attachment extends controller
class attachment
{
/** @var auth */
protected $auth;
/** @var service */
protected $cache;
/** @var config */
protected $config;
/** @var content_visibility */
protected $content_visibility;
/** @var driver_interface */
protected $db;
/** @var dispatcher_interface */
protected $dispatcher;
/** @var extension_guesser */
protected $extension_guesser;
/** @var language */
protected $language;
/** @var request */
protected $request;
/** @var storage */
protected $storage;
/** @var symfony_request */
protected $symfony_request;
/** @var user */
protected $user;
@ -76,14 +94,17 @@ class attachment extends controller
*/
public function __construct(auth $auth, service $cache, config $config, content_visibility $content_visibility, driver_interface $db, dispatcher_interface $dispatcher, extension_guesser $extension_guesser, language $language, request $request, storage $storage, symfony_request $symfony_request, user $user)
{
parent::__construct($cache, $db, $extension_guesser, $storage, $symfony_request);
$this->auth = $auth;
$this->cache = $cache;
$this->config = $config;
$this->content_visibility = $content_visibility;
$this->db = $db;
$this->dispatcher = $dispatcher;
$this->extension_guesser = $extension_guesser;
$this->language = $language;
$this->request = $request;
$this->storage = $storage;
$this->symfony_request = $symfony_request;
$this->user = $user;
}
@ -252,21 +273,19 @@ class attachment extends controller
);
extract($this->dispatcher->trigger_event('core.send_file_to_browser_before', compact($vars)));
// TODO: The next lines should go better in prepare, also the mimetype is handled by the storage table
// so probably can be removed
$response = new StreamedResponse();
// Content-type header
$response->headers->set('Content-Type', $attachment['mimetype']);
// Correct the mime type - we force application/octet-stream for all files, except images
if ($display_cat != attachment_category::IMAGE || !str_starts_with($attachment['mimetype'], 'image'))
{
$attachment['mimetype'] = 'application/octet-stream';
}
// Display file types in browser and force download for others
if (strpos($attachment['mimetype'], 'image') !== false
|| strpos($attachment['mimetype'], 'audio') !== false
|| strpos($attachment['mimetype'], 'video') !== false
if (str_contains($attachment['mimetype'], 'image')
|| str_contains($attachment['mimetype'], 'audio')
|| str_contains($attachment['mimetype'], 'video')
)
{
$disposition = $response->headers->makeDisposition(
$disposition = HeaderUtils::makeDisposition(
ResponseHeaderBag::DISPOSITION_INLINE,
$attachment['real_filename'],
$this->filenameFallback($attachment['real_filename'])
@ -274,20 +293,56 @@ class attachment extends controller
}
else
{
$disposition = $response->headers->makeDisposition(
$disposition = HeaderUtils::makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$attachment['real_filename'],
$this->filenameFallback($attachment['real_filename'])
);
}
if ($this->config['storage\\attachment\\provider'] === local::class)
{
$response = new BinaryFileResponse($this->config['storage\\attachment\\config\\path'] . '/' . $attachment['physical_filename']);
}
else
{
$response = new StreamedResponse();
$fp = $this->storage->read($attachment['physical_filename']);
$output = fopen('php://output', 'w+b');
$response->setCallback(function () use ($fp, $output) {
stream_copy_to_stream($fp, $output);
fclose($fp);
fclose($output);
flush();
// Terminate script to avoid the execution of terminate events
// This avoid possible errors with db connection closed
exit;
});
}
// Close db connection
$this->file_gc();
$response->setPrivate();
// Content-type header
$response->headers->set('Content-Type', $attachment['mimetype']);
$response->headers->set('Content-Disposition', $disposition);
$response->isNotModified($this->symfony_request);
// Set expires header for browser cache
$time = new \DateTime();
$response->setExpires($time->modify('+1 year'));
return parent::handle($attachment['physical_filename']);
@set_time_limit(0);
return $response;
}
/**
@ -300,16 +355,6 @@ class attachment extends controller
return !empty($filename) ? $filename : 'File';
}
/**
* {@inheritdoc}
*/
protected function prepare(StreamedResponse $response, string $file): void
{
$response->setPrivate(); // By default, should be private, but make sure of it
parent::prepare($response, $file);
}
/**
* Handles authentication when downloading attachments from a post or topic
*
@ -539,4 +584,13 @@ class attachment extends controller
return $allowed;
}
/**
* Garbage Collection
*/
protected function file_gc(): void
{
$this->cache->unload(); // Equivalent to $this->cache->get_driver()->unload();
$this->db->sql_close();
}
}