Skip to content

Commit 73de1b8

Browse files
Merge pull request #20030 from MauricioFauth/getNoCacheHeaders-clock-test
Test Core::getNoCacheHeaders() with a frozen clock
2 parents 4a258ca + d152e71 commit 73de1b8

4 files changed

Lines changed: 56 additions & 37 deletions

File tree

src/Core.php

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace PhpMyAdmin;
66

7+
use DateTimeImmutable;
8+
use DateTimeInterface;
9+
use DateTimeZone;
710
use PhpMyAdmin\Error\ErrorHandler;
811
use PhpMyAdmin\Exceptions\MissingExtensionException;
912
use PhpMyAdmin\Http\ServerRequest;
@@ -18,7 +21,6 @@
1821
use function filter_var;
1922
use function function_exists;
2023
use function getenv;
21-
use function gmdate;
2224
use function hash_equals;
2325
use function hash_hmac;
2426
use function header;
@@ -45,7 +47,6 @@
4547
use function unserialize;
4648
use function urldecode;
4749

48-
use const DATE_RFC1123;
4950
use const FILTER_VALIDATE_IP;
5051

5152
/**
@@ -209,10 +210,10 @@ public static function getEnv(string $variableName): string
209210
*
210211
* @return array<string, string>
211212
*/
212-
public static function headerJSON(): array
213+
public static function headerJSON(string $currentDateTime = 'now'): array
213214
{
214215
// No caching
215-
$headers = self::getNoCacheHeaders();
216+
$headers = self::getNoCacheHeaders($currentDateTime);
216217

217218
// Media type
218219
$headers['Content-Type'] = 'application/json; charset=UTF-8';
@@ -227,13 +228,15 @@ public static function headerJSON(): array
227228
}
228229

229230
/** @return array<string, string> */
230-
public static function getNoCacheHeaders(): array
231+
public static function getNoCacheHeaders(string $currentDateTime = 'now'): array
231232
{
232233
$headers = [];
233-
$date = gmdate(DATE_RFC1123);
234+
$formattedDateTime = (new DateTimeImmutable($currentDateTime))
235+
->setTimezone(new DateTimeZone('UTC'))
236+
->format(DateTimeInterface::RFC7231);
234237

235238
// rfc2616 - Section 14.21
236-
$headers['Expires'] = $date;
239+
$headers['Expires'] = $formattedDateTime;
237240

238241
// HTTP/1.1
239242
$headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0';
@@ -244,7 +247,7 @@ public static function getNoCacheHeaders(): array
244247
// test case: exporting a database into a .gz file with Safari
245248
// would produce files not having the current time
246249
// (added this header for Safari but should not harm other browsers)
247-
$headers['Last-Modified'] = $date;
250+
$headers['Last-Modified'] = $formattedDateTime;
248251

249252
return $headers;
250253
}
@@ -253,21 +256,16 @@ public static function getNoCacheHeaders(): array
253256
* @param string $filename Filename to include in headers if empty, none Content-Disposition header will be sent.
254257
* @param string $mimetype MIME type to include in headers.
255258
* @param int $length Length of content (optional)
256-
* @param bool $noCache Whether to include no-caching headers.
257259
*
258260
* @return array<string, string>
259261
*/
260262
public static function getDownloadHeaders(
261263
string $filename,
262264
string $mimetype,
263265
int $length = 0,
264-
bool $noCache = true,
266+
string $currentDateTime = 'now',
265267
): array {
266-
$headers = [];
267-
268-
if ($noCache) {
269-
$headers = self::getNoCacheHeaders();
270-
}
268+
$headers = self::getNoCacheHeaders($currentDateTime);
271269

272270
/* Replace all possibly dangerous chars in filename */
273271
$filename = Sanitize::sanitizeFilename($filename);
@@ -293,15 +291,10 @@ public static function getDownloadHeaders(
293291
* @param string $filename Filename to include in headers if empty, none Content-Disposition header will be sent.
294292
* @param string $mimetype MIME type to include in headers.
295293
* @param int $length Length of content (optional)
296-
* @param bool $noCache Whether to include no-caching headers.
297294
*/
298-
public static function downloadHeader(
299-
string $filename,
300-
string $mimetype,
301-
int $length = 0,
302-
bool $noCache = true,
303-
): void {
304-
$headers = self::getDownloadHeaders($filename, $mimetype, $length, $noCache);
295+
public static function downloadHeader(string $filename, string $mimetype, int $length = 0): void
296+
{
297+
$headers = self::getDownloadHeaders($filename, $mimetype, $length);
305298

306299
// The default output in PMA uses gzip,
307300
// so if we want to output uncompressed file, we should reset the encoding.

src/Header.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ public function getMessage(): string
335335
}
336336

337337
/** @return array<string, string> */
338-
public function getHttpHeaders(): array
338+
public function getHttpHeaders(string $currentDateTime = 'now'): array
339339
{
340340
$headers = [];
341341

@@ -388,7 +388,7 @@ public function getHttpHeaders(): array
388388
*/
389389
$headers['Permissions-Policy'] = 'fullscreen=(self), interest-cohort=()';
390390

391-
$headers = array_merge($headers, Core::getNoCacheHeaders());
391+
$headers = array_merge($headers, Core::getNoCacheHeaders($currentDateTime));
392392

393393
/**
394394
* A different Content-Type is set in {@see \PhpMyAdmin\Controllers\Transformation\WrapperController}.

tests/unit/CoreTest.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -658,9 +658,13 @@ public static function providerForTestPopulateRequestWithEncryptedQueryParamsWit
658658

659659
public function testGetDownloadHeaders(): void
660660
{
661-
$headersList = Core::getDownloadHeaders('test.sql', 'text/x-sql', 100, false);
661+
$headersList = Core::getDownloadHeaders('test.sql', 'text/x-sql', 100, '2015-10-21T05:28:00-02:00');
662662

663663
$expected = [
664+
'Expires' => 'Wed, 21 Oct 2015 07:28:00 GMT',
665+
'Cache-Control' => 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0',
666+
'Pragma' => 'no-cache',
667+
'Last-Modified' => 'Wed, 21 Oct 2015 07:28:00 GMT',
664668
'Content-Description' => 'File Transfer',
665669
'Content-Disposition' => 'attachment; filename="test.sql"',
666670
'Content-Type' => 'text/x-sql',
@@ -672,9 +676,13 @@ public function testGetDownloadHeaders(): void
672676

673677
public function testGetDownloadHeaders2(): void
674678
{
675-
$headersList = Core::getDownloadHeaders('test.sql.gz', 'application/x-gzip', 0, false);
679+
$headersList = Core::getDownloadHeaders('test.sql.gz', 'application/x-gzip', 0, '2015-10-21T05:28:00-02:00');
676680

677681
$expected = [
682+
'Expires' => 'Wed, 21 Oct 2015 07:28:00 GMT',
683+
'Cache-Control' => 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0',
684+
'Pragma' => 'no-cache',
685+
'Last-Modified' => 'Wed, 21 Oct 2015 07:28:00 GMT',
678686
'Content-Description' => 'File Transfer',
679687
'Content-Disposition' => 'attachment; filename="test.sql.gz"',
680688
'Content-Type' => 'application/x-gzip',
@@ -702,4 +710,28 @@ public function testGetEnv(): void
702710

703711
self::assertSame('', Core::getEnv('PHPMYADMIN_GET_ENV_TEST'));
704712
}
713+
714+
public function testGetNoCacheHeaders(): void
715+
{
716+
$expected = [
717+
'Expires' => 'Wed, 21 Oct 2015 07:28:00 GMT',
718+
'Cache-Control' => 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0',
719+
'Pragma' => 'no-cache',
720+
'Last-Modified' => 'Wed, 21 Oct 2015 07:28:00 GMT',
721+
];
722+
self::assertSame($expected, Core::getNoCacheHeaders('2015-10-21T05:28:00-02:00'));
723+
}
724+
725+
public function testHeaderJSON(): void
726+
{
727+
$expected = [
728+
'Expires' => 'Wed, 21 Oct 2015 07:28:00 GMT',
729+
'Cache-Control' => 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0',
730+
'Pragma' => 'no-cache',
731+
'Last-Modified' => 'Wed, 21 Oct 2015 07:28:00 GMT',
732+
'Content-Type' => 'application/json; charset=UTF-8',
733+
'X-Content-Type-Options' => 'nosniff',
734+
];
735+
self::assertSame($expected, Core::headerJSON('2015-10-21T05:28:00-02:00'));
736+
}
705737
}

tests/unit/HeaderTest.php

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@
2323
use PHPUnit\Framework\Attributes\Medium;
2424
use ReflectionProperty;
2525

26-
use function gmdate;
27-
28-
use const DATE_RFC1123;
29-
3026
#[CoversClass(Header::class)]
3127
#[Medium]
3228
class HeaderTest extends AbstractTestCase
@@ -193,7 +189,6 @@ public function testGetHttpHeaders(
193189
string $expectedWebKitCsp,
194190
): void {
195191
$header = $this->getNewHeaderInstance();
196-
$date = gmdate(DATE_RFC1123);
197192

198193
$config = Config::getInstance();
199194
$config->set('AllowThirdPartyFraming', $frameOptions);
@@ -203,7 +198,7 @@ public function testGetHttpHeaders(
203198
$config->set('CaptchaCsp', $captchaCsp);
204199

205200
$expected = [
206-
'X-Frame-Options' => $expectedFrameOptions,
201+
'X-Frame-Options' => $expectedFrameOptions ?? '',
207202
'Referrer-Policy' => 'same-origin',
208203
'Content-Security-Policy' => $expectedCsp,
209204
'X-Content-Security-Policy' => $expectedXCsp,
@@ -213,18 +208,17 @@ public function testGetHttpHeaders(
213208
'X-Permitted-Cross-Domain-Policies' => 'none',
214209
'X-Robots-Tag' => 'noindex, nofollow',
215210
'Permissions-Policy' => 'fullscreen=(self), interest-cohort=()',
216-
'Expires' => $date,
211+
'Expires' => 'Wed, 21 Oct 2015 07:28:00 GMT',
217212
'Cache-Control' => 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0',
218213
'Pragma' => 'no-cache',
219-
'Last-Modified' => $date,
214+
'Last-Modified' => 'Wed, 21 Oct 2015 07:28:00 GMT',
220215
'Content-Type' => 'text/html; charset=utf-8',
221216
];
222217
if ($expectedFrameOptions === null) {
223218
unset($expected['X-Frame-Options']);
224219
}
225220

226-
$headers = $this->callFunction($header, Header::class, 'getHttpHeaders', []);
227-
self::assertSame($expected, $headers);
221+
self::assertSame($expected, $header->getHttpHeaders('2015-10-21T05:28:00-02:00'));
228222
}
229223

230224
/** @return mixed[][] */

0 commit comments

Comments
 (0)