Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
avatar
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 5
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 handle
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 is_allowed
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 decode_filename
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 prepare
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13
14namespace phpbb\storage\controller;
15
16use phpbb\cache\service;
17use phpbb\config\config;
18use phpbb\db\driver\driver_interface;
19use phpbb\storage\storage;
20use Symfony\Component\HttpFoundation\Request as symfony_request;
21use Symfony\Component\HttpFoundation\Response;
22use Symfony\Component\HttpFoundation\ResponseHeaderBag;
23use Symfony\Component\HttpFoundation\StreamedResponse;
24
25/**
26 * Controller for /download/avatar/{file} routes
27 */
28class avatar extends controller
29{
30    /** @var config */
31    protected $config;
32
33    /** @var array */
34    protected $allowed_extensions = ['png', 'gif', 'jpg', 'jpeg'];
35
36    /**
37     * Constructor
38     *
39     * @param service                $cache
40     * @param config                $config
41     * @param driver_interface        $db
42     * @param storage                $storage
43     * @param symfony_request        $symfony_request
44     */
45    public function __construct(service $cache, config $config, driver_interface $db, storage $storage, symfony_request $symfony_request)
46    {
47        parent::__construct($cache, $db, $storage, $symfony_request);
48
49        $this->config = $config;
50    }
51
52    /**
53     * {@inheritdoc}
54     */
55    public function handle(string $file): Response
56    {
57        $file = $this->decode_filename($file);
58
59        return parent::handle($file);
60    }
61
62    /**
63     * {@inheritdoc}
64     */
65    protected function is_allowed(string $file): bool
66    {
67        $ext = substr(strrchr($file, '.'), 1);
68
69        // If filename have point and have an allowed extension
70        return strpos($file, '.') && in_array($ext, $this->allowed_extensions, true);
71    }
72
73    /**
74     * Decode avatar filename
75     *
76     * @param string $file        Filename
77     *
78     * @return string Filename in filesystem
79     */
80    protected function decode_filename(string $file): string
81    {
82        $avatar_group = false;
83
84        if (isset($file[0]) && $file[0] === 'g')
85        {
86            $avatar_group = true;
87            $file = substr($file, 1);
88        }
89
90        $ext    = substr(strrchr($file, '.'), 1);
91        $file    = (int) $file;
92
93        return $this->config['avatar_salt'] . '_' . ($avatar_group ? 'g' : '') . $file . '.' . $ext;
94    }
95
96    /**
97     * {@inheritdoc}
98     */
99    protected function prepare(StreamedResponse $response, string $file): void
100    {
101        $response->setPublic();
102
103        $disposition = $response->headers->makeDisposition(
104            ResponseHeaderBag::DISPOSITION_INLINE,
105            rawurlencode($file)
106        );
107
108        $response->headers->set('Content-Disposition', $disposition);
109
110        $time = new \DateTime();
111        $response->setExpires($time->modify('+1 year'));
112
113        parent::prepare($response, $file);
114    }
115}