Completed
Pull Request — development (#2330)
by Joshua
10:25
created

ManageSmileys_Controller::clearSmileyCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2
Metric Value
dl 0
loc 5
ccs 0
cts 5
cp 0
rs 9.4286
cc 1
eloc 3
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * This file takes care of all administration of smileys.
5
 *
6
 * @name      ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
9
 *
10
 * This software is a derived product, based on:
11
 *
12
 * Simple Machines Forum (SMF)
13
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
14
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
15
 *
16
 * @version 1.1 dev
17
 *
18
 */
19
20
if (!defined('ELK'))
21
	die('No access...');
22
23
/**
24
 * This class is in charge with administration of smileys and message icons.
25
 * It handles actions from the Smileys pages in admin panel.
26
 */
27
class ManageSmileys_Controller extends Action_Controller
28
{
29
	/**
30
	 * Smileys configuration settings form
31
	 * @var Settings_Form
32
	 */
33
	protected $_smileySettings;
34
35
	/**
36
	 * Contextual information about smiley sets.
37
	 * @var mixed[]
38
	 */
39
	private $_smiley_context = array();
40
41
	/**
42
	 * This is the dispatcher of smileys administration.
43
	 *
44
	 * @uses ManageSmileys language
45
	 * @uses ManageSmileys template
46
	 * @see Action_Controller::action_index()
47
	 */
48
	public function action_index()
49
	{
50
		global $context, $txt, $modSettings;
51
52
		loadLanguage('ManageSmileys');
53
		loadTemplate('ManageSmileys');
54
55
		$subActions = array(
56
			'addsmiley' => array($this, 'action_addsmiley', 'enabled' => !empty($modSettings['smiley_enable']), 'permission' => 'manage_smileys'),
57
			'editicon' => array($this, 'action_editicon', 'enabled' => !empty($modSettings['messageIcons_enable']), 'permission' => 'manage_smileys'),
58
			'editicons' => array($this, 'action_editicon', 'enabled' => !empty($modSettings['messageIcons_enable']), 'permission' => 'manage_smileys'),
59
			'editsets' => array($this, 'action_edit', 'permission' => 'admin_forum'),
60
			'editsmileys' => array($this, 'action_editsmiley', 'enabled' => !empty($modSettings['smiley_enable']), 'permission' => 'manage_smileys'),
61
			'import' => array($this, 'action_edit', 'permission' => 'manage_smileys'),
62
			'modifyset' => array($this, 'action_edit', 'permission' => 'manage_smileys'),
63
			'modifysmiley' => array($this, 'action_editsmiley', 'enabled' => !empty($modSettings['smiley_enable']), 'permission' => 'manage_smileys'),
64
			'setorder' => array($this, 'action_setorder', 'enabled' => !empty($modSettings['smiley_enable']), 'permission' => 'manage_smileys'),
65
			'settings' => array($this, 'action_smileySettings_display', 'permission' => 'manage_smileys'),
66
			'install' => array($this, 'action_install', 'permission' => 'manage_smileys')
67
		);
68
69
		// Action controller
70
		$action = new Action('manage_smileys');
71
72
		// Set the smiley context.
73
		$this->_initSmileyContext();
74
75
		// Load up all the tabs...
76
		$context[$context['admin_menu_name']]['tab_data'] = array(
77
			'title' => $txt['smileys_manage'],
78
			'help' => 'smileys',
79
			'description' => $txt['smiley_settings_explain'],
80
			'tabs' => array(
81
				'editsets' => array(
82
					'description' => $txt['smiley_editsets_explain'],
83
				),
84
				'addsmiley' => array(
85
					'description' => $txt['smiley_addsmiley_explain'],
86
				),
87
				'editsmileys' => array(
88
					'description' => $txt['smiley_editsmileys_explain'],
89
				),
90
				'setorder' => array(
91
					'description' => $txt['smiley_setorder_explain'],
92
				),
93
				'editicons' => array(
94
					'description' => $txt['icons_edit_icons_explain'],
95
				),
96
				'settings' => array(
97
					'description' => $txt['smiley_settings_explain'],
98
				),
99
			),
100
		);
101
102
		// Default the sub-action to 'edit smiley settings'. call integrate_sa_manage_smileys
103
		$subAction = $action->initialize($subActions, 'editsets');
104
105
		// Set up the template
106
		$context['page_title'] = $txt['smileys_manage'];
107
		$context['sub_action'] = $subAction;
108
109
		// Some settings may not be enabled, disallow these from the tabs as appropriate.
110
		if (empty($modSettings['messageIcons_enable']))
111
			$context[$context['admin_menu_name']]['tab_data']['tabs']['editicons']['disabled'] = true;
112
113
		if (empty($modSettings['smiley_enable']))
114
		{
115
			$context[$context['admin_menu_name']]['tab_data']['tabs']['addsmiley']['disabled'] = true;
116
			$context[$context['admin_menu_name']]['tab_data']['tabs']['editsmileys']['disabled'] = true;
117
			$context[$context['admin_menu_name']]['tab_data']['tabs']['setorder']['disabled'] = true;
118
		}
119
120
		// Call the right function for this sub-action.
121
		$action->dispatch($subAction);
122
	}
123
124
	/**
125
	 * Displays and allows to modify smileys settings.
126
	 * @uses show_settings sub template
127
	 */
128
	public function action_smileySettings_display()
129
	{
130
		global $context, $scripturl;
131
132
		// initialize the form
133
		$this->_initSmileySettingsForm();
134
135
		$config_vars = $this->_smileySettings->settings();
136
137
		// For the basics of the settings.
138
		require_once(SUBSDIR . '/Smileys.subs.php');
139
		$context['sub_template'] = 'show_settings';
140
141
		// Finish up the form...
142
		$context['post_url'] = $scripturl . '?action=admin;area=smileys;save;sa=settings';
143
		$context['permissions_excluded'] = array(-1);
144
145
		// Saving the settings?
146
		if (isset($this->_req->query->save))
147
		{
148
			checkSession();
149
150
			$this->_req->post->smiley_sets_default = $this->_req->getPost('smiley_sets_default', 'trim|strval', 'default');
151
152
			// Make sure that the smileys are in the right order after enabling them.
153
			if (isset($this->_req->post->smiley_enable))
154
				sortSmileyTable();
0 ignored issues
show
Deprecated Code introduced by
The function sortSmileyTable() has been deprecated with message: since 1.0 - the ordering is done in the query, probably not needed

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
155
156
			call_integration_hook('integrate_save_smiley_settings');
157
158
			// Save away
159
			Settings_Form::save_db($config_vars, $this->_req->post);
160
161
			// Flush the cache so the new settings take effect
162
			$this->clearSmileyCache();
163
164
			redirectexit('action=admin;area=smileys;sa=settings');
165
		}
166
167
		// We need this for the in-line permissions
168
		createToken('admin-mp');
169
170
		Settings_Form::prepare_db($config_vars);
171
	}
172
173
	/**
174
	 * Retrieve and initialize the form with smileys administration settings.
175
	 */
176
	private function _initSmileySettingsForm()
177
	{
178
		// Instantiate the form
179
		$this->_smileySettings = new Settings_Form();
180
181
		// Initialize it with our settings
182
		$config_vars = $this->_settings();
183
184
		return $this->_smileySettings->settings($config_vars);
185
	}
186
187
	/**
188
	 * Retrieve and return smileys administration settings.
189
	 */
190
	private function _settings()
191
	{
192
		global $txt, $modSettings, $context;
193
194
		// The directories...
195
		$context['smileys_dir'] = empty($modSettings['smileys_dir']) ? BOARDDIR . '/smileys' : $modSettings['smileys_dir'];
196
		$context['smileys_dir_found'] = is_dir($context['smileys_dir']);
197
198
		// All the settings for the page...
199
		$config_vars = array(
200
			array('title', 'settings'),
201
				// Inline permissions.
202
				array('permissions', 'manage_smileys'),
203
			'',
204
				array('select', 'smiley_sets_default', $this->_smiley_context),
205
				array('check', 'smiley_sets_enable'),
206
				array('check', 'smiley_enable', 'subtext' => $txt['smileys_enable_note']),
207
				array('text', 'smileys_url', 40),
208
				array('text', 'smileys_dir', 'invalid' => !$context['smileys_dir_found'], 40),
209
			'',
210
				// Message icons.
211
				array('check', 'messageIcons_enable', 'subtext' => $txt['setting_messageIcons_enable_note']),
212
		);
213
214
		call_integration_hook('integrate_modify_smiley_settings', array(&$config_vars));
215
216
		return $config_vars;
217
	}
218
219
	/**
220
	 * Return the smiley settings for use in admin search
221
	 */
222
	public function settings_search()
223
	{
224
		return $this->_settings();
225
	}
226
227
	/**
228
	 * List, add, remove, modify smileys sets.
229
	 */
230
	public function action_edit()
231
	{
232
		global $modSettings, $context, $txt, $scripturl;
233
234
		require_once(SUBSDIR . '/Smileys.subs.php');
235
236
		// Set the right tab to be selected.
237
		$context[$context['admin_menu_name']]['current_subsection'] = 'editsets';
238
		$context['sub_template'] = $context['sub_action'];
239
240
		// They must've been submitted a form.
241
		$this->_subActionSubmit();
242
243
		// Load all available smileysets...
244
		$context['smiley_sets'] = explode(',', $modSettings['smiley_sets_known']);
245
		$set_names = explode("\n", $modSettings['smiley_sets_names']);
246
		foreach ($context['smiley_sets'] as $i => $set)
247
			$context['smiley_sets'][$i] = array(
248
				'id' => $i,
249
				'path' => htmlspecialchars($set, ENT_COMPAT, 'UTF-8'),
250
				'name' => htmlspecialchars($set_names[$i], ENT_COMPAT, 'UTF-8'),
251
				'selected' => $set == $modSettings['smiley_sets_default']
252
			);
253
254
		// Importing any smileys from an existing set?
255
		$this->_subActionImport();
256
257
		// If we're modifying or adding a smileyset, some context info needs to be set.
258
		$this->_subActionModifySet();
259
260
		// This is our save haven.
261
		createToken('admin-mss', 'request');
262
263
		$listOptions = array(
264
			'id' => 'smiley_set_list',
265
			'title' => $txt['smiley_sets'],
266
			'no_items_label' => $txt['smiley_sets_none'],
267
			'base_href' => $scripturl . '?action=admin;area=smileys;sa=editsets',
268
			'default_sort_col' => 'default',
269
			'get_items' => array(
270
				'function' => 'list_getSmileySets',
271
			),
272
			'get_count' => array(
273
				'function' => 'list_getNumSmileySets',
274
			),
275
			'columns' => array(
276
				'default' => array(
277
					'header' => array(
278
						'value' => $txt['smiley_sets_default'],
279
						'class' => 'centertext',
280
					),
281
					'data' => array(
282
						'function' => function ($rowData) {
283
							global $settings;
284
285
							return $rowData['selected'] ? '<img src="' . $settings['images_url'] . '/icons/field_valid.png" alt="*" class="icon" />' : '';
286
						},
287
						'class' => 'centertext',
288
					),
289
					'sort' => array(
290
						'default' => 'selected DESC',
291
					),
292
				),
293
				'name' => array(
294
					'header' => array(
295
						'value' => $txt['smiley_sets_name'],
296
					),
297
					'data' => array(
298
						'db_htmlsafe' => 'name',
299
					),
300
					'sort' => array(
301
						'default' => 'name',
302
						'reverse' => 'name DESC',
303
					),
304
				),
305
				'url' => array(
306
					'header' => array(
307
						'value' => $txt['smiley_sets_url'],
308
					),
309
					'data' => array(
310
						'sprintf' => array(
311
							'format' => $modSettings['smileys_url'] . '/<strong>%1$s</strong>/...',
312
							'params' => array(
313
								'path' => true,
314
							),
315
						),
316
					),
317
					'sort' => array(
318
						'default' => 'path',
319
						'reverse' => 'path DESC',
320
					),
321
				),
322
				'modify' => array(
323
					'header' => array(
324
						'value' => $txt['smiley_set_modify'],
325
					),
326
					'data' => array(
327
						'sprintf' => array(
328
							'format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=modifyset;set=%1$d">' . $txt['smiley_set_modify'] . '</a>',
329
							'params' => array(
330
								'id' => true,
331
							),
332
						),
333
					),
334
				),
335
				'check' => array(
336
					'header' => array(
337
						'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />',
338
						'class' => 'centertext',
339
					),
340
					'data' => array(
341
						'function' => function ($rowData) {
342
							return $rowData['id'] == 0 ? '' : sprintf('<input type="checkbox" name="smiley_set[%1$d]" class="input_check" />', $rowData['id']);
343
						},
344
						'class' => 'centertext',
345
					),
346
				),
347
			),
348
			'form' => array(
349
				'href' => $scripturl . '?action=admin;area=smileys;sa=editsets',
350
				'token' => 'admin-mss',
351
			),
352
			'additional_rows' => array(
353
				array(
354
					'position' => 'below_table_data',
355
					'class' => 'submitbutton',
356
					'value' => '
357
						<input type="submit" name="delete_set" value="' . $txt['smiley_sets_delete'] . '" onclick="return confirm(\'' . $txt['smiley_sets_confirm'] . '\');" class="right_submit" />
358
						<a class="linkbutton" href="' . $scripturl . '?action=admin;area=smileys;sa=modifyset">' . $txt['smiley_sets_add'] . '</a> ',
359
				),
360
			),
361
		);
362
363
		createList($listOptions);
364
	}
365
366
	/**
367
	 * Submitted a smiley form, determine what actions are required.
368
	 *
369
	 * - Handle deleting of a smiley set
370
	 * - Adding a new set
371
	 * - Modifying an existing set
372
	 */
373
	private function _subActionSubmit()
374
	{
375
		global $context, $modSettings;
376
377
		if (isset($this->_req->post->smiley_save) || isset($this->_req->post->delete_set))
378
		{
379
			// Security first
380
			checkSession();
381
			validateToken('admin-mss', 'request');
382
383
			// Delete selected smiley sets.
384
			if (!empty($this->_req->post->delete_set) && !empty($this->_req->post->smiley_set))
385
			{
386
				$set_paths = explode(',', $modSettings['smiley_sets_known']);
387
				$set_names = explode("\n", $modSettings['smiley_sets_names']);
388
				foreach ($this->_req->post->smiley_set as $id => $val)
389
				{
390
					if (isset($set_paths[$id], $set_names[$id]) && !empty($id))
391
						unset($set_paths[$id], $set_names[$id]);
392
				}
393
394
				// Update the modsettings with the new values
395
				updateSettings(array(
396
					'smiley_sets_known' => implode(',', $set_paths),
397
					'smiley_sets_names' => implode("\n", $set_names),
398
					'smiley_sets_default' => in_array($modSettings['smiley_sets_default'], $set_paths) ? $modSettings['smiley_sets_default'] : $set_paths[0],
399
				));
400
			}
401
			// Add a new smiley set.
402
			elseif (!empty($this->_req->post->add))
403
				$context['sub_action'] = 'modifyset';
404
			// Create or modify a smiley set.
405
			elseif (isset($this->_req->post->set))
406
			{
407
				$set = $this->_req->getPost('set', 'intval', 0);
408
409
				$set_paths = explode(',', $modSettings['smiley_sets_known']);
410
				$set_names = explode("\n", $modSettings['smiley_sets_names']);
411
412
				// Create a new smiley set.
413
				if ($set == -1 && isset($this->_req->post->smiley_sets_path))
414
				{
415
					if (in_array($this->_req->post->smiley_sets_path, $set_paths))
416
						Errors::instance()->fatal_lang_error('smiley_set_already_exists');
417
418
					updateSettings(array(
419
						'smiley_sets_known' => $modSettings['smiley_sets_known'] . ',' . $this->_req->post->smiley_sets_path,
420
						'smiley_sets_names' => $modSettings['smiley_sets_names'] . "\n" . $this->_req->post->smiley_sets_name,
421
						'smiley_sets_default' => empty($this->_req->post->smiley_sets_default) ? $modSettings['smiley_sets_default'] : $this->_req->post->smiley_sets_path,
422
					));
423
				}
424
				// Modify an existing smiley set.
425
				else
426
				{
427
					// Make sure the smiley set exists.
428
					if (!isset($set_paths[$set]) || !isset($set_names[$set]))
429
						Errors::instance()->fatal_lang_error('smiley_set_not_found');
430
431
					// Make sure the path is not yet used by another smileyset.
432
					if (in_array($this->_req->post->smiley_sets_path, $set_paths) && $this->_req->post->smiley_sets_path != $set_paths[$set])
433
						Errors::instance()->fatal_lang_error('smiley_set_path_already_used');
434
435
					$set_paths[$set] = $this->_req->post->smiley_sets_path;
436
					$set_names[$set] = $this->_req->post->smiley_sets_name;
437
					updateSettings(array(
438
						'smiley_sets_known' => implode(',', $set_paths),
439
						'smiley_sets_names' => implode("\n", $set_names),
440
						'smiley_sets_default' => empty($this->_req->post->smiley_sets_default) ? $modSettings['smiley_sets_default'] : $this->_req->post->smiley_sets_path
441
					));
442
				}
443
444
				// The user might have checked to also import smileys.
445
				if (!empty($this->_req->post->smiley_sets_import))
446
					$this->importSmileys($this->_req->post->smiley_sets_path);
447
			}
448
449
			// No matter what, reset the cache
450
			$this->clearSmileyCache();
451
		}
452
	}
453
454
	/**
455
	 * If we're modifying or adding a smileyset, or if we imported from another
456
	 * set, then some context info needs to be set.
457
	 */
458
	private function _subActionModifySet()
459
	{
460
		global $context, $txt, $modSettings;
461
462
		if ($context['sub_action'] == 'modifyset')
463
		{
464
			$set = $this->_req->getQuery('set', 'intval', -1);
465
			if ($set == -1 || !isset($context['smiley_sets'][$set]))
466
				$context['current_set'] = array(
467
					'id' => '-1',
468
					'path' => '',
469
					'name' => '',
470
					'selected' => false,
471
					'is_new' => true,
472
				);
473
			else
474
			{
475
				$context['current_set'] = &$context['smiley_sets'][$set];
476
				$context['current_set']['is_new'] = false;
477
478
				// Calculate whether there are any smileys in the directory that can be imported.
479
				if (!empty($modSettings['smiley_enable']) && !empty($modSettings['smileys_dir']) && is_dir($modSettings['smileys_dir'] . '/' . $context['current_set']['path']))
480
				{
481
					$smileys = array();
482
					$dir = dir($modSettings['smileys_dir'] . '/' . $context['current_set']['path']);
483
					while ($entry = $dir->read())
484
					{
485
						if (in_array(strrchr($entry, '.'), array('.jpg', '.gif', '.jpeg', '.png')))
486
							$smileys[strtolower($entry)] = $entry;
487
					}
488
					$dir->close();
489
490
					if (empty($smileys))
491
						Errors::instance()->fatal_lang_error('smiley_set_dir_not_found', false, array($context['current_set']['name']));
492
493
					// Exclude the smileys that are already in the database.
494
					$found = smileyExists($smileys);
495
					foreach ($found as $smiley)
496
					{
497
						if (isset($smileys[$smiley]))
498
							unset($smileys[$smiley]);
499
					}
500
501
					$context['current_set']['can_import'] = count($smileys);
502
503
					// Setup this string to look nice.
504
					$txt['smiley_set_import_multiple'] = sprintf($txt['smiley_set_import_multiple'], $context['current_set']['can_import']);
505
				}
506
			}
507
508
			// Retrieve all potential smiley set directories.
509
			$context['smiley_set_dirs'] = array();
510
			if (!empty($modSettings['smileys_dir']) && is_dir($modSettings['smileys_dir']))
511
			{
512
				$dir = dir($modSettings['smileys_dir']);
513
				while ($entry = $dir->read())
514
				{
515
					if (!in_array($entry, array('.', '..')) && is_dir($modSettings['smileys_dir'] . '/' . $entry))
516
						$context['smiley_set_dirs'][] = array(
517
							'id' => $entry,
518
							'path' => $modSettings['smileys_dir'] . '/' . $entry,
519
							'selectable' => $entry == $context['current_set']['path'] || !in_array($entry, explode(',', $modSettings['smiley_sets_known'])),
520
							'current' => $entry == $context['current_set']['path'],
521
						);
522
				}
523
				$dir->close();
524
			}
525
		}
526
	}
527
528
	/**
529
	 * Importing smileys from an existing smiley set
530
	 */
531
	private function _subActionImport()
532
	{
533
		global $context;
534
535
		// Importing any smileys from an existing set?
536
		if ($context['sub_action'] === 'import')
537
		{
538
			checkSession('get');
539
			validateToken('admin-mss', 'request');
540
541
			$set = (int) $this->_req->query->set;
542
543
			// Sanity check - then import.
544
			if (isset($context['smiley_sets'][$set]))
545
				$this->importSmileys(un_htmlspecialchars($context['smiley_sets'][$set]['path']));
546
547
			// Force the process to continue.
548
			$context['sub_action'] = 'modifyset';
549
			$context['sub_template'] = 'modifyset';
550
		}
551
	}
552
553
	/**
554
	 * Add a smiley, that's right.
555
	 */
556
	public function action_addsmiley()
0 ignored issues
show
Coding Style introduced by
action_addsmiley uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
557
	{
558
		global $modSettings, $context, $txt;
559
560
		require_once(SUBSDIR . '/Smileys.subs.php');
561
562
		// Get a list of all known smiley sets.
563
		$context['smileys_dir'] = empty($modSettings['smileys_dir']) ? BOARDDIR . '/smileys' : $modSettings['smileys_dir'];
564
		$context['smileys_dir_found'] = is_dir($context['smileys_dir']);
565
		$context['smiley_sets'] = explode(',', $modSettings['smiley_sets_known']);
566
		$context['sub_template'] = 'addsmiley';
567
568
		$set_names = explode("\n", $modSettings['smiley_sets_names']);
569
		foreach ($context['smiley_sets'] as $i => $set)
570
			$context['smiley_sets'][$i] = array(
571
				'id' => $i,
572
				'path' => htmlspecialchars($set, ENT_COMPAT, 'UTF-8'),
573
				'name' => htmlspecialchars($set_names[$i], ENT_COMPAT, 'UTF-8'),
574
				'selected' => $set == $modSettings['smiley_sets_default']
575
			);
576
577
		// Submitting a form?
578
		if (isset($this->_req->post->$context['session_var'], $this->_req->post->smiley_code))
579
		{
580
			checkSession();
581
582
			// Some useful arrays... types we allow - and ports we don't!
583
			$allowedTypes = array('jpeg', 'jpg', 'gif', 'png', 'bmp');
584
			$disabledFiles = array('con', 'com1', 'com2', 'com3', 'com4', 'prn', 'aux', 'lpt1', '.htaccess', 'index.php');
585
586
			$this->_req->post->smiley_code = $this->_req->getPost('smiley_code', 'Util::htmltrim', '');
587
			$this->_req->post->smiley_filename = $this->_req->getPost('smiley_filename', 'Util::htmltrim', '');
588
			$this->_req->post->smiley_location = empty($this->_req->post->smiley_location) || $this->_req->post->smiley_location > 2 || $this->_req->post->smiley_location < 0 ? 0 : (int) $this->_req->post->smiley_location;
589
590
			// Make sure some code was entered.
591
			if (empty($this->_req->post->smiley_code))
592
				Errors::instance()->fatal_lang_error('smiley_has_no_code');
593
594
			// Check whether the new code has duplicates. It should be unique.
595
			if (validateDuplicateSmiley($this->_req->post->smiley_code))
596
				Errors::instance()->fatal_lang_error('smiley_not_unique');
597
598
			// If we are uploading - check all the smiley sets are writable!
599
			if ($this->_req->post->method != 'existing')
600
			{
601
				$writeErrors = array();
602
				foreach ($context['smiley_sets'] as $set)
603
				{
604
					if (!is_writable($context['smileys_dir'] . '/' . un_htmlspecialchars($set['path'])))
605
						$writeErrors[] = $set['path'];
606
				}
607
608
				if (!empty($writeErrors))
609
					Errors::instance()->fatal_lang_error('smileys_upload_error_notwritable', true, array(implode(', ', $writeErrors)));
610
			}
611
612
			// Uploading just one smiley for all of them?
613
			if (isset($this->_req->post->sameall) && isset($_FILES['uploadSmiley']['name']) && $_FILES['uploadSmiley']['name'] != '')
614
			{
615
				if (!is_uploaded_file($_FILES['uploadSmiley']['tmp_name']) || (ini_get('open_basedir') == '' && !file_exists($_FILES['uploadSmiley']['tmp_name'])))
616
					Errors::instance()->fatal_lang_error('smileys_upload_error');
617
618
				// Sorry, no spaces, dots, or anything else but letters allowed.
619
				$_FILES['uploadSmiley']['name'] = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $_FILES['uploadSmiley']['name']);
620
621
				// We only allow image files - it's THAT simple - no messing around here...
622
				if (!in_array(strtolower(substr(strrchr($_FILES['uploadSmiley']['name'], '.'), 1)), $allowedTypes))
623
					Errors::instance()->fatal_lang_error('smileys_upload_error_types', false, array(implode(', ', $allowedTypes)));
624
625
				// We only need the filename...
626
				$destName = basename($_FILES['uploadSmiley']['name']);
627
628
				// Make sure they aren't trying to upload a nasty file - for their own good here!
629
				if (in_array(strtolower($destName), $disabledFiles))
630
					Errors::instance()->fatal_lang_error('smileys_upload_error_illegal');
631
632
				// Check if the file already exists... and if not move it to EVERY smiley set directory.
633
				$i = 0;
634
635
				// Keep going until we find a set the file doesn't exist in. (or maybe it exists in all of them?)
636
				while (isset($context['smiley_sets'][$i]) && file_exists($context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName))
637
					$i++;
638
639
				// Okay, we're going to put the smiley right here, since it's not there yet!
640
				if (isset($context['smiley_sets'][$i]['path']))
641
				{
642
					$smileyLocation = $context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName;
643
					move_uploaded_file($_FILES['uploadSmiley']['tmp_name'], $smileyLocation);
644
					@chmod($smileyLocation, 0644);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
645
646
					// Now, we want to move it from there to all the other sets.
647
					for ($n = count($context['smiley_sets']); $i < $n; $i++)
648
					{
649
						$currentPath = $context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName;
650
651
						// The file is already there!  Don't overwrite it!
652
						if (file_exists($currentPath))
653
							continue;
654
655
						// Okay, so copy the first one we made to here.
656
						copy($smileyLocation, $currentPath);
657
						@chmod($currentPath, 0644);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
658
					}
659
				}
660
661
				// Finally make sure it's saved correctly!
662
				$this->_req->post->smiley_filename = $destName;
663
			}
664
			// What about uploading several files?
665
			elseif ($this->_req->post->method != 'existing')
666
			{
667
				$newName = '';
668
				foreach ($_FILES as $name => $dummy)
669
				{
670
					if ($_FILES[$name]['name'] == '')
671
						Errors::instance()->fatal_lang_error('smileys_upload_error_blank');
672
673
					if (empty($newName))
674
						$newName = basename($_FILES[$name]['name']);
675
					elseif (basename($_FILES[$name]['name']) != $newName)
676
						Errors::instance()->fatal_lang_error('smileys_upload_error_name');
677
				}
678
679
				foreach ($context['smiley_sets'] as $i => $set)
680
				{
681
					$set['name'] = un_htmlspecialchars($set['name']);
682
					$set['path'] = un_htmlspecialchars($set['path']);
683
684
					if (!isset($_FILES['individual_' . $set['name']]['name']) || $_FILES['individual_' . $set['name']]['name'] == '')
685
						continue;
686
687
					// Got one...
688
					if (!is_uploaded_file($_FILES['individual_' . $set['name']]['tmp_name']) || (ini_get('open_basedir') == '' && !file_exists($_FILES['individual_' . $set['name']]['tmp_name'])))
689
						Errors::instance()->fatal_lang_error('smileys_upload_error');
690
691
					// Sorry, no spaces, dots, or anything else but letters allowed.
692
					$_FILES['individual_' . $set['name']]['name'] = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $_FILES['individual_' . $set['name']]['name']);
693
694
					// We only allow image files - it's THAT simple - no messing around here...
695
					if (!in_array(strtolower(substr(strrchr($_FILES['individual_' . $set['name']]['name'], '.'), 1)), $allowedTypes))
696
						Errors::instance()->fatal_lang_error('smileys_upload_error_types', false, array(implode(', ', $allowedTypes)));
697
698
					// We only need the filename...
699
					$destName = basename($_FILES['individual_' . $set['name']]['name']);
700
701
					// Make sure they aren't trying to upload a nasty file - for their own good here!
702
					if (in_array(strtolower($destName), $disabledFiles))
703
						Errors::instance()->fatal_lang_error('smileys_upload_error_illegal');
704
705
					// If the file exists - ignore it.
706
					$smileyLocation = $context['smileys_dir'] . '/' . $set['path'] . '/' . $destName;
707
					if (file_exists($smileyLocation))
708
						continue;
709
710
					// Finally - move the image!
711
					move_uploaded_file($_FILES['individual_' . $set['name']]['tmp_name'], $smileyLocation);
712
					@chmod($smileyLocation, 0644);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
713
714
					// Should always be saved correctly!
715
					$this->_req->post->smiley_filename = $destName;
716
				}
717
			}
718
719
			// Also make sure a filename was given.
720
			if (empty($this->_req->post->smiley_filename))
721
				Errors::instance()->fatal_lang_error('smiley_has_no_filename');
722
723
			// Find the position on the right.
724
			$smiley_order = '0';
725
			if ($this->_req->post->smiley_location != 1)
726
			{
727
				$this->_req->post->smiley_location = (int) $this->_req->post->smiley_location;
728
				$smiley_order = nextSmileyLocation($this->_req->post->smiley_location);
729
730
				if (empty($smiley_order))
731
					$smiley_order = '0';
732
			}
733
			$param = array(
734
				$this->_req->post->smiley_code,
735
				$this->_req->post->smiley_filename,
736
				$this->_req->post->smiley_description,
737
				(int) $this->_req->post->smiley_location,
738
				$smiley_order,
739
			);
740
			addSmiley($param);
741
742
			$this->clearSmileyCache();
743
744
			// No errors? Out of here!
745
			redirectexit('action=admin;area=smileys;sa=editsmileys');
746
		}
747
748
		$context['selected_set'] = $modSettings['smiley_sets_default'];
749
750
		// Get all possible filenames for the smileys.
751
		$context['filenames'] = array();
752
		if ($context['smileys_dir_found'])
753
		{
754
			foreach ($context['smiley_sets'] as $smiley_set)
755
			{
756
				if (!file_exists($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path'])))
757
					continue;
758
759
				$dir = dir($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path']));
760
				while ($entry = $dir->read())
761
				{
762
					if (!in_array($entry, $context['filenames']) && in_array(strrchr($entry, '.'), array('.jpg', '.gif', '.jpeg', '.png')))
763
						$context['filenames'][strtolower($entry)] = array(
764
							'id' => htmlspecialchars($entry, ENT_COMPAT, 'UTF-8'),
765
							'selected' => false,
766
						);
767
				}
768
				$dir->close();
769
			}
770
			ksort($context['filenames']);
771
		}
772
773
		// Create a new smiley from scratch.
774
		$context['filenames'] = array_values($context['filenames']);
775
		$context['current_smiley'] = array(
776
			'id' => 0,
777
			'code' => '',
778
			'filename' => $context['filenames'][0]['id'],
779
			'description' => $txt['smileys_default_description'],
780
			'location' => 0,
781
			'is_new' => true,
782
		);
783
	}
784
785
	/**
786
	 * Add, remove, edit smileys.
787
	 */
788
	public function action_editsmiley()
789
	{
790
		global $modSettings, $context, $txt, $scripturl;
791
792
		require_once(SUBSDIR . '/Smileys.subs.php');
793
794
		// Force the correct tab to be displayed.
795
		$context[$context['admin_menu_name']]['current_subsection'] = 'editsmileys';
796
		$context['sub_template'] = $context['sub_action'];
797
798
		// Submitting a form?
799
		if (isset($this->_req->post->smiley_save) || isset($this->_req->post->smiley_action))
800
		{
801
			checkSession();
802
803
			// Changing the selected smileys?
804
			if (isset($this->_req->post->smiley_action) && !empty($this->_req->post->checked_smileys))
805
			{
806
				foreach ($this->_req->post->checked_smileys as $id => $smiley_id)
807
					$this->_req->post->checked_smileys[$id] = (int) $smiley_id;
808
809
				if ($this->_req->post->smiley_action == 'delete')
810
					deleteSmileys($this->_req->post->checked_smileys);
811
				// Changing the status of the smiley?
812
				else
813
				{
814
					// Check it's a valid type.
815
					$displayTypes = array(
816
						'post' => 0,
817
						'hidden' => 1,
818
						'popup' => 2
819
					);
820
					if (isset($displayTypes[$this->_req->post->smiley_action]))
821
						updateSmileyDisplayType($this->_req->post->checked_smileys, $displayTypes[$this->_req->post->smiley_action]);
822
				}
823
			}
824
			// Create/modify a smiley.
825
			elseif (isset($this->_req->post->smiley))
826
			{
827
				$this->_req->post->smiley = (int) $this->_req->post->smiley;
828
829
				// Is it a delete?
830
				if (!empty($this->_req->post->deletesmiley))
831
					deleteSmileys(array($this->_req->post->smiley));
832
				// Otherwise an edit.
833
				else
834
				{
835
					$this->_req->post->smiley_code = $this->_req->getPost('smiley_code', 'Util::htmltrim', '');
836
					$this->_req->post->smiley_filename = $this->_req->getPost('smiley_filename', 'Util::htmltrim', '');
837
					$this->_req->post->smiley_location = empty($this->_req->post->smiley_location) || $this->_req->post->smiley_location > 2 || $this->_req->post->smiley_location < 0 ? 0 : (int) $this->_req->post->smiley_location;
838
839
					// Make sure some code was entered.
840
					if (empty($this->_req->post->smiley_code))
841
						Errors::instance()->fatal_lang_error('smiley_has_no_code');
842
843
					// Also make sure a filename was given.
844
					if (empty($this->_req->post->smiley_filename))
845
						Errors::instance()->fatal_lang_error('smiley_has_no_filename');
846
847
					// Check whether the new code has duplicates. It should be unique.
848
					if (validateDuplicateSmiley($this->_req->post->smiley_code, $this->_req->post->smiley))
849
						Errors::instance()->fatal_lang_error('smiley_not_unique');
850
851
					$param = array(
852
						'smiley_location' => $this->_req->post->smiley_location,
853
						'smiley' => $this->_req->post->smiley,
854
						'smiley_code' => $this->_req->post->smiley_code,
855
						'smiley_filename' => $this->_req->post->smiley_filename,
856
						'smiley_description' => $this->_req->post->smiley_description,
857
					);
858
					updateSmiley($param);
859
				}
860
861
				// Sort all smiley codes for more accurate parsing (longest code first).
862
				sortSmileyTable();
0 ignored issues
show
Deprecated Code introduced by
The function sortSmileyTable() has been deprecated with message: since 1.0 - the ordering is done in the query, probably not needed

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
863
			}
864
865
			$this->clearSmileyCache();
866
		}
867
868
		// Load all known smiley sets.
869
		$context['smiley_sets'] = explode(',', $modSettings['smiley_sets_known']);
870
		$set_names = explode("\n", $modSettings['smiley_sets_names']);
871
		foreach ($context['smiley_sets'] as $i => $set)
872
			$context['smiley_sets'][$i] = array(
873
				'id' => $i,
874
				'path' => htmlspecialchars($set, ENT_COMPAT, 'UTF-8'),
875
				'name' => htmlspecialchars($set_names[$i], ENT_COMPAT, 'UTF-8'),
876
				'selected' => $set == $modSettings['smiley_sets_default']
877
			);
878
879
		// Prepare overview of all (custom) smileys.
880
		if ($context['sub_action'] == 'editsmileys')
881
		{
882
			// Determine the language specific sort order of smiley locations.
883
			$smiley_locations = array(
884
				$txt['smileys_location_form'],
885
				$txt['smileys_location_hidden'],
886
				$txt['smileys_location_popup'],
887
			);
888
			asort($smiley_locations);
889
890
			// Create a list of options for selecting smiley sets.
891
			$smileyset_option_list = '
892
				<select name="set" onchange="changeSet(this.options[this.selectedIndex].value);">';
893
			foreach ($context['smiley_sets'] as $smiley_set)
894
				$smileyset_option_list .= '
895
					<option value="' . $smiley_set['path'] . '"' . ($modSettings['smiley_sets_default'] == $smiley_set['path'] ? ' selected="selected"' : '') . '>' . $smiley_set['name'] . '</option>';
896
			$smileyset_option_list .= '
897
				</select>';
898
899
			$listOptions = array(
900
				'id' => 'smiley_list',
901
				'title' => $txt['smileys_edit'],
902
				'items_per_page' => 40,
903
				'base_href' => $scripturl . '?action=admin;area=smileys;sa=editsmileys',
904
				'default_sort_col' => 'filename',
905
				'get_items' => array(
906
					'function' => 'list_getSmileys',
907
				),
908
				'get_count' => array(
909
					'function' => 'list_getNumSmileys',
910
				),
911
				'no_items_label' => $txt['smileys_no_entries'],
912
				'columns' => array(
913
					'picture' => array(
914
						'data' => array(
915
							'sprintf' => array(
916
								'format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=modifysmiley;smiley=%1$d"><img src="' . $modSettings['smileys_url'] . '/' . $modSettings['smiley_sets_default'] . '/%2$s" alt="%3$s" id="smiley%1$d" /><input type="hidden" name="smileys[%1$d][filename]" value="%2$s" /></a>',
917
								'params' => array(
918
									'id_smiley' => false,
919
									'filename' => true,
920
									'description' => true,
921
								),
922
							),
923
							'class' => 'imagecolumn',
924
						),
925
					),
926
					'code' => array(
927
						'header' => array(
928
							'value' => $txt['smileys_code'],
929
						),
930
						'data' => array(
931
							'db_htmlsafe' => 'code',
932
						),
933
						'sort' => array(
934
							'default' => 'code',
935
							'reverse' => 'code DESC',
936
						),
937
					),
938
					'filename' => array(
939
						'header' => array(
940
							'value' => $txt['smileys_filename'],
941
						),
942
						'data' => array(
943
							'db_htmlsafe' => 'filename',
944
						),
945
						'sort' => array(
946
							'default' => 'filename',
947
							'reverse' => 'filename DESC',
948
						),
949
					),
950
					'location' => array(
951
						'header' => array(
952
							'value' => $txt['smileys_location'],
953
						),
954
						'data' => array(
955
							'function' => function ($rowData) {
956
								global $txt;
957
958
								if (empty($rowData['hidden']))
959
									return $txt['smileys_location_form'];
960
								elseif ($rowData['hidden'] == 1)
961
									return $txt['smileys_location_hidden'];
962
								else
963
									return $txt['smileys_location_popup'];
964
							},
965
						),
966
						'sort' => array(
967
							'default' => 'FIND_IN_SET(hidden, \'' . implode(',', array_keys($smiley_locations)) . '\')',
968
							'reverse' => 'FIND_IN_SET(hidden, \'' . implode(',', array_keys($smiley_locations)) . '\') DESC',
969
						),
970
					),
971
					'tooltip' => array(
972
						'header' => array(
973
							'value' => $txt['smileys_description'],
974
						),
975
						'data' => array(
976
							'function' => function ($rowData) {
977
								global $context, $txt, $modSettings;
978
979
								if (empty($modSettings['smileys_dir']) || !is_dir($modSettings['smileys_dir']))
980
									return htmlspecialchars($rowData['description'], ENT_COMPAT, 'UTF-8');
981
982
								// Check if there are smileys missing in some sets.
983
								$missing_sets = array();
984
								foreach ($context['smiley_sets'] as $smiley_set)
985
									if (!file_exists(sprintf('%1$s/%2$s/%3$s', $modSettings['smileys_dir'], $smiley_set['path'], $rowData['filename'])))
986
										$missing_sets[] = $smiley_set['path'];
987
988
								$description = htmlspecialchars($rowData['description'], ENT_COMPAT, 'UTF-8');
989
990
								if (!empty($missing_sets))
991
									$description .= sprintf('<br /><span class="smalltext"><strong>%1$s:</strong> %2$s</span>', $txt['smileys_not_found_in_set'], implode(', ', $missing_sets));
992
993
								return $description;
994
							},
995
						),
996
						'sort' => array(
997
							'default' => 'description',
998
							'reverse' => 'description DESC',
999
						),
1000
					),
1001
					'modify' => array(
1002
						'header' => array(
1003
							'value' => $txt['smileys_modify'],
1004
							'class' => 'centertext',
1005
						),
1006
						'data' => array(
1007
							'sprintf' => array(
1008
								'format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=modifysmiley;smiley=%1$d">' . $txt['smileys_modify'] . '</a>',
1009
								'params' => array(
1010
									'id_smiley' => false,
1011
								),
1012
							),
1013
							'class' => 'centertext',
1014
						),
1015
					),
1016
					'check' => array(
1017
						'header' => array(
1018
							'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />',
1019
							'class' => 'centertext',
1020
						),
1021
						'data' => array(
1022
							'sprintf' => array(
1023
								'format' => '<input type="checkbox" name="checked_smileys[]" value="%1$d" class="input_check" />',
1024
								'params' => array(
1025
									'id_smiley' => false,
1026
								),
1027
							),
1028
							'class' => 'centertext',
1029
						),
1030
					),
1031
				),
1032
				'form' => array(
1033
					'href' => $scripturl . '?action=admin;area=smileys;sa=editsmileys',
1034
					'name' => 'smileyForm',
1035
				),
1036
				'additional_rows' => array(
1037
					array(
1038
						'position' => 'above_column_headers',
1039
						'value' => $smileyset_option_list,
1040
						'class' => 'righttext',
1041
					),
1042
					array(
1043
						'position' => 'below_table_data',
1044
						'value' => '
1045
							<select name="smiley_action" onchange="makeChanges(this.value);">
1046
								<option value="-1">' . $txt['smileys_with_selected'] . ':</option>
1047
								<option value="-1">--------------</option>
1048
								<option value="hidden">' . $txt['smileys_make_hidden'] . '</option>
1049
								<option value="post">' . $txt['smileys_show_on_post'] . '</option>
1050
								<option value="popup">' . $txt['smileys_show_on_popup'] . '</option>
1051
								<option value="delete">' . $txt['smileys_remove'] . '</option>
1052
							</select>
1053
							<noscript>
1054
								<input type="submit" name="perform_action" value="' . $txt['go'] . '" class="right_submit" />
1055
							</noscript>',
1056
						'class' => 'righttext',
1057
					),
1058
				),
1059
				'javascript' => '
1060
					function makeChanges(action)
1061
					{
1062
						if (action == \'-1\')
1063
							return false;
1064
						else if (action == \'delete\')
1065
						{
1066
							if (confirm(\'' . $txt['smileys_confirm'] . '\'))
1067
								document.forms.smileyForm.submit();
1068
						}
1069
						else
1070
							document.forms.smileyForm.submit();
1071
						return true;
1072
					}
1073
					function changeSet(newSet)
1074
					{
1075
						var currentImage, i, knownSmileys = [];
1076
1077
						if (knownSmileys.length == 0)
1078
						{
1079
							for (var i = 0, n = document.images.length; i < n; i++)
1080
								if (document.images[i].id.substr(0, 6) == \'smiley\')
1081
									knownSmileys[knownSmileys.length] = document.images[i].id.substr(6);
1082
						}
1083
1084
						for (i = 0; i < knownSmileys.length; i++)
1085
						{
1086
							currentImage = document.getElementById("smiley" + knownSmileys[i]);
1087
							currentImage.src = "' . $modSettings['smileys_url'] . '/" + newSet + "/" + document.forms.smileyForm["smileys[" + knownSmileys[i] + "][filename]"].value;
1088
						}
1089
					}',
1090
			);
1091
1092
			createList($listOptions);
1093
1094
			// The list is the only thing to show, so make it the main template.
1095
			$context['default_list'] = 'smiley_list';
1096
			$context['sub_template'] = 'show_list';
1097
		}
1098
		// Modifying smileys.
1099
		elseif ($context['sub_action'] == 'modifysmiley')
1100
		{
1101
			// Get a list of all known smiley sets.
1102
			$context['smileys_dir'] = empty($modSettings['smileys_dir']) ? BOARDDIR . '/smileys' : $modSettings['smileys_dir'];
1103
			$context['smileys_dir_found'] = is_dir($context['smileys_dir']);
1104
			$context['smiley_sets'] = explode(',', $modSettings['smiley_sets_known']);
1105
			$set_names = explode("\n", $modSettings['smiley_sets_names']);
1106
			foreach ($context['smiley_sets'] as $i => $set)
1107
				$context['smiley_sets'][$i] = array(
1108
					'id' => $i,
1109
					'path' => htmlspecialchars($set, ENT_COMPAT, 'UTF-8'),
1110
					'name' => htmlspecialchars($set_names[$i], ENT_COMPAT, 'UTF-8'),
1111
					'selected' => $set == $modSettings['smiley_sets_default']
1112
				);
1113
1114
			$context['selected_set'] = $modSettings['smiley_sets_default'];
1115
1116
			// Get all possible filenames for the smileys.
1117
			$context['filenames'] = array();
1118
			if ($context['smileys_dir_found'])
1119
			{
1120
				foreach ($context['smiley_sets'] as $smiley_set)
1121
				{
1122
					if (!file_exists($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path'])))
1123
						continue;
1124
1125
					$dir = dir($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path']));
1126
					while ($entry = $dir->read())
1127
					{
1128
						if (!in_array($entry, $context['filenames']) && in_array(strrchr($entry, '.'), array('.jpg', '.gif', '.jpeg', '.png')))
1129
							$context['filenames'][strtolower($entry)] = array(
1130
								'id' => htmlspecialchars($entry, ENT_COMPAT, 'UTF-8'),
1131
								'selected' => false,
1132
							);
1133
					}
1134
					$dir->close();
1135
				}
1136
				ksort($context['filenames']);
1137
			}
1138
1139
			$this->_req->query->smiley = (int) $this->_req->query->smiley;
1140
			$context['current_smiley'] = getSmiley($this->_req->query->smiley);
1141
			$context['current_smiley']['code'] = htmlspecialchars($context['current_smiley']['code'], ENT_COMPAT, 'UTF-8');
1142
			$context['current_smiley']['filename'] = htmlspecialchars($context['current_smiley']['filename'], ENT_COMPAT, 'UTF-8');
1143
			$context['current_smiley']['description'] = htmlspecialchars($context['current_smiley']['description'], ENT_COMPAT, 'UTF-8');
1144
1145
			if (isset($context['filenames'][strtolower($context['current_smiley']['filename'])]))
1146
				$context['filenames'][strtolower($context['current_smiley']['filename'])]['selected'] = true;
1147
		}
1148
	}
1149
1150
	/**
1151
	 * Allows to edit the message icons.
1152
	 */
1153
	public function action_editicon()
1154
	{
1155
		global $context, $settings, $txt, $scripturl;
1156
1157
		require_once(SUBSDIR . '/MessageIcons.subs.php');
1158
1159
		// Get a list of icons.
1160
		$context['icons'] = fetchMessageIconsDetails();
1161
1162
		// Submitting a form?
1163
		if (isset($this->_req->post->icons_save))
1164
		{
1165
			checkSession();
1166
1167
			// Deleting icons?
1168
			if (isset($this->_req->post->delete) && !empty($this->_req->post->checked_icons))
1169
			{
1170
				$deleteIcons = array();
1171
				foreach ($this->_req->post->checked_icons as $icon)
1172
					$deleteIcons[] = (int) $icon;
1173
1174
				// Do the actual delete!
1175
				deleteMessageIcons($deleteIcons);
1176
			}
1177
			// Editing/Adding an icon?
1178
			elseif ($context['sub_action'] == 'editicon' && isset($this->_req->query->icon))
1179
			{
1180
				$this->_req->query->icon = (int) $this->_req->query->icon;
1181
1182
				// Do some preparation with the data... like check the icon exists *somewhere*
1183
				if (strpos($this->_req->post->icon_filename, '.png') !== false)
1184
					$this->_req->post->icon_filename = substr($this->_req->post->icon_filename, 0, -4);
1185
1186
				if (!file_exists($settings['default_theme_dir'] . '/images/post/' . $this->_req->post->icon_filename . '.png'))
1187
					Errors::instance()->fatal_lang_error('icon_not_found');
1188
				// There is a 16 character limit on message icons...
1189
				elseif (strlen($this->_req->post->icon_filename) > 16)
1190
					Errors::instance()->fatal_lang_error('icon_name_too_long');
1191
				elseif ($this->_req->post->icon_location == $this->_req->query->icon && !empty($this->_req->query->icon))
1192
					Errors::instance()->fatal_lang_error('icon_after_itself');
1193
1194
				// First do the sorting... if this is an edit reduce the order of everything after it by one ;)
1195
				if ($this->_req->query->icon != 0)
1196
				{
1197
					$oldOrder = $context['icons'][$this->_req->query->icon]['true_order'];
1198
					foreach ($context['icons'] as $id => $data)
1199
						if ($data['true_order'] > $oldOrder)
1200
							$context['icons'][$id]['true_order']--;
1201
				}
1202
1203
				// If there are no existing icons and this is a new one, set the id to 1 (mainly for non-mysql)
1204
				if (empty($this->_req->query->icon) && empty($context['icons']))
1205
					$this->_req->query->icon = 1;
1206
1207
				// Get the new order.
1208
				$newOrder = $this->_req->post->icon_location == 0 ? 0 : $context['icons'][$this->_req->post->icon_location]['true_order'] + 1;
1209
1210
				// Do the same, but with the one that used to be after this icon, done to avoid conflict.
1211
				foreach ($context['icons'] as $id => $data)
1212
					if ($data['true_order'] >= $newOrder)
1213
						$context['icons'][$id]['true_order']++;
1214
1215
				// Finally set the current icon's position!
1216
				$context['icons'][$this->_req->query->icon]['true_order'] = $newOrder;
1217
1218
				// Simply replace the existing data for the other bits.
1219
				$context['icons'][$this->_req->query->icon]['title'] = $this->_req->post->icon_description;
1220
				$context['icons'][$this->_req->query->icon]['filename'] = $this->_req->post->icon_filename;
1221
				$context['icons'][$this->_req->query->icon]['board_id'] = (int) $this->_req->post->icon_board;
1222
1223
				// Do a huge replace ;)
1224
				$iconInsert = array();
1225
				$iconInsert_new = array();
1226
				foreach ($context['icons'] as $id => $icon)
1227
				{
1228
					if ($id != 0)
1229
						$iconInsert[] = array($id, $icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']);
1230
					else
1231
						$iconInsert_new[] = array($icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']);
1232
				}
1233
1234
				updateMessageIcon($iconInsert);
1235
1236
				if (!empty($iconInsert_new))
1237
					addMessageIcon($iconInsert_new);
1238
			}
1239
1240
			// Sort by order, so it is quicker :)
1241
			sortMessageIconTable();
0 ignored issues
show
Deprecated Code introduced by
The function sortMessageIconTable() has been deprecated with message: since 1.0 - the ordering is done in the query, probably not needed

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
1242
1243
			// Unless we're adding a new thing, we'll escape
1244
			if (!isset($this->_req->post->add))
1245
				redirectexit('action=admin;area=smileys;sa=editicons');
1246
		}
1247
1248
		$context[$context['admin_menu_name']]['current_subsection'] = 'editicons';
1249
		$token = createToken('admin-sort');
1250
		$listOptions = array(
1251
			'id' => 'message_icon_list',
1252
			'title' => $txt['icons_edit_message_icons'],
1253
			'sortable' => true,
1254
			'base_href' => $scripturl . '?action=admin;area=smileys;sa=editicons',
1255
			'get_items' => array(
1256
				'function' => array($this, 'list_fetchMessageIconsDetails'),
1257
			),
1258
			'no_items_label' => $txt['icons_no_entries'],
1259
			'columns' => array(
1260
				'icon' => array(
1261
					'data' => array(
1262
						'sprintf' => array(
1263
							'format' => '<img src="%1$s" alt="%2$s" />',
1264
							'params' => array(
1265
								'image_url' => false,
1266
								'filename' => true,
1267
							),
1268
						),
1269
						'class' => 'centertext',
1270
					),
1271
				),
1272
				'filename' => array(
1273
					'header' => array(
1274
						'value' => $txt['smileys_filename'],
1275
					),
1276
					'data' => array(
1277
						'sprintf' => array(
1278
							'format' => '%1$s.png',
1279
							'params' => array(
1280
								'filename' => true,
1281
							),
1282
						),
1283
					),
1284
				),
1285
				'tooltip' => array(
1286
					'header' => array(
1287
						'value' => $txt['smileys_description'],
1288
					),
1289
					'data' => array(
1290
						'db_htmlsafe' => 'title',
1291
					),
1292
				),
1293
				'board' => array(
1294
					'header' => array(
1295
						'value' => $txt['icons_board'],
1296
					),
1297
					'data' => array(
1298
						'db' => 'board',
1299
					),
1300
				),
1301
				'modify' => array(
1302
					'header' => array(
1303
						'value' => $txt['smileys_modify'],
1304
					),
1305
					'data' => array(
1306
						'sprintf' => array(
1307
							'format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=editicon;icon=%1$s">' . $txt['smileys_modify'] . '</a>',
1308
							'params' => array(
1309
								'id' => false,
1310
							),
1311
						),
1312
					),
1313
				),
1314
				'check' => array(
1315
					'header' => array(
1316
						'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check" />',
1317
						'class' => 'centertext',
1318
					),
1319
					'data' => array(
1320
						'sprintf' => array(
1321
							'format' => '<input type="checkbox" name="checked_icons[]" value="%1$d" class="input_check" />',
1322
							'params' => array(
1323
								'id' => false,
1324
							),
1325
						),
1326
						'class' => 'centertext',
1327
					),
1328
				),
1329
			),
1330
			'form' => array(
1331
				'href' => $scripturl . '?action=admin;area=smileys;sa=editicons',
1332
				'hidden_fields' => array(
1333
					'icons_save' => 1,
1334
				)
1335
			),
1336
			'additional_rows' => array(
1337
				array(
1338
					'position' => 'below_table_data',
1339
					'class' => 'submitbutton',
1340
					'value' => '
1341
						<input type="submit" name="delete" value="' . $txt['quickmod_delete_selected'] . '" onclick="return confirm(\'' . $txt['icons_confirm'] . '\');" class="right_submit" />
1342
						<a class="linkbutton" href="' . $scripturl . '?action=admin;area=smileys;sa=editicon">' . $txt['icons_add_new'] . '</a>',
1343
				),
1344
				array(
1345
					'position' => 'after_title',
1346
					'value' => $txt['icons_reorder_note'],
1347
				),
1348
			),
1349
			'javascript' => '
1350
				$().elkSortable({
1351
					sa: "messageiconorder",
1352
					error: "' . $txt['admin_order_error'] . '",
1353
					title: "' . $txt['admin_order_title'] . '",
1354
					placeholder: "ui-state-highlight",
1355
					href: "?action=admin;area=smileys;sa=editicons",
1356
					token: {token_var: "' . $token['admin-sort_token_var'] . '", token_id: "' . $token['admin-sort_token'] . '"}
1357
				});
1358
			',
1359
		);
1360
1361
		createList($listOptions);
1362
1363
		// If we're adding/editing an icon we'll need a list of boards
1364
		if ($context['sub_action'] == 'editicon' || isset($this->_req->post->add))
1365
		{
1366
			// Force the sub_template just in case.
1367
			$context['sub_template'] = 'editicon';
1368
			$context['new_icon'] = !isset($this->_req->query->icon);
1369
1370
			// Get the properties of the current icon from the icon list.
1371
			if (!$context['new_icon'])
1372
				$context['icon'] = $context['icons'][$this->_req->query->icon];
1373
1374
			// Get a list of boards needed for assigning this icon to a specific board.
1375
			$boardListOptions = array(
1376
				'selected_board' => isset($context['icon']['board_id']) ? $context['icon']['board_id'] : 0,
1377
			);
1378
			require_once(SUBSDIR . '/Boards.subs.php');
1379
			$context += getBoardList($boardListOptions);
1380
		}
1381
	}
1382
1383
	/**
1384
	 * Allows to edit smileys order.
1385
	 */
1386
	public function action_setorder()
1387
	{
1388
		global $context, $txt;
1389
1390
		require_once(SUBSDIR . '/Smileys.subs.php');
1391
		$context['sub_template'] = 'setorder';
1392
1393
		// Move smileys to another position.
1394
		if (isset($this->_req->query->reorder))
1395
		{
1396
			checkSession('get');
1397
1398
			$this->_req->query->location = empty($this->_req->query->location) || $this->_req->query->location != 'popup' ? 0 : 2;
1399
			$this->_req->query->source = empty($this->_req->query->source) ? 0 : (int) $this->_req->query->source;
1400
1401
			if (empty($this->_req->query->source))
1402
				Errors::instance()->fatal_lang_error('smiley_not_found');
1403
1404
			$smiley = array();
1405
1406
			if (!empty($this->_req->query->after))
1407
			{
1408
				$this->_req->query->after = (int) $this->_req->query->after;
1409
1410
				$smiley = getSmileyPosition($this->_req->query->location, $this->_req->query->after);
1411
				if (empty($smiley))
1412
					Errors::instance()->fatal_lang_error('smiley_not_found');
1413
			}
1414
			else
1415
			{
1416
				$smiley['row'] = (int) $this->_req->query->row;
1417
				$smiley['order'] = -1;
1418
				$smiley['location'] = (int) $this->_req->query->location;
1419
			}
1420
1421
			moveSmileyPosition($smiley, $this->_req->query->source);
1422
		}
1423
1424
		$context['smileys'] = getSmileys();
1425
		$context['move_smiley'] = empty($this->_req->query->move) ? 0 : (int) $this->_req->query->move;
1426
1427
		// Make sure all rows are sequential.
1428
		foreach (array_keys($context['smileys']) as $location)
1429
			$context['smileys'][$location] = array(
1430
				'id' => $location,
1431
				'title' => $location == 'postform' ? $txt['smileys_location_form'] : $txt['smileys_location_popup'],
1432
				'description' => $location == 'postform' ? $txt['smileys_location_form_description'] : $txt['smileys_location_popup_description'],
1433
				'last_row' => count($context['smileys'][$location]['rows']),
1434
				'rows' => array_values($context['smileys'][$location]['rows']),
1435
			);
1436
1437
		// Check & fix smileys that are not ordered properly in the database.
1438
		foreach (array_keys($context['smileys']) as $location)
1439
		{
1440
			foreach ($context['smileys'][$location]['rows'] as $id => $smiley_row)
1441
			{
1442
				// Fix empty rows if any.
1443
				if ($id != $smiley_row[0]['row'])
1444
				{
1445
					updateSmileyRow($id, $smiley_row[0]['row'], $location);
1446
					// Only change the first row value of the first smiley (we don't need the others :P).
1447
					$context['smileys'][$location]['rows'][$id][0]['row'] = $id;
1448
				}
1449
1450
				// Make sure the smiley order is always sequential.
1451
				foreach ($smiley_row as $order_id => $smiley)
1452
					if ($order_id != $smiley['order'])
1453
						updateSmileyOrder($smiley['id'], $order_id);
1454
			}
1455
		}
1456
1457
		$this->clearSmileyCache();
1458
1459
		createToken('admin-sort');
1460
	}
1461
1462
	/**
1463
	 * Install a smiley set.
1464
	 */
1465
	public function action_install()
1466
	{
1467
		global $modSettings, $scripturl, $context, $txt, $user_info;
1468
1469
		isAllowedTo('manage_smileys');
1470
		checkSession('request');
1471
1472
		// One of these two may be necessary
1473
		loadLanguage('Errors');
1474
		loadLanguage('Packages');
1475
1476
		require_once(SUBSDIR . '/Smileys.subs.php');
1477
		require_once(SUBSDIR . '/Package.subs.php');
1478
1479
		// Installing unless proven otherwise
1480
		$testing = false;
1481
		$destination = '';
1482
		$name = '';
1483
1484
		if (isset($this->_req->query->set_gz))
1485
		{
1486
			$base_name = strtr(basename($this->_req->query->set_gz), ':/', '-_');
1487
			$name = Util::htmlspecialchars(strtok(basename($this->_req->query->set_gz), '.'));
1488
			$context['filename'] = $base_name;
1489
1490
			// Check that the smiley is from simplemachines.org, for now... maybe add mirroring later.
1491
			if (!isAuthorizedServer($this->_req->query->set_gz) == 0)
1492
				Errors::instance()->fatal_lang_error('not_valid_server');
1493
1494
			$destination = BOARDDIR . '/packages/' . $base_name;
1495
1496
			if (file_exists($destination))
1497
				Errors::instance()->fatal_lang_error('package_upload_error_exists');
1498
1499
			// Let's copy it to the packages directory
1500
			file_put_contents($destination, fetch_web_data($this->_req->query->set_gz));
1501
			$testing = true;
1502
		}
1503
		elseif (isset($this->_req->query->package))
1504
		{
1505
			$base_name = basename($this->_req->query->package);
1506
			$name = Util::htmlspecialchars(strtok(basename($this->_req->query->package), '.'));
1507
			$context['filename'] = $base_name;
1508
1509
			$destination = BOARDDIR . '/packages/' . basename($this->_req->query->package);
1510
		}
1511
1512
		if (!file_exists($destination))
1513
			Errors::instance()->fatal_lang_error('package_no_file', false);
1514
1515
		// Make sure temp directory exists and is empty.
1516
		if (file_exists(BOARDDIR . '/packages/temp'))
1517
			deltree(BOARDDIR . '/packages/temp', false);
1518
1519
		if (!mktree(BOARDDIR . '/packages/temp', 0755))
1520
		{
1521
			deltree(BOARDDIR . '/packages/temp', false);
1522
			if (!mktree(BOARDDIR . '/packages/temp', 0777))
1523
			{
1524
				deltree(BOARDDIR . '/packages/temp', false);
1525
				// @todo not sure about url in destination_url
1526
				create_chmod_control(array(BOARDDIR . '/packages/temp/delme.tmp'), array('destination_url' => $scripturl . '?action=admin;area=smileys;sa=install;set_gz=' . $this->_req->query->set_gz, 'crash_on_error' => true));
1527
1528
				deltree(BOARDDIR . '/packages/temp', false);
1529
				if (!mktree(BOARDDIR . '/packages/temp', 0777))
1530
					Errors::instance()->fatal_lang_error('package_cant_download', false);
1531
			}
1532
		}
1533
1534
		$extracted = read_tgz_file($destination, BOARDDIR . '/packages/temp');
1535
1536
		// @todo needs to change the URL in the next line ;)
1537
		if (!$extracted)
1538
			Errors::instance()->fatal_lang_error('packageget_unable', false, array('http://custom.elkarte.net/index.php?action=search;type=12;basic_search=' . $name));
1539
1540
		if ($extracted && !file_exists(BOARDDIR . '/packages/temp/package-info.xml'))
1541
		{
1542
			foreach ($extracted as $file)
0 ignored issues
show
Bug introduced by
The expression $extracted of type boolean|array<integer,*> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1543
			{
1544
				if (basename($file['filename']) == 'package-info.xml')
1545
				{
1546
					$base_path = dirname($file['filename']) . '/';
1547
					break;
1548
				}
1549
			}
1550
		}
1551
1552
		if (!isset($base_path))
1553
			$base_path = '';
1554
1555
		if (!file_exists(BOARDDIR . '/packages/temp/' . $base_path . 'package-info.xml'))
1556
			Errors::instance()->fatal_lang_error('package_get_error_missing_xml', false);
1557
1558
		$smileyInfo = getPackageInfo($context['filename']);
1559
		if (!is_array($smileyInfo))
1560
			Errors::instance()->fatal_lang_error($smileyInfo);
1561
1562
		// See if it is installed?
1563
		if (isSmileySetInstalled($smileyInfo['id']))
1564
			fata_lang_error('package_installed_warning1');
1565
1566
		// Everything is fine, now it's time to do something, first we test
1567
		$actions = parsePackageInfo($smileyInfo['xml'], true, 'install');
1568
1569
		$context['post_url'] = $scripturl . '?action=admin;area=smileys;sa=install;package=' . $base_name;
0 ignored issues
show
Bug introduced by
The variable $base_name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1570
		$context['has_failure'] = false;
1571
		$context['actions'] = array();
1572
		$context['ftp_needed'] = false;
1573
1574
		$bbc_parser = \BBC\ParserWrapper::getInstance();
1575
1576
		foreach ($actions as $action)
1577
		{
1578
			if ($action['type'] == 'readme' || $action['type'] == 'license')
1579
			{
1580
				$type = 'package_' . $action['type'];
1581
				if (file_exists(BOARDDIR . '/packages/temp/' . $base_path . $action['filename']))
1582
					$context[$type] = htmlspecialchars(trim(file_get_contents(BOARDDIR . '/packages/temp/' . $base_path . $action['filename']), "\n\r"), ENT_COMPAT, 'UTF-8');
1583
				elseif (file_exists($action['filename']))
1584
					$context[$type] = htmlspecialchars(trim(file_get_contents($action['filename']), "\n\r"), ENT_COMPAT, 'UTF-8');
1585
1586
				if (!empty($action['parse_bbc']))
1587
				{
1588
					require_once(SUBSDIR . '/Post.subs.php');
1589
					preparsecode($context[$type]);
1590
					$context[$type] = $bbc_parser->parsePackage($context[$type]);
1591
				}
1592
				else
1593
					$context[$type] = nl2br($context[$type]);
1594
1595
				continue;
1596
			}
1597
			elseif ($action['type'] == 'require-dir')
1598
			{
1599
				// Do this one...
1600
				$thisAction = array(
1601
					'type' => $txt['package_extract'] . ' ' . ($action['type'] == 'require-dir' ? $txt['package_tree'] : $txt['package_file']),
1602
					'action' => Util::htmlspecialchars(strtr($action['destination'], array(BOARDDIR => '.')))
1603
				);
1604
1605
				$file = BOARDDIR . '/packages/temp/' . $base_path . $action['filename'];
1606
				if (isset($action['filename']) && (!file_exists($file) || !is_writable(dirname($action['destination']))))
1607
				{
1608
					$context['has_failure'] = true;
1609
1610
					$thisAction += array(
1611
						'description' => $txt['package_action_error'],
1612
						'failed' => true,
1613
					);
1614
				}
1615
1616
				// Show a description for the action if one is provided
1617
				if (empty($thisAction['description']))
1618
					$thisAction['description'] = isset($action['description']) ? $action['description'] : '';
1619
1620
				$context['actions'][] = $thisAction;
1621
			}
1622
			elseif ($action['type'] == 'credits')
1623
			{
1624
				// Time to build the billboard
1625
				$credits_tag = array(
1626
					'url' => $action['url'],
1627
					'license' => $action['license'],
1628
					'copyright' => $action['copyright'],
1629
					'title' => $action['title'],
1630
				);
1631
			}
1632
		}
1633
1634
		if ($testing)
1635
		{
1636
			$context['sub_template'] = 'view_package';
1637
			$context['uninstalling'] = false;
1638
			$context['is_installed'] = false;
1639
			$context['package_name'] = $smileyInfo['name'];
1640
			loadTemplate('Packages');
1641
		}
1642
		// Do the actual install
1643
		else
1644
		{
1645
			$actions = parsePackageInfo($smileyInfo['xml'], false, 'install');
0 ignored issues
show
Unused Code introduced by
$actions is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1646
			foreach ($context['actions'] as $action)
0 ignored issues
show
Bug introduced by
The expression $context['actions'] of type string|false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1647
			{
1648
				updateSettings(array(
1649
					'smiley_sets_known' => $modSettings['smiley_sets_known'] . ',' . basename($action['action']),
1650
					'smiley_sets_names' => $modSettings['smiley_sets_names'] . "\n" . $smileyInfo['name'] . (count($context['actions']) > 1 ? ' ' . (!empty($action['description']) ? Util::htmlspecialchars($action['description']) : basename($action['action'])) : ''),
1651
				));
1652
			}
1653
1654
			package_flush_cache();
1655
1656
			// Time to tell pacman we have a new package installed!
1657
			package_put_contents(BOARDDIR . '/packages/installed.list', time());
1658
1659
			// Credits tag?
1660
			$credits_tag = (empty($credits_tag)) ? '' : serialize($credits_tag);
1661
			$installed = array(
1662
				'filename' => $smileyInfo['filename'],
1663
				'name' => $smileyInfo['name'],
1664
				'package_id' => $smileyInfo['id'],
1665
				'version' => $smileyInfo['filename'],
1666
				'id_member' => $user_info['id'],
1667
				'member_name' => $user_info['name'],
1668
				'credits_tag' => $credits_tag,
1669
			);
1670
			logPackageInstall($installed);
1671
1672
			logAction('install_package', array('package' => Util::htmlspecialchars($smileyInfo['name']), 'version' => Util::htmlspecialchars($smileyInfo['version'])), 'admin');
1673
1674
			$this->clearSmileyCache();
1675
		}
1676
1677
		if (file_exists(BOARDDIR . '/packages/temp'))
1678
			deltree(BOARDDIR . '/packages/temp');
1679
1680
		if (!$testing)
1681
			redirectexit('action=admin;area=smileys');
1682
	}
1683
1684
	/**
1685
	 * Sets our internal smiley context.
1686
	 */
1687
	private function _initSmileyContext()
1688
	{
1689
		global $modSettings;
1690
1691
		// Validate the smiley set name.
1692
		$smiley_sets = explode(',', $modSettings['smiley_sets_known']);
1693
		$set_names = explode("\n", $modSettings['smiley_sets_names']);
1694
		$smiley_context = array();
1695
1696
		foreach ($smiley_sets as $i => $set)
1697
			$smiley_context[$set] = $set_names[$i];
1698
1699
		$this->_smiley_context = $smiley_context;
1700
	}
1701
1702
	/**
1703
	 * A function to import new smileys from an existing directory into the database.
1704
	 *
1705
	 * @param string $smileyPath
1706
	 */
1707
	public function importSmileys($smileyPath)
1708
	{
1709
		global $modSettings;
1710
1711
		require_once(SUBSDIR . '/Smileys.subs.php');
1712
1713
		if (empty($modSettings['smileys_dir']) || !is_dir($modSettings['smileys_dir'] . '/' . $smileyPath))
1714
			Errors::instance()->fatal_lang_error('smiley_set_unable_to_import');
1715
1716
		$smileys = array();
1717
		$dir = dir($modSettings['smileys_dir'] . '/' . $smileyPath);
1718
		while ($entry = $dir->read())
1719
		{
1720
			if (in_array(strrchr($entry, '.'), array('.jpg', '.gif', '.jpeg', '.png')))
1721
				$smileys[strtolower($entry)] = $entry;
1722
		}
1723
		$dir->close();
1724
1725
		// Exclude the smileys that are already in the database.
1726
		$duplicates = smileyExists($smileys);
1727
1728
		foreach ($duplicates as $duplicate)
1729
		{
1730
			if (isset($smileys[strtolower($duplicate)]))
1731
				unset($smileys[strtolower($duplicate)]);
1732
		}
1733
1734
		$smiley_order = getMaxSmileyOrder();
1735
1736
		$new_smileys = array();
1737
		foreach ($smileys as $smiley)
1738
			if (strlen($smiley) <= 48)
1739
				$new_smileys[] = array(':' . strtok($smiley, '.') . ':', $smiley, strtok($smiley, '.'), 0, ++$smiley_order);
1740
1741
		if (!empty($new_smileys))
1742
		{
1743
			addSmiley($new_smileys);
1744
1745
			// Make sure the smiley codes are still in the right order.
1746
			sortSmileyTable();
0 ignored issues
show
Deprecated Code introduced by
The function sortSmileyTable() has been deprecated with message: since 1.0 - the ordering is done in the query, probably not needed

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
1747
1748
			$this->clearSmileyCache();
1749
		}
1750
	}
1751
1752
	/**
1753
	 * Callback function for createList().
1754
	 *
1755
	 * @param int $start The item to start with (for pagination purposes)
1756
	 * @param int $items_per_page  The number of items to show per page
1757
	 * @param string $sort A string indicating how to sort the results
1758
	 */
1759
	public function list_fetchMessageIconsDetails($start, $items_per_page, $sort)
0 ignored issues
show
Unused Code introduced by
The parameter $start is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $items_per_page is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $sort is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1760
	{
1761
		return fetchMessageIconsDetails();
1762
	}
1763
1764
	protected function clearSmileyCache()
1765
	{
1766
		Cache::instance()->remove('parsing_smileys');
1767
		Cache::instance()->remove('posting_smileys');
1768
	}
1769
}