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

Download   F

Complexity

Total Complexity 64

Size/Duplication

Total Lines 583
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 219
c 3
b 0
f 0
dl 0
loc 583
rs 3.28
wmc 64

17 Methods

Rating   Name   Duplication   Size   Complexity  
A isCompressible() 0 4 1
A getFromTopic() 0 25 2
B validate() 0 44 6
A __construct() 0 9 2
A rebuildData() 0 34 5
A noAttach() 0 25 3
A getAvatar() 0 31 2
A send_file() 0 18 3
A isTemporary() 0 4 1
B prepare_headers() 0 77 11
C send() 0 38 14
A isAvatar() 0 3 1
A increaseDownloadCounter() 0 13 3
A getThumbFromTopic() 0 62 4
A isApproved() 0 3 1
A isOwner() 0 3 2
A validateTemporary() 0 33 3

How to fix   Complexity   

Complex Class

Complex classes like Download often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Download, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This is the file that takes care of sending the bits to the browser
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\Attachments;
18
19
use ElkArte\Graphics\TextImage;
20
use ElkArte\Graphics\Image;
21
use ElkArte\Exceptions\Exception;
22
use ElkArte\AttachmentsDirectory;
23
use ElkArte\TemporaryAttachmentsList;
24
use ElkArte\Http\Headers;
25
use ElkArte\Languages\Txt;
26
use ElkArte\User;
27
use ElkArte\HttpReq;
28
29
/**
30
 * This class takes one file and if it exists it sends it back to the browser that requesetd it
31
 */
32
class Download
33
{
34
	protected $string_attach = '';
35
	protected $id_attach = 0;
36
	protected $file_path = null;
37
	protected $data = [];
38
	protected $db = null;
39
40
	/**
41
	 * Starts up the download process
42
	 *
43
	 * @param string $id_attach String version of the attachment id
44
	 */
45
	public function __construct($id_attach)
46
	{
47
		$this->string_attach = $id_attach;
48
		// Non-temporary attachments shall have integer ids
49
		if (!$this->isTemporary())
50
		{
51
			$this->id_attach = (int) $id;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id seems to be never defined.
Loading history...
52
		}
53
		$this->db = database();
54
	}
55
56
	/**
57
	 * Temporary attachments have special names, so need slightly special handling
58
	 */
59
	public function isTemporary()
60
	{
61
		// Temporary attachment, special case...
62
		return strpos($this->string_attach, 'post_tmp_' . User::$info->id . '_') !== false;
63
	}
64
65
	/**
66
	 * Fetches data from the db and determine if the attachment actually exists
67
	 *
68
	 * @param null|string $text
69
	 * @param null|int $id_topic
70
	 * @throws \ElkArte\Exceptions\Exception
71
	 */
72
	public function validate($type, $id_topic = null)
73
	{
74
		if (empty($this->id_attach))
75
		{
76
			return false;
77
		}
78
79
		if ($this->isTemporary())
80
		{
81
			return $this->validateTemporary();
82
		}
83
84
		if ($type === Attachment::DL_TYPE_AVATAR)
85
		{
86
			$data = $this->getAvatar();
87
		}
88
		else
89
		{
90
			if ($type === Attachment::DL_TYPE_THUMB)
91
			{
92
				$data = $this->getThumbFromTopic($id_topic);
93
				if (empty($data['filename']))
94
				{
95
					$data = array_merge($data, $this->rebuildData($id_topic));
96
				}
97
			}
98
			else
99
			{
100
				$data = $this->getFromTopic($id_topic);
101
			}
102
		}
103
		$this->data = $data;
104
105
		$this->data['id_folder'] = $data['id_folder'] ?? '';
106
		$this->data['real_filename'] = $data['filename'] ?? '';
107
		$this->data['file_hash'] = $data['file_hash'] ?? '';
108
		$this->data['file_ext'] = $data['fileext'] ?? '';
109
		$this->data['id_attach'] = $data['id_attach'] ?? '';
110
		$this->data['attachment_type'] = $data['attachment_type'] ?? '';
111
		$this->data['mime_type'] = $data['mime_type'] ?? '';
112
		$this->data['is_approved'] = $data['approved'] ?? '';
113
		$this->data['id_member'] = $data['id_member'] ?? '';
114
115
		return !empty($this->data['real_filename']);
116
	}
117
118
	/**
119
	 * Same as validate, but for temporary attachments
120
	 */
121
	protected function validateTemporary()
122
	{
123
		global $modSettings;
124
125
		$tmp_attachments = new TemporaryAttachmentsList();
126
		$attachmentsDir = new AttachmentsDirectory($modSettings, $this->db);
127
128
		try
129
		{
130
			$this->data = $tmp_attachments->getTempAttachById($this->_req->query->attach, $attachmentsDir, User::$info->id);
0 ignored issues
show
Bug Best Practice introduced by
The property _req does not exist on ElkArte\Attachments\Download. Did you maybe forget to declare it?
Loading history...
131
			$this->data['file_ext'] = pathinfo($this->data['name'], PATHINFO_EXTENSION);
132
			$this->file_path = $this->data['tmp_name'];
133
			$this->data['id_attach'] = $this->data['attachid'];
134
			$this->data['real_filename'] = $this->data['name'];
135
			$this->data['mime_type'] = $this->data['type'];
136
		}
137
		catch (\Exception $e)
138
		{
139
			throw new Exception($e->getMessage(), false);
140
		}
141
142
		$this->data['resize'] = true;
143
144
		// Return mime type ala mimetype extension
145
		if (substr(getMimeType($this->file_path), 0, 5) !== 'image')
146
		{
147
			$checkMime = returnMimeThumb($file_ext);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $file_ext seems to be never defined.
Loading history...
148
			$mime_type = 'image/png';
0 ignored issues
show
Unused Code introduced by
The assignment to $mime_type is dead and can be removed.
Loading history...
149
			$this->data['resize'] = false;
150
			$this->file_path = $checkMime;
151
		}
152
153
		return !empty($this->data['real_filename']);
154
	}
155
156
	/**
157
	 * Reads and returns the data of the image
158
	 *
159
	 * @param bool $inline
160
	 * @param bool $use_compression
161
	 */
162
	public function send($inline, $use_compression)
163
	{
164
		if (empty($this->id_attach) || empty($this->data['real_filename']))
165
		{
166
			return $this->noAttach();
167
		}
168
169
		if ($this->file_path === null)
170
		{
171
			$this->file_path = getAttachmentFilename($this->data['real_filename'], $this->id_attach, $this->data['id_folder'], false, $this->data['file_hash']);
172
		}
173
174
		$eTag = '"' . substr($this->id_attach . $this->data['real_filename'] . @filemtime($this->file_path), 0, 64) . '"';
0 ignored issues
show
Bug introduced by
Are you sure @filemtime($this->file_path) of type false|integer can be used in concatenation? ( Ignorable by Annotation )

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

174
		$eTag = '"' . substr($this->id_attach . $this->data['real_filename'] . /** @scrutinizer ignore-type */ @filemtime($this->file_path), 0, 64) . '"';
Loading history...
175
		$disposition = $inline ? 'inline' : 'attachment';
176
		$do_cache = !($inline === false && getValidMimeImageType($this->data['file_ext']) !== '');
177
178
		// Make sure the mime type warrants an inline display.
179
		if ($inline && !empty($this->data['mime_type']) && strpos($this->data['mime_type'], 'image/') !== 0)
180
		{
181
			$this->data['mime_type'] = '';
182
		}
183
		// Does this have a mime type?
184
		elseif (empty($this->data['mime_type']) || $inline === false && getValidMimeImageType($this->data['file_ext']) !== '')
185
		{
186
			$this->data['mime_type'] = '';
187
		}
188
		$this->prepare_headers($this->file_path, $eTag, $this->data['mime_type'], $disposition, $this->data['real_filename'], $do_cache);
189
190
		if (!empty($this->data['resize']))
191
		{
192
			// Create a thumbnail image
193
			$image = new Image($this->file_path);
194
195
			$this->file_path = $this->file_path . '_thumb';
196
			$image->createThumbnail(100, 100, $this->file_path, '',false);
197
		}
198
199
		return $this->send_file($use_compression && $this->isCompressible());
200
	}
201
202
	/**
203
	 * Is the atachment is approved or not
204
	 */
205
	public function isApproved()
206
	{
207
		return !empty($this->data['is_approved']);
208
	}
209
210
	/**
211
	 * If the user requesting the attachment is its owner
212
	 */
213
	public function isOwner()
214
	{
215
		return (int) $this->data['id_member'] !== 0 && User::$info->id === (int) $this->data['id_member'];
216
	}
217
218
	/**
219
	 * If the attachment is an avatar
220
	 */
221
	public function isAvatar()
222
	{
223
		return $this->data['attachment_type'] == Attachment::DB_TYPE_AVATAR;
224
	}
225
226
	/**
227
	 * Generates a language image based on text for display, outputs image and exits
228
	 *
229
	 * @param null|string $text
230
	 * @throws \ElkArte\Exceptions\Exception
231
	 */
232
	public function noAttach($text = null)
233
	{
234
		global $txt;
235
236
		if ($text === null)
237
		{
238
			Txt::load('Errors');
239
			$text = $txt['attachment_not_found'];
240
		}
241
242
		try
243
		{
244
			$img = new TextImage($text);
245
			$img = $img->generate(200);
246
		}
247
		catch (\Exception $e)
248
		{
249
			throw new Exception('no_access', false);
250
		}
251
252
		$this->prepare_headers('no_image', 'no_image', 'image/png', 'inline', 'no_image.png', true, false);
253
254
		Headers::instance()->sendHeaders();
255
256
		return $img;
257
	}
258
259
	/**
260
	 * Increase download counter for id_attach.
261
	 *
262
	 * What it does:
263
	 *
264
	 * - Does not check if it's a thumbnail.
265
	 *
266
	 * @param int $id_attach
267
	 * @package Attachments
268
	 */
269
	public function increaseDownloadCounter()
270
	{
271
		if (empty($this->id_attach) || $this->isAvatar())
272
		{
273
			return;
274
		}
275
276
		$this->db->fetchQuery('
277
			UPDATE {db_prefix}attachments
278
			SET downloads = downloads + 1
279
			WHERE id_attach = {int:id_attach}',
280
			array(
281
				'id_attach' => $this->id_attach,
282
			)
283
		);
284
	}
285
286
	/**
287
	 * Sends the requested file to the user.  If the file is compressible e.g.
288
	 * has a mine type of text/??? may compress the file prior to sending.
289
	 */
290
	protected function send_file($use_compression)
291
	{
292
		$headers = Headers::instance();
293
		$body = file_get_contents($this->file_path);
294
295
		// If we can/should compress this file
296
		if ($use_compression && strlen($body) > 250)
297
		{
298
			$body = gzencode($body, 2);
299
			$headers
300
				->header('Content-Encoding', 'gzip')
301
				->header('Vary', 'Accept-Encoding');
302
		}
303
304
		// Someone is getting a present
305
		$headers->header('Content-Length', strlen($body));
306
		$headers->send();
307
		return $body;
308
	}
309
310
	/**
311
	 * If the mime type benefits from compression e.g. text/xyz and gzencode is
312
	 * available and the user agent accepts gzip, then return true, else false
313
	 *
314
	 * @return bool if we should compress the file
315
	 */
316
	protected function isCompressible()
317
	{
318
		// Not compressible, or not supported / requested by client
319
		return (bool) preg_match('~^(?:text/|application/(?:json|xml|rss\+xml)$)~i', $this->data['mime_type']);
320
	}
321
322
	/**
323
	 * Takes care of sending out the most common headers.
324
	 *
325
	 * @param string $filename Full path+file name of the file in the filesystem
326
	 * @param string $eTag ETag cache validator
327
	 * @param string $mime_type The mime-type of the file
328
	 * @param string $disposition The value of the Content-Disposition header
329
	 * @param string $real_filename The original name of the file
330
	 * @param bool $do_cache If send the a max-age header or not
331
	 * @param bool $check_filename When false, any check on $filename is skipped
332
	 */
333
	protected function prepare_headers($filename, $eTag, $mime_type, $disposition, $real_filename, $do_cache, $check_filename = true)
334
	{
335
		global $txt;
336
337
		$headers = Headers::instance();
338
		$request = HttpReq::instance();
339
340
		// No point in a nicer message, because this is supposed to be an attachment anyway...
341
		if ($check_filename && !file_exists($filename))
342
		{
343
			Txt::load('Errors');
344
345
			$protocol = preg_match('~HTTP/1\.[01]~i', $request->server->SERVER_PROTOCOL) ? $request->server->SERVER_PROTOCOL : 'HTTP/1.0';
346
			$headers
347
				->removeHeader('all')
348
				->headerSpecial($protocol . ' 404 Not Found')
349
				->sendHeaders();
350
351
			// We need to die like this *before* we send any anti-caching headers as below.
352
			die('404 - ' . $txt['attachment_not_found']);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
353
		}
354
355
		// If it hasn't been modified since the last time this attachment was retrieved, there's no need to display it again.
356
		if (!empty($request->server->HTTP_IF_MODIFIED_SINCE))
357
		{
358
			list ($modified_since) = explode(';', $request->server->HTTP_IF_MODIFIED_SINCE);
359
			if (!$check_filename || strtotime($modified_since) >= filemtime($filename))
360
			{
361
				@ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ob_end_clean(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

361
				/** @scrutinizer ignore-unhandled */ @ob_end_clean();

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
362
363
				// Answer the question - no, it hasn't been modified ;).
364
				$headers
365
					->removeHeader('all')
366
					->headerSpecial('HTTP/1.1 304 Not Modified')
367
					->sendHeaders();
368
				exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
369
			}
370
		}
371
372
		// Check whether the ETag was sent back, and cache based on that...
373
		if (!empty($request->server->HTTP_IF_NONE_MATCH) && strpos($request->server->HTTP_IF_NONE_MATCH, $eTag) !== false)
374
		{
375
			@ob_end_clean();
376
377
			$headers
378
				->removeHeader('all')
379
				->headerSpecial('HTTP/1.1 304 Not Modified')
380
				->sendHeaders();
381
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
382
		}
383
384
		// Send the attachment headers.
385
		$headers
386
			->header('Expires', gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT')
387
			->header('Last-Modified', gmdate('D, d M Y H:i:s', $check_filename ? filemtime($filename) : time() - 525600 * 60) . ' GMT')
388
			->header('Accept-Ranges', 'bytes')
389
			->header('Connection', 'close')
390
			->header('ETag', $eTag);
391
392
		// Different browsers like different standards...
393
		$headers->setAttachmentFileParams($mime_type, $real_filename, $disposition);
394
395
		// If this has an "image extension" - but isn't actually an image - then ensure it isn't cached cause of silly IE.
396
		if ($do_cache)
397
		{
398
			$headers
399
				->header('Cache-Control', 'max-age=' . (525600 * 60) . ', private');
400
		}
401
		else
402
		{
403
			$headers
404
				->header('Pragma', 'no-cache')
405
				->header('Cache-Control', 'no-cache');
406
		}
407
408
		// Try to buy some time...
409
		detectServer()->setTimeLimit(600);
410
	}
411
412
	/**
413
	 * Some magic in case data are not available immediately
414
	 */
415
	protected function rebuildData($id_topic)
416
	{
417
		global $modSettings;
418
419
		$full_attach = $this->getFromTopic($id_topic);
420
		$attachment = [
421
			'filename' => !empty($full_attach['filename']) ? $full_attach['filename'] : '',
422
			'id_attach' => 0,
423
			'attachment_type' => 0,
424
			'approved' => $full_attach['approved'],
425
			'id_member' => $full_attach['id_member']
426
		];
427
428
		// If it is a known extension, show a mimetype extension image
429
		$check = returnMimeThumb(!empty($full_attach['fileext']) ? $full_attach['fileext'] : 'default');
430
		if ($check !== false)
0 ignored issues
show
introduced by
The condition $check !== false is always true.
Loading history...
431
		{
432
			$attachment['fileext'] = 'png';
433
			$attachment['mime_type'] = 'image/png';
434
			$this->file_path = $check;
435
		}
436
		else
437
		{
438
			$attachmentsDir = new AttachmentsDirectory($modSettings, $this->db);
439
			$this->file_path = $attachmentsDir->getCurrent() . '/' . $attachment['filename'];
440
		}
441
442
		if (substr(getMimeType($this->file_path), 0, 5) !== 'image')
443
		{
444
			$attachment['fileext'] = 'png';
445
			$attachment['mime_type'] = 'image/png';
446
			$this->file_path = $settings['theme_dir'] . '/images/mime_images/default.png';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $settings seems to be never defined.
Loading history...
447
		}
448
		return $attachment;
449
	}
450
451
	/**
452
	 * Get the avatar with the specified ID.
453
	 *
454
	 * What it does:
455
	 *
456
	 * - It gets avatar data (folder, name of the file, filehash, etc)
457
	 * from the database.
458
	 * - Must return the same array keys as getAttachmentFromTopic()
459
	 *
460
	 * @return array
461
	 * @package Attachments
462
	 */
463
	protected function getAvatar()
464
	{
465
		// Use our cache when possible
466
		$cache = array();
467
		if (Cache::instance()->getVar($cache, 'getAvatar_id-' . $this->id_attach))
0 ignored issues
show
Bug introduced by
The type ElkArte\Attachments\Cache was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
468
		{
469
			return $cache;
470
		}
471
472
		$avatarData = array();
473
		$this->db->fetchQuery('
474
			SELECT 
475
				id_folder, filename, file_hash, fileext, id_attach, attachment_type,
476
				mime_type, approved, id_member
477
			FROM {db_prefix}attachments
478
			WHERE id_attach = {int:id_attach}
479
				AND id_member > {int:blank_id_member}
480
			LIMIT 1',
481
			array(
482
				'id_attach' => $this->id_attach,
483
				'blank_id_member' => 0,
484
			)
485
		)->fetch_callback(
486
			function ($row) use (&$avatarData) {
487
				$avatarData = $row;
488
			}
489
		);
490
491
		Cache::instance()->put('getAvatar_id-' . $this->id_attach, $avatarData, 900);
492
493
		return $avatarData;
494
	}
495
496
	/**
497
	 * Get the specified attachment.
498
	 *
499
	 * What it does:
500
	 *
501
	 * - This includes a check of the topic
502
	 * - it only returns the attachment if it's indeed attached to a message in the topic given as parameter, and
503
	 * query_see_board...
504
	 * - Must return the same array keys as getAvatar() and getAttachmentThumbFromTopic()
505
	 *
506
	 * @param int $id_topic
507
	 *
508
	 * @return array
509
	 * @package Attachments
510
	 */
511
	protected function getFromTopic($id_topic)
512
	{
513
		// Make sure this attachment is on this board.
514
		$attachmentData = array();
515
		$request = $this->db->fetchQuery('
516
			SELECT 
517
				a.id_folder, a.filename, a.file_hash, a.fileext, a.id_attach, a.attachment_type, 
518
				a.mime_type, a.approved, m.id_member
519
			FROM {db_prefix}attachments AS a
520
				INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg AND m.id_topic = {int:current_topic})
521
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
522
			WHERE a.id_attach = {int:attach}
523
			LIMIT 1',
524
			array(
525
				'attach' => $this->id_attach,
526
				'current_topic' => $id_topic,
527
			)
528
		);
529
		if ($request->num_rows() != 0)
530
		{
531
			$attachmentData = $request->fetch_assoc();
532
		}
533
		$request->free_result();
534
535
		return $attachmentData;
536
	}
537
538
	/**
539
	 * Get the thumbnail of specified attachment.
540
	 *
541
	 * What it does:
542
	 *
543
	 * - This includes a check of the topic
544
	 * - it only returns the attachment if it's indeed attached to a message in the topic given as parameter, and
545
	 * query_see_board...
546
	 * - Must return the same array keys as getAvatar() & getAttachmentFromTopic
547
	 *
548
	 * @param int $id_topic
549
	 *
550
	 * @return array
551
	 * @package Attachments
552
	 */
553
	function getThumbFromTopic($id_topic)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
554
	{
555
		// Make sure this attachment is on this board.
556
		$request = $this->db->fetchQuery('
557
			SELECT 
558
				th.id_folder, th.filename, th.file_hash, th.fileext, th.id_attach, 
559
				th.attachment_type, th.mime_type,
560
				a.id_folder AS attach_id_folder, a.filename AS attach_filename,
561
				a.file_hash AS attach_file_hash, a.fileext AS attach_fileext,
562
				a.id_attach AS attach_id_attach, a.attachment_type AS attach_attachment_type,
563
				a.mime_type AS attach_mime_type,
564
				a.approved, m.id_member
565
			FROM {db_prefix}attachments AS a
566
				INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg AND m.id_topic = {int:current_topic})
567
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND {query_see_board})
568
				LEFT JOIN {db_prefix}attachments AS th ON (th.id_attach = a.id_thumb)
569
			WHERE a.id_attach = {int:attach}',
570
			array(
571
				'attach' => $this->id_attach,
572
				'current_topic' => $id_topic,
573
			)
574
		);
575
		$attachmentData = [
576
			'id_folder' => '', 'filename' => '', 'file_hash' => '', 'fileext' => '', 'id_attach' => '',
577
			'attachment_type' => '', 'mime_type' => '', 'approved' => '', 'id_member' => ''];
578
		if ($request->num_rows() != 0)
579
		{
580
			$row = $request->fetch_assoc();
581
582
			// If there is a hash then the thumbnail exists
583
			if (!empty($row['file_hash']))
584
			{
585
				$attachmentData = array(
586
					'id_folder' => $row['id_folder'],
587
					'filename' => $row['filename'],
588
					'file_hash' => $row['file_hash'],
589
					'fileext' => $row['fileext'],
590
					'id_attach' => $row['id_attach'],
591
					'attachment_type' => $row['attachment_type'],
592
					'mime_type' => $row['mime_type'],
593
					'approved' => $row['approved'],
594
					'id_member' => $row['id_member'],
595
				);
596
			}
597
			// otherwise $modSettings['attachmentThumbnails'] may be (or was) off, so original file
598
			elseif (getValidMimeImageType($row['attach_mime_type']) !== '')
599
			{
600
				$attachmentData = array(
601
					'id_folder' => $row['attach_id_folder'],
602
					'filename' => $row['attach_filename'],
603
					'file_hash' => $row['attach_file_hash'],
604
					'fileext' => $row['attach_fileext'],
605
					'id_attach' => $row['attach_id_attach'],
606
					'attachment_type' => $row['attach_attachment_type'],
607
					'mime_type' => $row['attach_mime_type'],
608
					'approved' => $row['approved'],
609
					'id_member' => $row['id_member'],
610
				);
611
			}
612
		}
613
614
		return $attachmentData;
615
	}
616
}