Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
14.58% covered (danger)
14.58%
14 / 96
25.00% covered (danger)
25.00%
2 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
upload
14.58% covered (danger)
14.58%
14 / 96
25.00% covered (danger)
25.00%
2 / 8
269.28
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 get_data
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 prepare_form
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 process_form
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
90
 prepare_form_acp
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 delete
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 get_template_name
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 can_upload
0.00% covered (danger)
0.00%
0 / 1
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\avatar\driver;
15
16use bantu\IniGetWrapper\IniGetWrapper;
17use phpbb\config\config;
18use phpbb\event\dispatcher_interface;
19use phpbb\files\factory;
20use phpbb\path_helper;
21use phpbb\routing\helper;
22use phpbb\storage\exception\storage_exception;
23use phpbb\storage\storage;
24
25/**
26* Handles avatars uploaded to the board.
27*/
28class upload extends \phpbb\avatar\driver\driver
29{
30    /**
31     * @var helper
32     */
33    private $routing_helper;
34
35    /**
36     * @var storage
37     */
38    protected $storage;
39
40    /**
41    * @var dispatcher_interface
42    */
43    protected $dispatcher;
44
45    /**
46     * @var factory
47     */
48    protected $files_factory;
49
50    /**
51     * @var IniGetWrapper
52     */
53    protected $php_ini;
54
55    /**
56     * Construct a driver object
57     *
58     * @param config $config phpBB configuration
59     * @param string $phpbb_root_path Path to the phpBB root
60     * @param string $php_ext PHP file extension
61     * @param storage $storage phpBB avatar storage
62     * @param path_helper $path_helper phpBB path helper
63     * @param helper $routing_helper phpBB routing helper
64     * @param dispatcher_interface $dispatcher phpBB Event dispatcher object
65     * @param factory $files_factory File classes factory
66     * @param IniGetWrapper $php_ini ini_get() wrapper
67     */
68    public function __construct(config $config, string $phpbb_root_path, string $php_ext, storage $storage, path_helper $path_helper, helper $routing_helper, dispatcher_interface $dispatcher, factory $files_factory, IniGetWrapper $php_ini)
69    {
70        $this->config = $config;
71        $this->phpbb_root_path = $phpbb_root_path;
72        $this->php_ext = $php_ext;
73        $this->storage = $storage;
74        $this->path_helper = $path_helper;
75        $this->routing_helper = $routing_helper;
76        $this->dispatcher = $dispatcher;
77        $this->files_factory = $files_factory;
78        $this->php_ini = $php_ini;
79    }
80
81    /**
82    * {@inheritdoc}
83    */
84    public function get_data($row)
85    {
86        return array(
87            'src' => $this->routing_helper->route('phpbb_storage_avatar', ['file' => $row['avatar']]),
88            'width' => $row['avatar_width'],
89            'height' => $row['avatar_height'],
90        );
91    }
92
93    /**
94    * {@inheritdoc}
95    */
96    public function prepare_form($request, $template, $user, $row, &$error)
97    {
98        if (!$this->can_upload())
99        {
100            return false;
101        }
102
103        $web_path = $this->path_helper->get_web_root_path();
104
105        $template->assign_vars([
106            'AVATAR_ALLOWED_EXTENSIONS' => implode(',', preg_replace('/^/', '.', $this->allowed_extensions)),
107            'AVATAR_UPLOAD_SIZE'        => $this->config['avatar_filesize'],
108            'T_ASSETS_PATH'                => $web_path . '/assets',
109        ]);
110
111        return true;
112    }
113
114    /**
115    * {@inheritdoc}
116    */
117    public function process_form($request, $template, $user, $row, &$error)
118    {
119        if (!$this->can_upload())
120        {
121            return false;
122        }
123
124        /** @var \phpbb\files\upload $upload */
125        $upload = $this->files_factory->get('upload')
126            ->set_error_prefix('AVATAR_')
127            ->set_allowed_extensions($this->allowed_extensions)
128            ->set_max_filesize($this->config['avatar_filesize'])
129            ->set_allowed_dimensions(
130                $this->config['avatar_min_width'],
131                $this->config['avatar_min_height'],
132                $this->config['avatar_max_width'],
133                $this->config['avatar_max_height'])
134            ->set_disallowed_content((isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));
135
136        $upload_file = $request->file('avatar_upload_file');
137
138        if (empty($upload_file['name']))
139        {
140            return false;
141        }
142
143        /** @var \phpbb\files\filespec_storage $file */
144        $file = $upload->handle_upload('files.types.form_storage', 'avatar_upload_file');
145
146        $prefix = $this->config['avatar_salt'] . '_';
147        $file->clean_filename('avatar', $prefix, $row['id']);
148
149        // If there was an error during upload, then abort operation
150        if (count($file->error))
151        {
152            $file->remove($this->storage);
153            $error = $file->error;
154            return false;
155        }
156
157        $filedata = array(
158            'filename'            => $file->get('filename'),
159            'filesize'            => $file->get('filesize'),
160            'mimetype'            => $file->get('mimetype'),
161            'extension'            => $file->get('extension'),
162            'physical_filename'    => $file->get('realname'),
163            'real_filename'        => $file->get('uploadname'),
164        );
165
166        /**
167        * Before moving new file in place (and eventually overwriting the existing avatar with the newly uploaded avatar)
168        *
169        * @event core.avatar_driver_upload_move_file_before
170        * @var    array    filedata            Array containing uploaded file data
171        * @var    \phpbb\files\filespec file    Instance of filespec class
172        * @var    string    prefix                Prefix for the avatar filename
173        * @var    array    row                    Array with avatar row data
174        * @var    array    error                Array of errors, if filled in by this event file will not be moved
175        * @since 3.1.6-RC1
176        * @changed 3.1.9-RC1 Added filedata
177        * @changed 3.2.3-RC1 Added file
178        */
179        $vars = array(
180            'filedata',
181            'file',
182            'prefix',
183            'row',
184            'error',
185        );
186        extract($this->dispatcher->trigger_event('core.avatar_driver_upload_move_file_before', compact($vars)));
187
188        unset($filedata);
189
190        if (!count($error))
191        {
192            // Move file and overwrite any existing image
193            $file->move_file($this->storage, true);
194        }
195
196        // If there was an error during move, then clean up leftovers
197        $error = array_merge($error, $file->error);
198        if (count($error))
199        {
200            $file->remove($this->storage);
201            return false;
202        }
203
204        // Delete current avatar if not overwritten
205        $ext = substr(strrchr($row['avatar'], '.'), 1);
206        if ($ext && $ext !== $file->get('extension'))
207        {
208            $this->delete($row);
209        }
210
211        return array(
212            'avatar' => $row['id'] . '_' . time() . '.' . $file->get('extension'),
213            'avatar_width' => $file->get('width'),
214            'avatar_height' => $file->get('height'),
215        );
216    }
217
218    /**
219    * {@inheritdoc}
220    */
221    public function prepare_form_acp($user)
222    {
223        return array(
224            'avatar_filesize'        => array('lang' => 'MAX_FILESIZE',            'validate' => 'int:0',    'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
225        );
226    }
227
228    /**
229    * {@inheritdoc}
230    */
231    public function delete($row)
232    {
233        $error = array();
234        $prefix = $this->config['avatar_salt'] . '_';
235        $ext = substr(strrchr($row['avatar'], '.'), 1);
236        $filename = $prefix . $row['id'] . '.' . $ext;
237
238        /**
239        * Before deleting an existing avatar
240        *
241        * @event core.avatar_driver_upload_delete_before
242        * @var    string    prefix                Prefix for the avatar filename
243        * @var    array    row                    Array with avatar row data
244        * @var    array    error                Array of errors, if filled in by this event file will not be deleted
245        * @since 3.1.6-RC1
246        * @changed 3.3.0-a1                    Remove destination
247        */
248        $vars = array(
249            'prefix',
250            'row',
251            'error',
252        );
253        extract($this->dispatcher->trigger_event('core.avatar_driver_upload_delete_before', compact($vars)));
254
255        if (!count($error) && $this->storage->exists($filename))
256        {
257            try
258            {
259                $this->storage->delete($filename);
260                return true;
261            }
262            catch (storage_exception $e)
263            {
264                // Fail is covered by return statement below
265            }
266        }
267
268        return false;
269    }
270
271    /**
272    * {@inheritdoc}
273    */
274    public function get_template_name()
275    {
276        return 'ucp_avatar_options_upload.html';
277    }
278
279    /**
280    * Check if user is able to upload an avatar to a temporary folder
281    *
282    * @return bool True if user can upload, false if not
283    */
284    protected function can_upload()
285    {
286        return (bool) $this->php_ini->getBool('file_uploads');
287    }
288}