Passed
Pull Request — development (#3580)
by Emanuele
06:53
created

Attachment::action_no_attach()   A

Complexity

Conditions 3
Paths 6

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 14
nc 6
nop 1
dl 0
loc 26
ccs 0
cts 10
cp 0
crap 12
rs 9.7998
c 2
b 0
f 0
1
<?php
2
3
/**
4
 * Attachment display.
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * This file contains code covered by:
11
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
12
 *
13
 * @version 2.0 dev
14
 *
15
 */
16
17
namespace ElkArte\Controller;
18
19
use ElkArte\AbstractController;
20
use ElkArte\Action;
21
use ElkArte\Errors\AttachmentErrorContext;
22
use ElkArte\Exceptions\Exception;
23
use ElkArte\AttachmentsDirectory;
24
use ElkArte\Attachments\Download;
25
use ElkArte\Http\Headers;
26
use ElkArte\TemporaryAttachmentsList;
27
use ElkArte\Languages\Txt;
28
29
/**
30
 * Everything to do with attachment handling / processing
31
 *
32
 * What it does:
33
 *
34
 * - Handles the downloading of an attachment or avatar
35
 * - Handles the uploading of attachments via Ajax
36
 * - Increments the download count where applicable
37
 *
38
 * @package Attachments
39
 */
40
class Attachment extends AbstractController
41
{
42
	/**
43
	 * {@inheritdoc }
44 2
	 */
45
	public function needTheme($action = '')
46 2
	{
47
		global $modSettings, $maintenance;
48
49 2
		// If guests are not allowed to browse and the user is a guest... kick him!
50
		if (empty($modSettings['allow_guestAccess']) && $this->user->is_guest)
51
		{
52
			return true;
53
		}
54
55 2
		// If not in maintenance or allowed to use the forum in maintenance
56
		if (empty($maintenance) || allowedTo('admin_forum'))
57 2
		{
58
			$sa = $this->_req->getQuery('sa', 'trim', '');
59 2
60
			return $sa === 'ulattach' || $sa === 'rmattach';
61
		}
62
63
		// ... politely kick them out
64
		return true;
65
	}
66
67
	/**
68
	 * {@inheritdoc }
69
	 */
70
	public function trackStats($action = '')
71
	{
72
		return false;
73
	}
74
75
	/**
76
	 * The default action is to download an attachment.
77
	 * This allows ?action=attachment to be forwarded to action_dlattach()
78
	 */
79
	public function action_index()
80
	{
81
		// add a subaction array to act accordingly
82
		$subActions = array(
83
			'dlattach' => array($this, 'action_dlattach'),
84
			'tmpattach' => array($this, 'action_tmpattach'),
85
			'ulattach' => array($this, 'action_ulattach'),
86
			'rmattach' => array($this, 'action_rmattach'),
87
		);
88
89
		// Setup the action handler
90
		$action = new Action('attachments');
91
		$subAction = $action->initialize($subActions, 'dlattach');
92
93
		// Call the action
94
		$action->dispatch($subAction);
95
	}
96
97
	/**
98
	 * Function to upload attachments via ajax calls
99
	 *
100
	 * - Currently called by drag drop attachment functionality
101
	 * - Pass the form data with session vars
102
	 * - Responds back with errors or file data
103
	 */
104
	public function action_ulattach()
105 2
	{
106
		global $context, $modSettings, $txt;
107 2
108
		$resp_data = array();
109 2
		Txt::load('Errors');
110 2
		$context['attachments']['can']['post'] = !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1 && (allowedTo('post_attachment') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_attachments')));
111 2
112
		// Set up the template details
113
		$template_layers = theme()->getLayers();
114 2
		$template_layers->removeAll();
115 2
		theme()->getTemplates()->load('Json');
116 2
		$context['sub_template'] = 'send_json';
117 2
118
		// Make sure the session is still valid
119
		if (checkSession('request', '', false) !== '')
120 2
		{
121
			$context['json_data'] = array('result' => false, 'data' => $txt['session_timeout_file_upload']);
122
123
			return false;
124
		}
125
126
		// We should have files, otherwise why are we here?
127
		if (isset($_FILES['attachment']))
128 2
		{
129
			Txt::load('Post');
130 2
131
			$attach_errors = AttachmentErrorContext::context();
132 2
			$attach_errors->activate();
133 2
134
			if ($context['attachments']['can']['post'] && empty($this->_req->post->from_qr))
135 2
			{
136
				require_once(SUBSDIR . '/Attachments.subs.php');
137 2
138
				processAttachments($this->_req->getPost('msg', 'intval', 0));
139 2
			}
140 2
141
			// Any mistakes?
142
			if ($attach_errors->hasErrors())
143
			{
144 2
				$errors = $attach_errors->prepareErrors();
145
146 2
				// Bad news for you, the attachments did not process, lets tell them why
147
				foreach ($errors as $error)
148
				{
149 2
					$resp_data[] = $error;
150
				}
151 2
152
				$context['json_data'] = array('result' => false, 'data' => $resp_data);
153
			}
154 2
			// No errors, lets get the details of what we have for our response back to the upload dialog
155
			else
156
			{
157
				$tmp_attachments = new TemporaryAttachmentsList();
158
				foreach ($tmp_attachments->toArray() as $val)
159
				{
160
					// We need to grab the name anyhow
161
					if (!empty($val['tmp_name']))
162
					{
163
						$resp_data = array(
164
							'name' => $val['name'],
165
							'attachid' => $val['public_attachid'],
166
							'size' => $val['size'],
167
							'resized' => !empty($val['resized']),
168
						);
169
					}
170
				}
171
172
				$context['json_data'] = array('result' => true, 'data' => $resp_data);
173 2
			}
174
		}
175
		// Could not find the files you claimed to have sent
176
		else
177
		{
178
			$context['json_data'] = array('result' => false, 'data' => $txt['no_files_uploaded']);
179 2
		}
180
	}
181 2
182
	/**
183
	 * Function to remove temporary attachments which were newly added via ajax calls
184
	 * or to remove previous saved ones from an existing post
185
	 *
186
	 * What it does:
187
	 *
188
	 * - Currently called by drag drop attachment functionality
189
	 * - Requires file name and file path
190
	 * - Responds back with success or error
191
	 */
192
	public function action_rmattach()
193
	{
194
		global $context, $txt;
195
196
		// Prepare the template so we can respond with json
197
		$template_layers = theme()->getLayers();
198
		$template_layers->removeAll();
199
		theme()->getTemplates()->load('Json');
200
		$context['sub_template'] = 'send_json';
201
202
		// Make sure the session is valid
203
		if (checkSession('request', '', false) !== '')
204
		{
205
			Txt::load('Errors');
206
			$context['json_data'] = array('result' => false, 'data' => $txt['session_timeout']);
207
208
			return false;
209
		}
210
211
		// We need a filename and path, or we are not going any further
212
		if (isset($this->_req->post->attachid))
213
		{
214
			$result = false;
215
			$tmp_attachments = new TemporaryAttachmentsList();
216
			if ($tmp_attachments->hasAttachments())
217
			{
218
				$attachId = $tmp_attachments->getIdFromPublic($this->_req->post->attachid);
219
220
				try
221
				{
222
					$tmp_attachments->removeById($attachId);
223
					$context['json_data'] = array('result' => true);
224
					$result = true;
225
				}
226
				catch (\Exception $e)
227
				{
228
					$result = $e->getMessage();
229
				}
230
			}
231
232
			// Not a temporary attachment, but a previously uploaded one?
233
			if ($result !== true)
234
			{
235
				require_once(SUBSDIR . '/ManageAttachments.subs.php');
236
				$attachId = $this->_req->getPost('attachid', 'intval');
237
				if (canRemoveAttachment($attachId, $this->user->id))
238
				{
239
					$result_tmp = removeAttachments(array('id_attach' => $attachId), '', true);
240
					if (!empty($result_tmp))
241
					{
242
						$context['json_data'] = array('result' => true);
243
						$result = true;
244
					}
245
					else
246
					{
247
						$result = $result_tmp;
248
					}
249
				}
250
			}
251
252
			if ($result !== true)
253
			{
254
				Txt::load('Errors');
255
				$context['json_data'] = array('result' => false, 'data' => $txt[!empty($result) ? $result : 'attachment_not_found']);
256
			}
257
		}
258
		else
259
		{
260
			Txt::load('Errors');
261
			$context['json_data'] = array('result' => false, 'data' => $txt['attachment_not_found']);
262
		}
263
	}
264
265
	/**
266
	 * Downloads an attachment or avatar, and increments the download count.
267
	 *
268
	 * What it does:
269
	 *
270
	 * - It requires the view_attachments permission. (not for avatars!)
271
	 * - It disables the session parser, and clears any previous output.
272
	 * - It is accessed via the query string ?action=dlattach.
273
	 * - Views to attachments and avatars do not increase hits and are not logged
274
	 *   in the "Who's Online" log.
275
	 *
276
	 * @throws \ElkArte\Exceptions\Exception
277
	 */
278
	public function action_dlattach()
279
	{
280
		global $modSettings, $context, $topic, $board;
281
282
		// Some defaults that we need.
283
		$context['no_last_modified'] = true;
284
		$filename = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $filename is dead and can be removed.
Loading history...
285
286
		// We need to do some work on attachments and avatars.
287
		require_once(SUBSDIR . '/Attachments.subs.php');
288
289
		$attachment_class = new Download($this->_req->query->attach ?? '');
290
291
		$inline = $attachment_class->isTemporary();
292
293
		if ($this->_req->getQuery('type') === 'avatar')
294
		{
295
			$inline = true;
296
			$id_topic = null;
297
		}
298
		// This is just a regular attachment...
299
		else
300
		{
301
			if (empty($topic) && !empty($id_attach))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id_attach seems to never exist and therefore empty should always be true.
Loading history...
302
			{
303
				$id_board = 0;
304
				$id_topic = 0;
305
				$attachPos = getAttachmentPosition($id_attach);
306
				if ($attachPos !== false)
307
				{
308
					list($id_board, $id_topic) = array_values($attachPos);
0 ignored issues
show
Bug introduced by
It seems like $attachPos can also be of type true; however, parameter $array of array_values() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

308
					list($id_board, $id_topic) = array_values(/** @scrutinizer ignore-type */ $attachPos);
Loading history...
309
				}
310
			}
311
			else
312
			{
313
				$id_board = $board;
314
				$id_topic = $topic;
315
			}
316
317
			isAllowedTo('view_attachments', $id_board);
318
		}
319
320
		$type = $this->_req->getQuery('thumb') !== null ? 'thumb' : $this->_req->getQuery('type');
321
		if ($attachment_class->validate($type, $id_topic))
322
		{
323
			// If it isn't yet approved (and is an attachment), do they have permission to view it?
324
			if ($attachment_class->isApproved() == false && $attachment_class->isOwner() == false && $attachment_class->isAvatar() == false)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
325
			{
326
				isAllowedTo('approve_posts', $id_board ?? $board);
327
			}
328
329
			$attachment_class->increaseDownloadCounter();
330
		}
331
332
		$use_compression = !empty($modSettings['enableCompressedOutput']) && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false && function_exists('gzencode');
333
		echo $attachment_class->send($inline, $use_compression);
334
335
		obExit(false);
336
	}
337
}
338