Failed Conditions
Branch release-2.1 (4e22cf)
by Rick
06:39
created

Sources/ManageSmileys.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * This file takes care of all administration of smileys.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines http://www.simplemachines.org
10
 * @copyright 2017 Simple Machines and individual contributors
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 4
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * This is the dispatcher of smileys administration.
21
 */
22
function ManageSmileys()
23
{
24
	global $context, $txt, $modSettings;
25
26
	isAllowedTo('manage_smileys');
27
28
	loadLanguage('ManageSmileys');
29
	loadTemplate('ManageSmileys');
30
31
	$subActions = array(
32
		'addsmiley' => 'AddSmiley',
33
		'editicon' => 'EditMessageIcons',
34
		'editicons' => 'EditMessageIcons',
35
		'editsets' => 'EditSmileySets',
36
		'editsmileys' => 'EditSmileys',
37
		'import' => 'EditSmileySets',
38
		'modifyset' => 'EditSmileySets',
39
		'modifysmiley' => 'EditSmileys',
40
		'setorder' => 'EditSmileyOrder',
41
		'settings' => 'EditSmileySettings',
42
		'install' => 'InstallSmileySet'
43
	);
44
45
	// If customized smileys is disabled don't show the setting page
46
	if (empty($modSettings['smiley_enable']))
47
	{
48
		unset($subActions['addsmiley']);
49
		unset($subActions['editsmileys']);
50
		unset($subActions['setorder']);
51
		unset($subActions['modifysmiley']);
52
	}
53
	if (empty($modSettings['messageIcons_enable']))
54
	{
55
		unset($subActions['editicon']);
56
		unset($subActions['editicons']);
57
	}
58
59
	// Default the sub-action to 'edit smiley settings'.
60
	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'editsets';
61
62
	$context['page_title'] = $txt['smileys_manage'];
63
	$context['sub_action'] = $_REQUEST['sa'];
64
	$context['sub_template'] = $context['sub_action'];
65
66
	// Load up all the tabs...
67
	$context[$context['admin_menu_name']]['tab_data'] = array(
68
		'title' => $txt['smileys_manage'],
69
		'help' => 'smileys',
70
		'description' => $txt['smiley_settings_explain'],
71
		'tabs' => array(
72
			'editsets' => array(
73
				'description' => $txt['smiley_editsets_explain'],
74
			),
75
			'addsmiley' => array(
76
				'description' => $txt['smiley_addsmiley_explain'],
77
			),
78
			'editsmileys' => array(
79
				'description' => $txt['smiley_editsmileys_explain'],
80
			),
81
			'setorder' => array(
82
				'description' => $txt['smiley_setorder_explain'],
83
			),
84
			'editicons' => array(
85
				'description' => $txt['icons_edit_icons_explain'],
86
			),
87
			'settings' => array(
88
				'description' => $txt['smiley_settings_explain'],
89
			),
90
		),
91
	);
92
93
	// Some settings may not be enabled, disallow these from the tabs as appropriate.
94
	if (empty($modSettings['messageIcons_enable']))
95
		$context[$context['admin_menu_name']]['tab_data']['tabs']['editicons']['disabled'] = true;
96
	if (empty($modSettings['smiley_enable']))
97
	{
98
		$context[$context['admin_menu_name']]['tab_data']['tabs']['addsmiley']['disabled'] = true;
99
		$context[$context['admin_menu_name']]['tab_data']['tabs']['editsmileys']['disabled'] = true;
100
		$context[$context['admin_menu_name']]['tab_data']['tabs']['setorder']['disabled'] = true;
101
	}
102
103
	call_integration_hook('integrate_manage_smileys', array(&$subActions));
104
105
	// Call the right function for this sub-action.
106
	call_helper($subActions[$_REQUEST['sa']]);
107
}
108
109
/**
110
 * Handles modifying smileys settings.
111
 *
112
 * @param bool $return_config Whether or not to return the config_vars array (used for admin search)
113
 * @return void|array Returns nothing or returns the $config_vars array if $return_config is true
114
 */
115
function EditSmileySettings($return_config = false)
116
{
117
	global $modSettings, $context, $txt, $boarddir, $sourcedir, $scripturl;
118
119
	// The directories...
120
	$context['smileys_dir'] = empty($modSettings['smileys_dir']) ? $boarddir . '/Smileys' : $modSettings['smileys_dir'];
121
	$context['smileys_dir_found'] = is_dir($context['smileys_dir']);
122
123
	// Get the names of the smiley sets.
124
	$smiley_sets = explode(',', $modSettings['smiley_sets_known']);
125
	$set_names = explode("\n", $modSettings['smiley_sets_names']);
126
127
	$smiley_context = array();
128
	foreach ($smiley_sets as $i => $set)
129
		$smiley_context[$set] = $set_names[$i];
130
131
	// All the settings for the page...
132
	$config_vars = array(
133
		array('title', 'settings'),
134
			// Inline permissions.
135
			array('permissions', 'manage_smileys'),
136
		'',
137
			array('select', 'smiley_sets_default', $smiley_context),
138
			array('check', 'smiley_sets_enable'),
139
			array('check', 'smiley_enable', 'subtext' => $txt['smileys_enable_note']),
140
			array('text', 'smileys_url', 40),
141
			array('warning', !is_dir($context['smileys_dir']) ? 'setting_smileys_dir_wrong' : ''),
142
			array('text', 'smileys_dir', 'invalid' => !$context['smileys_dir_found'], 40),
143
		'',
144
			// Message icons.
145
			array('check', 'messageIcons_enable', 'subtext' => $txt['setting_messageIcons_enable_note']),
146
	);
147
148
	call_integration_hook('integrate_modify_smiley_settings', array(&$config_vars));
149
150
	if ($return_config)
151
		return $config_vars;
152
153
	// Setup the basics of the settings template.
154
	require_once($sourcedir . '/ManageServer.php');
155
	$context['sub_template'] = 'show_settings';
156
157
	// Finish up the form...
158
	$context['post_url'] = $scripturl . '?action=admin;area=smileys;save;sa=settings';
159
160
	// Saving the settings?
161
	if (isset($_GET['save']))
162
	{
163
		checkSession();
164
165
		// Validate the smiley set name.
166
		$_POST['smiley_sets_default'] = empty($smiley_context[$_POST['smiley_sets_default']]) ? 'default' : $_POST['smiley_sets_default'];
167
168
		call_integration_hook('integrate_save_smiley_settings');
169
170
		saveDBSettings($config_vars);
171
		$_SESSION['adm-save'] = true;
172
173
		cache_put_data('parsing_smileys', null, 480);
174
		cache_put_data('posting_smileys', null, 480);
175
176
		redirectexit('action=admin;area=smileys;sa=settings');
177
	}
178
179
	// We need this for the in-line permissions
180
	createToken('admin-mp');
181
182
	prepareDBSettingContext($config_vars);
183
}
184
185
/**
186
 * List, add, remove, modify smileys sets.
187
 */
188
function EditSmileySets()
189
{
190
	global $modSettings, $context, $txt;
191
	global $smcFunc, $scripturl, $sourcedir;
192
193
	// Set the right tab to be selected.
194
	$context[$context['admin_menu_name']]['current_subsection'] = 'editsets';
195
196
	// They must've been submitted a form.
197
	if (isset($_POST['smiley_save']))
198
	{
199
		checkSession();
200
		validateToken('admin-mss', 'request');
201
202
		// Delete selected smiley sets.
203
		if (!empty($_POST['delete']) && !empty($_POST['smiley_set']))
204
		{
205
			$set_paths = explode(',', $modSettings['smiley_sets_known']);
206
			$set_names = explode("\n", $modSettings['smiley_sets_names']);
207
			foreach ($_POST['smiley_set'] as $id => $val)
208
			{
209
				// If this is the set you've marked as default, or the only one remaining, you can't delete it
210
				if ($modSettings['smiley_sets_default'] != $set_paths[$id] && count($set_paths) != 1 && isset($set_paths[$id], $set_names[$id]))
211
					unset($set_paths[$id], $set_names[$id]);
212
			}
213
214
			// Shortcut... array_merge() on a single array resets the numeric keys
215
			$set_paths = array_merge($set_paths);
216
			$set_names = array_merge($set_names);
217
218
			updateSettings(array(
219
				'smiley_sets_known' => implode(',', $set_paths),
220
				'smiley_sets_names' => implode("\n", $set_names),
221
				'smiley_sets_default' => in_array($modSettings['smiley_sets_default'], $set_paths) ? $modSettings['smiley_sets_default'] : $set_paths[0],
222
			));
223
		}
224
		// Add a new smiley set.
225
		elseif (!empty($_POST['add']))
226
			$context['sub_action'] = 'modifyset';
227
		// Create or modify a smiley set.
228
		elseif (isset($_POST['set']))
229
		{
230
			$set_paths = explode(',', $modSettings['smiley_sets_known']);
231
			$set_names = explode("\n", $modSettings['smiley_sets_names']);
232
233
			// Create a new smiley set.
234
			if ($_POST['set'] == -1 && isset($_POST['smiley_sets_path']))
235
			{
236
				if (in_array($_POST['smiley_sets_path'], $set_paths))
237
					fatal_lang_error('smiley_set_already_exists');
238
239
				updateSettings(array(
240
					'smiley_sets_known' => $modSettings['smiley_sets_known'] . ',' . $_POST['smiley_sets_path'],
241
					'smiley_sets_names' => $modSettings['smiley_sets_names'] . "\n" . $_POST['smiley_sets_name'],
242
					'smiley_sets_default' => empty($_POST['smiley_sets_default']) ? $modSettings['smiley_sets_default'] : $_POST['smiley_sets_path'],
243
				));
244
			}
245
			// Modify an existing smiley set.
246
			else
247
			{
248
				// Make sure the smiley set exists.
249
				if (!isset($set_paths[$_POST['set']]) || !isset($set_names[$_POST['set']]))
250
					fatal_lang_error('smiley_set_not_found');
251
252
				// Make sure the path is not yet used by another smileyset.
253
				if (in_array($_POST['smiley_sets_path'], $set_paths) && $_POST['smiley_sets_path'] != $set_paths[$_POST['set']])
254
					fatal_lang_error('smiley_set_path_already_used');
255
256
				$set_paths[$_POST['set']] = $_POST['smiley_sets_path'];
257
				$set_names[$_POST['set']] = $_POST['smiley_sets_name'];
258
				updateSettings(array(
259
					'smiley_sets_known' => implode(',', $set_paths),
260
					'smiley_sets_names' => implode("\n", $set_names),
261
					'smiley_sets_default' => empty($_POST['smiley_sets_default']) ? $modSettings['smiley_sets_default'] : $_POST['smiley_sets_path']
262
				));
263
			}
264
265
			// The user might have checked to also import smileys.
266
			if (!empty($_POST['smiley_sets_import']))
267
				ImportSmileys($_POST['smiley_sets_path']);
268
		}
269
		cache_put_data('parsing_smileys', null, 480);
270
		cache_put_data('posting_smileys', null, 480);
271
	}
272
273
	// Load all available smileysets...
274
	$context['smiley_sets'] = explode(',', $modSettings['smiley_sets_known']);
275
	$set_names = explode("\n", $modSettings['smiley_sets_names']);
276 View Code Duplication
	foreach ($context['smiley_sets'] as $i => $set)
277
		$context['smiley_sets'][$i] = array(
278
			'id' => $i,
279
			'path' => $smcFunc['htmlspecialchars']($set),
280
			'name' => $smcFunc['htmlspecialchars']($set_names[$i]),
281
			'selected' => $set == $modSettings['smiley_sets_default']
282
		);
283
284
	// Importing any smileys from an existing set?
285
	if ($context['sub_action'] == 'import')
286
	{
287
		checkSession('get');
288
		validateToken('admin-mss', 'request');
289
290
		$_GET['set'] = (int) $_GET['set'];
291
292
		// Sanity check - then import.
293
		if (isset($context['smiley_sets'][$_GET['set']]))
294
			ImportSmileys(un_htmlspecialchars($context['smiley_sets'][$_GET['set']]['path']));
295
296
		// Force the process to continue.
297
		$context['sub_action'] = 'modifyset';
298
		$context['sub_template'] = 'modifyset';
299
	}
300
	// If we're modifying or adding a smileyset, some context info needs to be set.
301
	if ($context['sub_action'] == 'modifyset')
302
	{
303
		$_GET['set'] = !isset($_GET['set']) ? -1 : (int) $_GET['set'];
304
		if ($_GET['set'] == -1 || !isset($context['smiley_sets'][$_GET['set']]))
305
			$context['current_set'] = array(
306
				'id' => '-1',
307
				'path' => '',
308
				'name' => '',
309
				'selected' => false,
310
				'is_new' => true,
311
			);
312
		else
313
		{
314
			$context['current_set'] = &$context['smiley_sets'][$_GET['set']];
315
			$context['current_set']['is_new'] = false;
316
317
			// Calculate whether there are any smileys in the directory that can be imported.
318
			if (!empty($modSettings['smiley_enable']) && !empty($modSettings['smileys_dir']) && is_dir($modSettings['smileys_dir'] . '/' . $context['current_set']['path']))
319
			{
320
				$smileys = array();
321
				$dir = dir($modSettings['smileys_dir'] . '/' . $context['current_set']['path']);
322 View Code Duplication
				while ($entry = $dir->read())
323
				{
324
					if (in_array(strrchr($entry, '.'), array('.jpg', '.gif', '.jpeg', '.png')))
325
						$smileys[strtolower($entry)] = $entry;
326
				}
327
				$dir->close();
328
329
				if (empty($smileys))
330
					fatal_lang_error('smiley_set_dir_not_found', false, array($context['current_set']['name']));
331
332
				// Exclude the smileys that are already in the database.
333
				$request = $smcFunc['db_query']('', '
334
					SELECT filename
335
					FROM {db_prefix}smileys
336
					WHERE filename IN ({array_string:smiley_list})',
337
					array(
338
						'smiley_list' => $smileys,
339
					)
340
				);
341 View Code Duplication
				while ($row = $smcFunc['db_fetch_assoc']($request))
342
					if (isset($smileys[strtolower($row['filename'])]))
343
						unset($smileys[strtolower($row['filename'])]);
344
				$smcFunc['db_free_result']($request);
345
346
				$context['current_set']['can_import'] = count($smileys);
347
				$context['current_set']['import_url'] = $scripturl . '?action=admin;area=smileys;sa=import;set=' . $context['current_set']['id'] . ';' . $context['session_var'] . '=' . $context['session_id'];
348
			}
349
		}
350
351
		// Retrieve all potential smiley set directories.
352
		$context['smiley_set_dirs'] = array();
353
		if (!empty($modSettings['smileys_dir']) && is_dir($modSettings['smileys_dir']))
354
		{
355
			$dir = dir($modSettings['smileys_dir']);
356
			while ($entry = $dir->read())
357
			{
358
				if (!in_array($entry, array('.', '..')) && is_dir($modSettings['smileys_dir'] . '/' . $entry))
359
					$context['smiley_set_dirs'][] = array(
360
						'id' => $entry,
361
						'path' => $modSettings['smileys_dir'] . '/' . $entry,
362
						'selectable' => $entry == $context['current_set']['path'] || !in_array($entry, explode(',', $modSettings['smiley_sets_known'])),
363
						'current' => $entry == $context['current_set']['path'],
364
					);
365
			}
366
			$dir->close();
367
		}
368
	}
369
370
	// This is our save haven.
371
	createToken('admin-mss', 'request');
372
373
	// In case we need to import smileys, we need to add the token in now.
374
	if (isset($context['current_set']['import_url']))
375
		$context['current_set']['import_url'] .= ';' . $context['admin-mss_token_var'] . '=' . $context['admin-mss_token'];
376
377
	$listOptions = array(
378
		'id' => 'smiley_set_list',
379
		'title' => $txt['smiley_sets'],
380
		'no_items_label' => $txt['smiley_sets_none'],
381
		'base_href' => $scripturl . '?action=admin;area=smileys;sa=editsets',
382
		'default_sort_col' => 'default',
383
		'get_items' => array(
384
			'function' => 'list_getSmileySets',
385
		),
386
		'get_count' => array(
387
			'function' => 'list_getNumSmileySets',
388
		),
389
		'columns' => array(
390
			'default' => array(
391
				'header' => array(
392
					'value' => $txt['smiley_sets_default'],
393
					'class' => 'centercol',
394
				),
395
				'data' => array(
396
					'function' => function ($rowData)
397
					{
398
						return $rowData['selected'] ? '<span class="generic_icons valid"></span>' : '';
399
					},
400
					'class' => 'centercol',
401
				),
402
				'sort' => array(
403
					'default' => 'selected DESC',
404
				),
405
			),
406
			'name' => array(
407
				'header' => array(
408
					'value' => $txt['smiley_sets_name'],
409
				),
410
				'data' => array(
411
					'db_htmlsafe' => 'name',
412
				),
413
				'sort' => array(
414
					'default' => 'name',
415
					'reverse' => 'name DESC',
416
				),
417
			),
418
			'url' => array(
419
				'header' => array(
420
					'value' => $txt['smiley_sets_url'],
421
				),
422
				'data' => array(
423
					'sprintf' => array(
424
						'format' => $modSettings['smileys_url'] . '/<strong>%1$s</strong>/...',
425
						'params' => array(
426
							'path' => true,
427
						),
428
					),
429
				),
430
				'sort' => array(
431
					'default' => 'path',
432
					'reverse' => 'path DESC',
433
				),
434
			),
435
			'modify' => array(
436
				'header' => array(
437
					'value' => $txt['smiley_set_modify'],
438
					'class' => 'centercol',
439
				),
440
				'data' => array(
441
					'sprintf' => array(
442
						'format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=modifyset;set=%1$d">' . $txt['smiley_set_modify'] . '</a>',
443
						'params' => array(
444
							'id' => true,
445
						),
446
					),
447
					'class' => 'centercol',
448
				),
449
			),
450
			'check' => array(
451
				'header' => array(
452
					'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check">',
453
					'class' => 'centercol',
454
				),
455
				'data' => array(
456
					'function' => function ($rowData)
457
					{
458
						return $rowData['selected'] ? '' : sprintf('<input type="checkbox" name="smiley_set[%1$d]" class="input_check">', $rowData['id']);
459
					},
460
					'class' => 'centercol',
461
				),
462
			),
463
		),
464
		'form' => array(
465
			'href' => $scripturl . '?action=admin;area=smileys;sa=editsets',
466
			'token' => 'admin-mss',
467
		),
468
		'additional_rows' => array(
469
			array(
470
				'position' => 'above_table_headers',
471
				'value' => '<input type="hidden" name="smiley_save"><input type="submit" name="delete" value="' . $txt['smiley_sets_delete'] . '" data-confirm="' . $txt['smiley_sets_confirm'] . '" class="button_submit you_sure"> <a class="button_link" href="' . $scripturl . '?action=admin;area=smileys;sa=modifyset' . '">' . $txt['smiley_sets_add'] . '</a> ',
472
			),
473
			array(
474
				'position' => 'below_table_data',
475
				'value' => '<input type="hidden" name="smiley_save"><input type="submit" name="delete" value="' . $txt['smiley_sets_delete'] . '" data-confirm="' . $txt['smiley_sets_confirm'] . '" class="button_submit you_sure"> <a class="button_link" href="' . $scripturl . '?action=admin;area=smileys;sa=modifyset' . '">' . $txt['smiley_sets_add'] . '</a> ',
476
			),
477
		),
478
	);
479
480
	require_once($sourcedir . '/Subs-List.php');
481
	createList($listOptions);
482
}
483
484
/**
485
 * Callback function for createList().
486
 * @todo to be moved to Subs-Smileys?
487
 *
488
 * @param int $start The item to start with (not used here)
489
 * @param int $items_per_page The number of items to show per page (not used here)
490
 * @param string $sort A string indicating how to sort the results
491
 * @return array An array of info about the smiley sets
492
 */
493
function list_getSmileySets($start, $items_per_page, $sort)
494
{
495
	global $modSettings;
496
497
	$known_sets = explode(',', $modSettings['smiley_sets_known']);
498
	$set_names = explode("\n", $modSettings['smiley_sets_names']);
499
	$cols = array(
500
		'id' => array(),
501
		'selected' => array(),
502
		'path' => array(),
503
		'name' => array(),
504
	);
505
	foreach ($known_sets as $i => $set)
506
	{
507
		$cols['id'][] = $i;
508
		$cols['selected'][] = $i;
509
		$cols['path'][] = $set;
510
		$cols['name'][] = $set_names[$i];
511
	}
512
	$sort_flag = strpos($sort, 'DESC') === false ? SORT_ASC : SORT_DESC;
513
	if (substr($sort, 0, 4) === 'name')
514
		array_multisort($cols['name'], $sort_flag, SORT_REGULAR, $cols['path'], $cols['selected'], $cols['id']);
515
	elseif (substr($sort, 0, 4) === 'path')
516
		array_multisort($cols['path'], $sort_flag, SORT_REGULAR, $cols['name'], $cols['selected'], $cols['id']);
517
	else
518
		array_multisort($cols['selected'], $sort_flag, SORT_REGULAR, $cols['path'], $cols['name'], $cols['id']);
519
520
	$smiley_sets = array();
521 View Code Duplication
	foreach ($cols['id'] as $i => $id)
522
		$smiley_sets[] = array(
523
			'id' => $id,
524
			'path' => $cols['path'][$i],
525
			'name' => $cols['name'][$i],
526
			'selected' => $cols['path'][$i] == $modSettings['smiley_sets_default']
527
		);
528
529
	return $smiley_sets;
530
}
531
532
/**
533
 * Callback function for createList().
534
 * @todo to be moved to Subs-Smileys?
535
 * @return int The total number of known smiley sets
536
 */
537
function list_getNumSmileySets()
538
{
539
	global $modSettings;
540
541
	return count(explode(',', $modSettings['smiley_sets_known']));
542
}
543
544
/**
545
 * Add a smiley, that's right.
546
 */
547
function AddSmiley()
548
{
549
	global $modSettings, $context, $txt, $boarddir, $smcFunc;
550
551
	// Get a list of all known smiley sets.
552
	$context['smileys_dir'] = empty($modSettings['smileys_dir']) ? $boarddir . '/Smileys' : $modSettings['smileys_dir'];
553
	$context['smileys_dir_found'] = is_dir($context['smileys_dir']);
554
	$context['smiley_sets'] = explode(',', $modSettings['smiley_sets_known']);
555
	$set_names = explode("\n", $modSettings['smiley_sets_names']);
556 View Code Duplication
	foreach ($context['smiley_sets'] as $i => $set)
557
		$context['smiley_sets'][$i] = array(
558
			'id' => $i,
559
			'path' => $smcFunc['htmlspecialchars']($set),
560
			'name' => $smcFunc['htmlspecialchars']($set_names[$i]),
561
			'selected' => $set == $modSettings['smiley_sets_default']
562
		);
563
564
	// Submitting a form?
565
	if (isset($_POST[$context['session_var']], $_POST['smiley_code']))
566
	{
567
		checkSession();
568
569
		// Some useful arrays... types we allow - and ports we don't!
570
		$allowedTypes = array('jpeg', 'jpg', 'gif', 'png', 'bmp');
571
		$disabledFiles = array('con', 'com1', 'com2', 'com3', 'com4', 'prn', 'aux', 'lpt1', '.htaccess', 'index.php');
572
573
		$_POST['smiley_code'] = htmltrim__recursive($_POST['smiley_code']);
574
		$_POST['smiley_location'] = empty($_POST['smiley_location']) || $_POST['smiley_location'] > 2 || $_POST['smiley_location'] < 0 ? 0 : (int) $_POST['smiley_location'];
575
		$_POST['smiley_filename'] = htmltrim__recursive($_POST['smiley_filename']);
576
577
		// Make sure some code was entered.
578
		if (empty($_POST['smiley_code']))
579
			fatal_lang_error('smiley_has_no_code');
580
581
		// Check whether the new code has duplicates. It should be unique.
582
		$request = $smcFunc['db_query']('', '
583
			SELECT id_smiley
584
			FROM {db_prefix}smileys
585
			WHERE code = {raw:mysql_binary_statement} {string:smiley_code}',
586
			array(
587
				'mysql_binary_statement' => $smcFunc['db_title'] == 'MySQL' ? 'BINARY' : '',
588
				'smiley_code' => $_POST['smiley_code'],
589
			)
590
		);
591
		if ($smcFunc['db_num_rows']($request) > 0)
592
			fatal_lang_error('smiley_not_unique');
593
		$smcFunc['db_free_result']($request);
594
595
		// If we are uploading - check all the smiley sets are writable!
596
		if ($_POST['method'] != 'existing')
597
		{
598
			$writeErrors = array();
599
			foreach ($context['smiley_sets'] as $set)
600
			{
601
				if (!is_writable($context['smileys_dir'] . '/' . un_htmlspecialchars($set['path'])))
602
					$writeErrors[] = $set['path'];
603
			}
604
			if (!empty($writeErrors))
605
				fatal_lang_error('smileys_upload_error_notwritable', true, array(implode(', ', $writeErrors)));
606
		}
607
608
		// Uploading just one smiley for all of them?
609
		if (isset($_POST['sameall']) && isset($_FILES['uploadSmiley']['name']) && $_FILES['uploadSmiley']['name'] != '')
610
		{
611 View Code Duplication
			if (!is_uploaded_file($_FILES['uploadSmiley']['tmp_name']) || (ini_get('open_basedir') == '' && !file_exists($_FILES['uploadSmiley']['tmp_name'])))
612
				fatal_lang_error('smileys_upload_error');
613
614
			// Sorry, no spaces, dots, or anything else but letters allowed.
615
			$_FILES['uploadSmiley']['name'] = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $_FILES['uploadSmiley']['name']);
616
617
			// We only allow image files - it's THAT simple - no messing around here...
618 View Code Duplication
			if (!in_array(strtolower(substr(strrchr($_FILES['uploadSmiley']['name'], '.'), 1)), $allowedTypes))
619
				fatal_lang_error('smileys_upload_error_types', false, array(implode(', ', $allowedTypes)));
620
621
			// We only need the filename...
622
			$destName = basename($_FILES['uploadSmiley']['name']);
623
624
			// Make sure they aren't trying to upload a nasty file - for their own good here!
625
			if (in_array(strtolower($destName), $disabledFiles))
626
				fatal_lang_error('smileys_upload_error_illegal');
627
628
			// Check if the file already exists... and if not move it to EVERY smiley set directory.
629
			$i = 0;
630
			// Keep going until we find a set the file doesn't exist in. (or maybe it exists in all of them?)
631
			while (isset($context['smiley_sets'][$i]) && file_exists($context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName))
632
				$i++;
633
634
			// Okay, we're going to put the smiley right here, since it's not there yet!
635
			if (isset($context['smiley_sets'][$i]['path']))
636
			{
637
				$smileyLocation = $context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName;
638
				move_uploaded_file($_FILES['uploadSmiley']['tmp_name'], $smileyLocation);
639
				smf_chmod($smileyLocation, 0644);
640
641
				// Now, we want to move it from there to all the other sets.
642
				for ($n = count($context['smiley_sets']); $i < $n; $i++)
643
				{
644
					$currentPath = $context['smileys_dir'] . '/' . un_htmlspecialchars($context['smiley_sets'][$i]['path']) . '/' . $destName;
645
646
					// The file is already there!  Don't overwrite it!
647
					if (file_exists($currentPath))
648
						continue;
649
650
					// Okay, so copy the first one we made to here.
651
					copy($smileyLocation, $currentPath);
652
					smf_chmod($currentPath, 0644);
653
				}
654
			}
655
656
			// Finally make sure it's saved correctly!
657
			$_POST['smiley_filename'] = $destName;
658
		}
659
		// What about uploading several files?
660
		elseif ($_POST['method'] != 'existing')
661
		{
662
			$newName = '';
663
			foreach ($_FILES as $name => $data)
664
			{
665
				if ($_FILES[$name]['name'] == '')
666
					fatal_lang_error('smileys_upload_error_blank');
667
668
				if (empty($newName))
669
					$newName = basename($_FILES[$name]['name']);
670
				elseif (basename($_FILES[$name]['name']) != $newName)
671
					fatal_lang_error('smileys_upload_error_name');
672
			}
673
674
			foreach ($context['smiley_sets'] as $i => $set)
675
			{
676
				$set['name'] = un_htmlspecialchars($set['name']);
677
				$set['path'] = un_htmlspecialchars($set['path']);
678
679
				if (!isset($_FILES['individual_' . $set['name']]['name']) || $_FILES['individual_' . $set['name']]['name'] == '')
680
					continue;
681
682
				// Got one...
683
				if (!is_uploaded_file($_FILES['individual_' . $set['name']]['tmp_name']) || (ini_get('open_basedir') == '' && !file_exists($_FILES['individual_' . $set['name']]['tmp_name'])))
684
					fatal_lang_error('smileys_upload_error');
685
686
				// Sorry, no spaces, dots, or anything else but letters allowed.
687
				$_FILES['individual_' . $set['name']]['name'] = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $_FILES['individual_' . $set['name']]['name']);
688
689
				// We only allow image files - it's THAT simple - no messing around here...
690 View Code Duplication
				if (!in_array(strtolower(substr(strrchr($_FILES['individual_' . $set['name']]['name'], '.'), 1)), $allowedTypes))
691
					fatal_lang_error('smileys_upload_error_types', false, array(implode(', ', $allowedTypes)));
692
693
				// We only need the filename...
694
				$destName = basename($_FILES['individual_' . $set['name']]['name']);
695
696
				// Make sure they aren't trying to upload a nasty file - for their own good here!
697
				if (in_array(strtolower($destName), $disabledFiles))
698
					fatal_lang_error('smileys_upload_error_illegal');
699
700
				// If the file exists - ignore it.
701
				$smileyLocation = $context['smileys_dir'] . '/' . $set['path'] . '/' . $destName;
702
				if (file_exists($smileyLocation))
703
					continue;
704
705
				// Finally - move the image!
706
				move_uploaded_file($_FILES['individual_' . $set['name']]['tmp_name'], $smileyLocation);
707
				smf_chmod($smileyLocation, 0644);
708
709
				// Should always be saved correctly!
710
				$_POST['smiley_filename'] = $destName;
711
			}
712
		}
713
714
		// Also make sure a filename was given.
715
		if (empty($_POST['smiley_filename']))
716
			fatal_lang_error('smiley_has_no_filename');
717
718
		// Find the position on the right.
719
		$smiley_order = '0';
720
		if ($_POST['smiley_location'] != 1)
721
		{
722
			$request = $smcFunc['db_query']('', '
723
				SELECT MAX(smiley_order) + 1
724
				FROM {db_prefix}smileys
725
				WHERE hidden = {int:smiley_location}
726
					AND smiley_row = {int:first_row}',
727
				array(
728
					'smiley_location' => $_POST['smiley_location'],
729
					'first_row' => 0,
730
				)
731
			);
732
			list ($smiley_order) = $smcFunc['db_fetch_row']($request);
733
			$smcFunc['db_free_result']($request);
734
735
			if (empty($smiley_order))
736
				$smiley_order = '0';
737
		}
738
		$smcFunc['db_insert']('',
739
			'{db_prefix}smileys',
740
			array(
741
				'code' => 'string-30', 'filename' => 'string-48', 'description' => 'string-80', 'hidden' => 'int', 'smiley_order' => 'int',
742
			),
743
			array(
744
				$_POST['smiley_code'], $_POST['smiley_filename'], $_POST['smiley_description'], $_POST['smiley_location'], $smiley_order,
745
			),
746
			array('id_smiley')
747
		);
748
749
		cache_put_data('parsing_smileys', null, 480);
750
		cache_put_data('posting_smileys', null, 480);
751
752
		// No errors? Out of here!
753
		redirectexit('action=admin;area=smileys;sa=editsmileys');
754
	}
755
756
	$context['selected_set'] = $modSettings['smiley_sets_default'];
757
758
	// Get all possible filenames for the smileys.
759
	$context['filenames'] = array();
760 View Code Duplication
	if ($context['smileys_dir_found'])
761
	{
762
		foreach ($context['smiley_sets'] as $smiley_set)
763
		{
764
			if (!file_exists($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path'])))
765
				continue;
766
767
			$dir = dir($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path']));
768
			while ($entry = $dir->read())
769
			{
770
				if (!in_array($entry, $context['filenames']) && in_array(strrchr($entry, '.'), array('.jpg', '.gif', '.jpeg', '.png')))
771
					$context['filenames'][strtolower($entry)] = array(
772
						'id' => $smcFunc['htmlspecialchars']($entry),
773
						'selected' => false,
774
					);
775
			}
776
			$dir->close();
777
		}
778
		ksort($context['filenames']);
779
	}
780
781
	// Create a new smiley from scratch.
782
	$context['filenames'] = array_values($context['filenames']);
783
	$context['current_smiley'] = array(
784
		'id' => 0,
785
		'code' => '',
786
		'filename' => $context['filenames'][0]['id'],
787
		'description' => $txt['smileys_default_description'],
788
		'location' => 0,
789
		'is_new' => true,
790
	);
791
}
792
793
/**
794
 * Add, remove, edit smileys.
795
 */
796
function EditSmileys()
797
{
798
	global $modSettings, $context, $txt, $boarddir;
799
	global $smcFunc, $scripturl, $sourcedir;
800
801
	// Force the correct tab to be displayed.
802
	$context[$context['admin_menu_name']]['current_subsection'] = 'editsmileys';
803
804
	// Submitting a form?
805
	if (isset($_POST['smiley_save']) || isset($_POST['smiley_action']))
806
	{
807
		checkSession();
808
809
		// Changing the selected smileys?
810
		if (isset($_POST['smiley_action']) && !empty($_POST['checked_smileys']))
811
		{
812
			foreach ($_POST['checked_smileys'] as $id => $smiley_id)
813
				$_POST['checked_smileys'][$id] = (int) $smiley_id;
814
815
			if ($_POST['smiley_action'] == 'delete')
816
				$smcFunc['db_query']('', '
817
					DELETE FROM {db_prefix}smileys
818
					WHERE id_smiley IN ({array_int:checked_smileys})',
819
					array(
820
						'checked_smileys' => $_POST['checked_smileys'],
821
					)
822
				);
823
			// Changing the status of the smiley?
824
			else
825
			{
826
				// Check it's a valid type.
827
				$displayTypes = array(
828
					'post' => 0,
829
					'hidden' => 1,
830
					'popup' => 2
831
				);
832
				if (isset($displayTypes[$_POST['smiley_action']]))
833
					$smcFunc['db_query']('', '
834
						UPDATE {db_prefix}smileys
835
						SET hidden = {int:display_type}
836
						WHERE id_smiley IN ({array_int:checked_smileys})',
837
						array(
838
							'checked_smileys' => $_POST['checked_smileys'],
839
							'display_type' => $displayTypes[$_POST['smiley_action']],
840
						)
841
					);
842
			}
843
		}
844
		// Create/modify a smiley.
845
		elseif (isset($_POST['smiley']))
846
		{
847
			// Is it a delete?
848
			if (!empty($_POST['deletesmiley']))
849
			{
850
				$smcFunc['db_query']('', '
851
					DELETE FROM {db_prefix}smileys
852
					WHERE id_smiley = {int:current_smiley}',
853
					array(
854
						'current_smiley' => $_POST['smiley'],
855
					)
856
				);
857
			}
858
			// Otherwise an edit.
859
			else
860
			{
861
				$_POST['smiley'] = (int) $_POST['smiley'];
862
				$_POST['smiley_code'] = htmltrim__recursive($_POST['smiley_code']);
863
				$_POST['smiley_filename'] = htmltrim__recursive($_POST['smiley_filename']);
864
				$_POST['smiley_location'] = empty($_POST['smiley_location']) || $_POST['smiley_location'] > 2 || $_POST['smiley_location'] < 0 ? 0 : (int) $_POST['smiley_location'];
865
866
				// Make sure some code was entered.
867
				if (empty($_POST['smiley_code']))
868
					fatal_lang_error('smiley_has_no_code');
869
870
				// Also make sure a filename was given.
871
				if (empty($_POST['smiley_filename']))
872
					fatal_lang_error('smiley_has_no_filename');
873
874
				// Check whether the new code has duplicates. It should be unique.
875
				$request = $smcFunc['db_query']('', '
876
					SELECT id_smiley
877
					FROM {db_prefix}smileys
878
					WHERE code = {raw:mysql_binary_type} {string:smiley_code}' . (empty($_POST['smiley']) ? '' : '
879
						AND id_smiley != {int:current_smiley}'),
880
					array(
881
						'current_smiley' => $_POST['smiley'],
882
						'mysql_binary_type' => $smcFunc['db_title'] == 'MySQL' ? 'BINARY' : '',
883
						'smiley_code' => $_POST['smiley_code'],
884
					)
885
				);
886
				if ($smcFunc['db_num_rows']($request) > 0)
887
					fatal_lang_error('smiley_not_unique');
888
				$smcFunc['db_free_result']($request);
889
890
				$smcFunc['db_query']('', '
891
					UPDATE {db_prefix}smileys
892
					SET
893
						code = {string:smiley_code},
894
						filename = {string:smiley_filename},
895
						description = {string:smiley_description},
896
						hidden = {int:smiley_location}
897
					WHERE id_smiley = {int:current_smiley}',
898
					array(
899
						'smiley_location' => $_POST['smiley_location'],
900
						'current_smiley' => $_POST['smiley'],
901
						'smiley_code' => $_POST['smiley_code'],
902
						'smiley_filename' => $_POST['smiley_filename'],
903
						'smiley_description' => $_POST['smiley_description'],
904
					)
905
				);
906
			}
907
		}
908
909
		cache_put_data('parsing_smileys', null, 480);
910
		cache_put_data('posting_smileys', null, 480);
911
	}
912
913
	// Load all known smiley sets.
914
	$context['smiley_sets'] = explode(',', $modSettings['smiley_sets_known']);
915
	$set_names = explode("\n", $modSettings['smiley_sets_names']);
916 View Code Duplication
	foreach ($context['smiley_sets'] as $i => $set)
917
		$context['smiley_sets'][$i] = array(
918
			'id' => $i,
919
			'path' => $smcFunc['htmlspecialchars']($set),
920
			'name' => $smcFunc['htmlspecialchars']($set_names[$i]),
921
			'selected' => $set == $modSettings['smiley_sets_default']
922
		);
923
924
	// Prepare overview of all (custom) smileys.
925
	if ($context['sub_action'] == 'editsmileys')
926
	{
927
		// Determine the language specific sort order of smiley locations.
928
		$smiley_locations = array(
929
			$txt['smileys_location_form'],
930
			$txt['smileys_location_hidden'],
931
			$txt['smileys_location_popup'],
932
		);
933
		asort($smiley_locations);
934
935
		// Create a list of options for selecting smiley sets.
936
		$smileyset_option_list = '
937
			<select name="set" onchange="changeSet(this.options[this.selectedIndex].value);">';
938
		foreach ($context['smiley_sets'] as $smiley_set)
939
			$smileyset_option_list .= '
940
				<option value="' . $smiley_set['path'] . '"' . ($modSettings['smiley_sets_default'] == $smiley_set['path'] ? ' selected' : '') . '>' . $smiley_set['name'] . '</option>';
941
		$smileyset_option_list .= '
942
			</select>';
943
944
		$listOptions = array(
945
			'id' => 'smiley_list',
946
			'title' => $txt['smileys_edit'],
947
			'items_per_page' => 40,
948
			'base_href' => $scripturl . '?action=admin;area=smileys;sa=editsmileys',
949
			'default_sort_col' => 'filename',
950
			'get_items' => array(
951
				'function' => 'list_getSmileys',
952
			),
953
			'get_count' => array(
954
				'function' => 'list_getNumSmileys',
955
			),
956
			'no_items_label' => $txt['smileys_no_entries'],
957
			'columns' => array(
958
				'picture' => array(
959
					'data' => array(
960
						'sprintf' => array(
961
							'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" style="padding: 2px;" id="smiley%1$d"><input type="hidden" name="smileys[%1$d][filename]" value="%2$s"></a>',
962
							'params' => array(
963
								'id_smiley' => false,
964
								'filename' => true,
965
								'description' => true,
966
							),
967
						),
968
						'class' => 'centercol',
969
					),
970
				),
971
				'code' => array(
972
					'header' => array(
973
						'value' => $txt['smileys_code'],
974
					),
975
					'data' => array(
976
						'db_htmlsafe' => 'code',
977
					),
978
					'sort' => array(
979
						'default' => 'code',
980
						'reverse' => 'code DESC',
981
					),
982
				),
983
				'filename' => array(
984
					'header' => array(
985
						'value' => $txt['smileys_filename'],
986
					),
987
					'data' => array(
988
						'db_htmlsafe' => 'filename',
989
					),
990
					'sort' => array(
991
						'default' => 'filename',
992
						'reverse' => 'filename DESC',
993
					),
994
				),
995
				'location' => array(
996
					'header' => array(
997
						'value' => $txt['smileys_location'],
998
					),
999
					'data' => array(
1000
						'function' => function ($rowData) use ($txt)
1001
						{
1002
							if (empty($rowData['hidden']))
1003
								return $txt['smileys_location_form'];
1004
							elseif ($rowData['hidden'] == 1)
1005
								return $txt['smileys_location_hidden'];
1006
							else
1007
								return $txt['smileys_location_popup'];
1008
						},
1009
					),
1010
					'sort' => array(
1011
						'default' => 'FIND_IN_SET(hidden, \'' . implode(',', array_keys($smiley_locations)) . '\')',
1012
						'reverse' => 'FIND_IN_SET(hidden, \'' . implode(',', array_keys($smiley_locations)) . '\') DESC',
1013
					),
1014
				),
1015
				'tooltip' => array(
1016
					'header' => array(
1017
						'value' => $txt['smileys_description'],
1018
					),
1019
					'data' => array(
1020
						'function' => function ($rowData) use ($context, $txt, $modSettings, $smcFunc)
1021
						{
1022
							if (empty($modSettings['smileys_dir']) || !is_dir($modSettings['smileys_dir']))
1023
								return $smcFunc['htmlspecialchars']($rowData['description']);
1024
1025
							// Check if there are smileys missing in some sets.
1026
							$missing_sets = array();
1027
							foreach ($context['smiley_sets'] as $smiley_set)
1028
								if (!file_exists(sprintf('%1$s/%2$s/%3$s', $modSettings['smileys_dir'], $smiley_set['path'], $rowData['filename'])))
1029
									$missing_sets[] = $smiley_set['path'];
1030
1031
							$description = $smcFunc['htmlspecialchars']($rowData['description']);
1032
1033
							if (!empty($missing_sets))
1034
								$description .= sprintf('<br><span class="smalltext"><strong>%1$s:</strong> %2$s</span>', $txt['smileys_not_found_in_set'], implode(', ', $missing_sets));
1035
1036
							return $description;
1037
						},
1038
					),
1039
					'sort' => array(
1040
						'default' => 'description',
1041
						'reverse' => 'description DESC',
1042
					),
1043
				),
1044
				'modify' => array(
1045
					'header' => array(
1046
						'value' => $txt['smileys_modify'],
1047
						'class' => 'centercol',
1048
					),
1049
					'data' => array(
1050
						'sprintf' => array(
1051
							'format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=modifysmiley;smiley=%1$d">' . $txt['smileys_modify'] . '</a>',
1052
							'params' => array(
1053
								'id_smiley' => false,
1054
							),
1055
						),
1056
						'class' => 'centercol',
1057
					),
1058
				),
1059
				'check' => array(
1060
					'header' => array(
1061
						'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check">',
1062
						'class' => 'centercol',
1063
					),
1064
					'data' => array(
1065
						'sprintf' => array(
1066
							'format' => '<input type="checkbox" name="checked_smileys[]" value="%1$d" class="input_check">',
1067
							'params' => array(
1068
								'id_smiley' => false,
1069
							),
1070
						),
1071
						'class' => 'centercol',
1072
					),
1073
				),
1074
			),
1075
			'form' => array(
1076
				'href' => $scripturl . '?action=admin;area=smileys;sa=editsmileys',
1077
				'name' => 'smileyForm',
1078
			),
1079
			'additional_rows' => array(
1080
				array(
1081
					'position' => 'above_column_headers',
1082
					'value' => $smileyset_option_list,
1083
					'class' => 'righttext',
1084
				),
1085
				array(
1086
					'position' => 'below_table_data',
1087
					'value' => '
1088
						<select name="smiley_action" onchange="makeChanges(this.value);">
1089
							<option value="-1">' . $txt['smileys_with_selected'] . ':</option>
1090
							<option value="-1" disabled>--------------</option>
1091
							<option value="hidden">' . $txt['smileys_make_hidden'] . '</option>
1092
							<option value="post">' . $txt['smileys_show_on_post'] . '</option>
1093
							<option value="popup">' . $txt['smileys_show_on_popup'] . '</option>
1094
							<option value="delete">' . $txt['smileys_remove'] . '</option>
1095
						</select>
1096
						<noscript>
1097
							<input type="submit" name="perform_action" value="' . $txt['go'] . '" class="button_submit">
1098
						</noscript>',
1099
					'class' => 'righttext',
1100
				),
1101
			),
1102
			'javascript' => '
1103
				function makeChanges(action)
1104
				{
1105
					if (action == \'-1\')
1106
						return false;
1107
					else if (action == \'delete\')
1108
					{
1109
						if (confirm(\'' . $txt['smileys_confirm'] . '\'))
1110
							document.forms.smileyForm.submit();
1111
					}
1112
					else
1113
						document.forms.smileyForm.submit();
1114
					return true;
1115
				}
1116
				function changeSet(newSet)
1117
				{
1118
					var currentImage, i, knownSmileys = [];
1119
1120
					if (knownSmileys.length == 0)
1121
					{
1122
						for (var i = 0, n = document.images.length; i < n; i++)
1123
							if (document.images[i].id.substr(0, 6) == \'smiley\')
1124
								knownSmileys[knownSmileys.length] = document.images[i].id.substr(6);
1125
					}
1126
1127
					for (i = 0; i < knownSmileys.length; i++)
1128
					{
1129
						currentImage = document.getElementById("smiley" + knownSmileys[i]);
1130
						currentImage.src = "' . $modSettings['smileys_url'] . '/" + newSet + "/" + document.forms.smileyForm["smileys[" + knownSmileys[i] + "][filename]"].value;
1131
					}
1132
				}',
1133
		);
1134
1135
		require_once($sourcedir . '/Subs-List.php');
1136
		createList($listOptions);
1137
1138
		// The list is the only thing to show, so make it the main template.
1139
		$context['default_list'] = 'smiley_list';
1140
		$context['sub_template'] = 'show_list';
1141
	}
1142
	// Modifying smileys.
1143
	elseif ($context['sub_action'] == 'modifysmiley')
1144
	{
1145
		// Get a list of all known smiley sets.
1146
		$context['smileys_dir'] = empty($modSettings['smileys_dir']) ? $boarddir . '/Smileys' : $modSettings['smileys_dir'];
1147
		$context['smileys_dir_found'] = is_dir($context['smileys_dir']);
1148
		$context['smiley_sets'] = explode(',', $modSettings['smiley_sets_known']);
1149
		$set_names = explode("\n", $modSettings['smiley_sets_names']);
1150 View Code Duplication
		foreach ($context['smiley_sets'] as $i => $set)
1151
			$context['smiley_sets'][$i] = array(
1152
				'id' => $i,
1153
				'path' => $smcFunc['htmlspecialchars']($set),
1154
				'name' => $smcFunc['htmlspecialchars']($set_names[$i]),
1155
				'selected' => $set == $modSettings['smiley_sets_default']
1156
			);
1157
1158
		$context['selected_set'] = $modSettings['smiley_sets_default'];
1159
1160
		// Get all possible filenames for the smileys.
1161
		$context['filenames'] = array();
1162 View Code Duplication
		if ($context['smileys_dir_found'])
1163
		{
1164
			foreach ($context['smiley_sets'] as $smiley_set)
1165
			{
1166
				if (!file_exists($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path'])))
1167
					continue;
1168
1169
				$dir = dir($context['smileys_dir'] . '/' . un_htmlspecialchars($smiley_set['path']));
1170
				while ($entry = $dir->read())
1171
				{
1172
					if (!in_array($entry, $context['filenames']) && in_array(strrchr($entry, '.'), array('.jpg', '.gif', '.jpeg', '.png')))
1173
						$context['filenames'][strtolower($entry)] = array(
1174
							'id' => $smcFunc['htmlspecialchars']($entry),
1175
							'selected' => false,
1176
						);
1177
				}
1178
				$dir->close();
1179
			}
1180
			ksort($context['filenames']);
1181
		}
1182
1183
		$request = $smcFunc['db_query']('', '
1184
			SELECT id_smiley AS id, code, filename, description, hidden AS location, 0 AS is_new
1185
			FROM {db_prefix}smileys
1186
			WHERE id_smiley = {int:current_smiley}',
1187
			array(
1188
				'current_smiley' => (int) $_REQUEST['smiley'],
1189
			)
1190
		);
1191
		if ($smcFunc['db_num_rows']($request) != 1)
1192
			fatal_lang_error('smiley_not_found');
1193
		$context['current_smiley'] = $smcFunc['db_fetch_assoc']($request);
1194
		$smcFunc['db_free_result']($request);
1195
1196
		$context['current_smiley']['code'] = $smcFunc['htmlspecialchars']($context['current_smiley']['code']);
1197
		$context['current_smiley']['filename'] = $smcFunc['htmlspecialchars']($context['current_smiley']['filename']);
1198
		$context['current_smiley']['description'] = $smcFunc['htmlspecialchars']($context['current_smiley']['description']);
1199
1200
		if (isset($context['filenames'][strtolower($context['current_smiley']['filename'])]))
1201
			$context['filenames'][strtolower($context['current_smiley']['filename'])]['selected'] = true;
1202
	}
1203
}
1204
1205
/**
1206
 * Callback function for createList().
1207
 *
1208
 * @param int $start The item to start with (not used here)
1209
 * @param int $items_per_page The number of items to show per page (not used here)
1210
 * @param string $sort A string indicating how to sort the results
1211
 * @return array An array of info about the smileys
1212
 */
1213 View Code Duplication
function list_getSmileys($start, $items_per_page, $sort)
1214
{
1215
	global $smcFunc;
1216
1217
	$request = $smcFunc['db_query']('', '
1218
		SELECT id_smiley, code, filename, description, smiley_row, smiley_order, hidden
1219
		FROM {db_prefix}smileys
1220
		ORDER BY {raw:sort}',
1221
		array(
1222
			'sort' => $sort,
1223
		)
1224
	);
1225
	$smileys = array();
1226
	while ($row = $smcFunc['db_fetch_assoc']($request))
1227
		$smileys[] = $row;
1228
	$smcFunc['db_free_result']($request);
1229
1230
	return $smileys;
1231
}
1232
1233
/**
1234
 * Callback function for createList().
1235
 * @return int The number of smileys
1236
 */
1237
function list_getNumSmileys()
1238
{
1239
	global $smcFunc;
1240
1241
	$request = $smcFunc['db_query']('', '
1242
		SELECT COUNT(*)
1243
		FROM {db_prefix}smileys',
1244
		array()
1245
	);
1246
	list($numSmileys) = $smcFunc['db_fetch_row'];
1247
	$smcFunc['db_free_result']($request);
1248
1249
	return $numSmileys;
1250
}
1251
1252
/**
1253
 * Allows to edit smileys order.
1254
 */
1255
function EditSmileyOrder()
1256
{
1257
	global $context, $txt, $smcFunc;
1258
1259
	// Move smileys to another position.
1260
	if (isset($_REQUEST['reorder']))
1261
	{
1262
		checkSession('get');
1263
1264
		$_GET['location'] = empty($_GET['location']) || $_GET['location'] != 'popup' ? 0 : 2;
1265
		$_GET['source'] = empty($_GET['source']) ? 0 : (int) $_GET['source'];
1266
1267
		if (empty($_GET['source']))
1268
			fatal_lang_error('smiley_not_found');
1269
1270
		if (!empty($_GET['after']))
1271
		{
1272
			$_GET['after'] = (int) $_GET['after'];
1273
1274
			$request = $smcFunc['db_query']('', '
1275
				SELECT smiley_row, smiley_order, hidden
1276
				FROM {db_prefix}smileys
1277
				WHERE hidden = {int:location}
1278
					AND id_smiley = {int:after_smiley}',
1279
				array(
1280
					'location' => $_GET['location'],
1281
					'after_smiley' => $_GET['after'],
1282
				)
1283
			);
1284
			if ($smcFunc['db_num_rows']($request) != 1)
1285
				fatal_lang_error('smiley_not_found');
1286
			list ($smiley_row, $smiley_order, $smileyLocation) = $smcFunc['db_fetch_row']($request);
1287
			$smcFunc['db_free_result']($request);
1288
		}
1289
		else
1290
		{
1291
			$smiley_row = (int) $_GET['row'];
1292
			$smiley_order = -1;
1293
			$smileyLocation = (int) $_GET['location'];
1294
		}
1295
1296
		$smcFunc['db_query']('', '
1297
			UPDATE {db_prefix}smileys
1298
			SET smiley_order = smiley_order + 1
1299
			WHERE hidden = {int:new_location}
1300
				AND smiley_row = {int:smiley_row}
1301
				AND smiley_order > {int:smiley_order}',
1302
			array(
1303
				'new_location' => $_GET['location'],
1304
				'smiley_row' => $smiley_row,
1305
				'smiley_order' => $smiley_order,
1306
			)
1307
		);
1308
1309
		$smcFunc['db_query']('', '
1310
			UPDATE {db_prefix}smileys
1311
			SET
1312
				smiley_order = {int:smiley_order} + 1,
1313
				smiley_row = {int:smiley_row},
1314
				hidden = {int:new_location}
1315
			WHERE id_smiley = {int:current_smiley}',
1316
			array(
1317
				'smiley_order' => $smiley_order,
1318
				'smiley_row' => $smiley_row,
1319
				'new_location' => $smileyLocation,
1320
				'current_smiley' => $_GET['source'],
1321
			)
1322
		);
1323
1324
		cache_put_data('parsing_smileys', null, 480);
1325
		cache_put_data('posting_smileys', null, 480);
1326
	}
1327
1328
	$request = $smcFunc['db_query']('', '
1329
		SELECT id_smiley, code, filename, description, smiley_row, smiley_order, hidden
1330
		FROM {db_prefix}smileys
1331
		WHERE hidden != {int:popup}
1332
		ORDER BY smiley_order, smiley_row',
1333
		array(
1334
			'popup' => 1,
1335
		)
1336
	);
1337
	$context['smileys'] = array(
1338
		'postform' => array(
1339
			'rows' => array(),
1340
		),
1341
		'popup' => array(
1342
			'rows' => array(),
1343
		),
1344
	);
1345
	while ($row = $smcFunc['db_fetch_assoc']($request))
1346
	{
1347
		$location = empty($row['hidden']) ? 'postform' : 'popup';
1348
		$context['smileys'][$location]['rows'][$row['smiley_row']][] = array(
1349
			'id' => $row['id_smiley'],
1350
			'code' => $smcFunc['htmlspecialchars']($row['code']),
1351
			'filename' => $smcFunc['htmlspecialchars']($row['filename']),
1352
			'description' => $smcFunc['htmlspecialchars']($row['description']),
1353
			'row' => $row['smiley_row'],
1354
			'order' => $row['smiley_order'],
1355
			'selected' => !empty($_REQUEST['move']) && $_REQUEST['move'] == $row['id_smiley'],
1356
		);
1357
	}
1358
	$smcFunc['db_free_result']($request);
1359
1360
	$context['move_smiley'] = empty($_REQUEST['move']) ? 0 : (int) $_REQUEST['move'];
1361
1362
	// Make sure all rows are sequential.
1363
	foreach (array_keys($context['smileys']) as $location)
1364
		$context['smileys'][$location] = array(
1365
			'id' => $location,
1366
			'title' => $location == 'postform' ? $txt['smileys_location_form'] : $txt['smileys_location_popup'],
1367
			'description' => $location == 'postform' ? $txt['smileys_location_form_description'] : $txt['smileys_location_popup_description'],
1368
			'last_row' => count($context['smileys'][$location]['rows']),
1369
			'rows' => array_values($context['smileys'][$location]['rows']),
1370
		);
1371
1372
	// Check & fix smileys that are not ordered properly in the database.
1373
	foreach (array_keys($context['smileys']) as $location)
1374
	{
1375
		foreach ($context['smileys'][$location]['rows'] as $id => $smiley_row)
1376
		{
1377
			// Fix empty rows if any.
1378
			if ($id != $smiley_row[0]['row'])
1379
			{
1380
				$smcFunc['db_query']('', '
1381
					UPDATE {db_prefix}smileys
1382
					SET smiley_row = {int:new_row}
1383
					WHERE smiley_row = {int:current_row}
1384
						AND hidden = {int:location}',
1385
					array(
1386
						'new_row' => $id,
1387
						'current_row' => $smiley_row[0]['row'],
1388
						'location' => $location == 'postform' ? '0' : '2',
1389
					)
1390
				);
1391
				// Only change the first row value of the first smiley (we don't need the others :P).
1392
				$context['smileys'][$location]['rows'][$id][0]['row'] = $id;
1393
			}
1394
			// Make sure the smiley order is always sequential.
1395
			foreach ($smiley_row as $order_id => $smiley)
1396
				if ($order_id != $smiley['order'])
1397
					$smcFunc['db_query']('', '
1398
						UPDATE {db_prefix}smileys
1399
						SET smiley_order = {int:new_order}
1400
						WHERE id_smiley = {int:current_smiley}',
1401
						array(
1402
							'new_order' => $order_id,
1403
							'current_smiley' => $smiley['id'],
1404
						)
1405
					);
1406
		}
1407
	}
1408
1409
	cache_put_data('parsing_smileys', null, 480);
1410
	cache_put_data('posting_smileys', null, 480);
1411
}
1412
1413
/**
1414
 * Install a smiley set.
1415
 */
1416
function InstallSmileySet()
1417
{
1418
	global $sourcedir, $boarddir, $packagesdir, $modSettings, $smcFunc, $scripturl, $context, $txt, $user_info;
1419
1420
	isAllowedTo('manage_smileys');
1421
	checkSession('request');
1422
	// One of these two may be necessary
1423
	loadLanguage('Errors');
1424
	loadLanguage('Packages');
1425
1426
	require_once($sourcedir . '/Subs-Package.php');
1427
1428
	// Installing unless proven otherwise
1429
	$testing = false;
1430
1431
	if (isset($_REQUEST['set_gz']))
1432
	{
1433
		$base_name = strtr(basename($_REQUEST['set_gz']), ':/', '-_');
1434
		$name = $smcFunc['htmlspecialchars'](strtok(basename($_REQUEST['set_gz']), '.'));
1435
		$context['filename'] = $base_name;
1436
1437
		// Check that the smiley is from simplemachines.org, for now... maybe add mirroring later.
1438
		// @ TODO: Our current xml files serve http links.  Allowing both for now until we serve https.
1439
		if (preg_match('~^https?://[\w_\-]+\.simplemachines\.org/~', $_REQUEST['set_gz']) == 0 || strpos($_REQUEST['set_gz'], 'dlattach') !== false)
1440
			fatal_lang_error('not_on_simplemachines');
1441
1442
		$destination = $packagesdir . '/' . $base_name;
1443
1444
		if (file_exists($destination))
1445
			fatal_lang_error('package_upload_error_exists');
1446
1447
		// Let's copy it to the Packages directory
1448
		file_put_contents($destination, fetch_web_data($_REQUEST['set_gz']));
1449
		$testing = true;
1450
	}
1451
	elseif (isset($_REQUEST['package']))
1452
	{
1453
		$base_name = basename($_REQUEST['package']);
1454
		$name = $smcFunc['htmlspecialchars'](strtok(basename($_REQUEST['package']), '.'));
1455
		$context['filename'] = $base_name;
1456
1457
		$destination = $packagesdir . '/' . basename($_REQUEST['package']);
1458
	}
1459
1460
	if (empty($destination) || !file_exists($destination))
1461
		fatal_lang_error('package_no_file', false);
1462
1463
	// Make sure temp directory exists and is empty.
1464
	if (file_exists($packagesdir . '/temp'))
1465
		deltree($packagesdir . '/temp', false);
1466
1467
	if (!mktree($packagesdir . '/temp', 0755))
1468
	{
1469
		deltree($packagesdir . '/temp', false);
1470
		if (!mktree($packagesdir . '/temp', 0777))
1471
		{
1472
			deltree($packagesdir . '/temp', false);
1473
			// @todo not sure about url in destination_url
1474
			create_chmod_control(array($packagesdir . '/temp/delme.tmp'), array('destination_url' => $scripturl . '?action=admin;area=smileys;sa=install;set_gz=' . $_REQUEST['set_gz'], 'crash_on_error' => true));
1475
1476
			deltree($packagesdir . '/temp', false);
1477
			if (!mktree($packagesdir . '/temp', 0777))
1478
				fatal_lang_error('package_cant_download', false);
1479
		}
1480
	}
1481
1482
	$extracted = read_tgz_file($destination, $packagesdir . '/temp');
0 ignored issues
show
The variable $destination 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...
1483
	if (!$extracted)
1484
		fatal_lang_error('packageget_unable', false, array('https://custom.simplemachines.org/mods/index.php?action=search;type=12;basic_search=' . $name));
0 ignored issues
show
The variable $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...
1485
	if ($extracted && !file_exists($packagesdir . '/temp/package-info.xml'))
1486
		foreach ($extracted as $file)
1487
			if (basename($file['filename']) == 'package-info.xml')
1488
			{
1489
				$base_path = dirname($file['filename']) . '/';
1490
				break;
1491
			}
1492
1493
	if (!isset($base_path))
1494
		$base_path = '';
1495
1496
	if (!file_exists($packagesdir . '/temp/' . $base_path . 'package-info.xml'))
1497
		fatal_lang_error('package_get_error_missing_xml', false);
1498
1499
	$smileyInfo = getPackageInfo($context['filename']);
1500
	if (!is_array($smileyInfo))
1501
		fatal_lang_error($smileyInfo);
1502
1503
	// See if it is installed?
1504
	$request = $smcFunc['db_query']('', '
1505
		SELECT version, themes_installed, db_changes
1506
		FROM {db_prefix}log_packages
1507
		WHERE package_id = {string:current_package}
1508
			AND install_state != {int:not_installed}
1509
		ORDER BY time_installed DESC
1510
		LIMIT 1',
1511
		array(
1512
			'not_installed'	=> 0,
1513
			'current_package' => $smileyInfo['id'],
1514
		)
1515
	);
1516
1517
	if ($smcFunc['db_num_rows']($request) > 0)
1518
		fatal_lang_error('package_installed_warning1');
1519
1520
	// Everything is fine, now it's time to do something
1521
	$actions = parsePackageInfo($smileyInfo['xml'], true, 'install');
1522
1523
	$context['post_url'] = $scripturl . '?action=admin;area=smileys;sa=install;package=' . $base_name;
0 ignored issues
show
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...
1524
	$context['has_failure'] = false;
1525
	$context['actions'] = array();
1526
	$context['ftp_needed'] = false;
1527
1528
	foreach ($actions as $action)
1529
	{
1530
		if ($action['type'] == 'readme' || $action['type'] == 'license')
1531
		{
1532
			$type = 'package_' . $action['type'];
1533 View Code Duplication
			if (file_exists($packagesdir . '/temp/' . $base_path . $action['filename']))
1534
				$context[$type] = $smcFunc['htmlspecialchars'](trim(file_get_contents($packagesdir . '/temp/' . $base_path . $action['filename']), "\n\r"));
1535
			elseif (file_exists($action['filename']))
1536
				$context[$type] = $smcFunc['htmlspecialchars'](trim(file_get_contents($action['filename']), "\n\r"));
1537
1538
			if (!empty($action['parse_bbc']))
1539
			{
1540
				require_once($sourcedir . '/Subs-Post.php');
1541
				preparsecode($context[$type]);
1542
				$context[$type] = parse_bbc($context[$type]);
1543
			}
1544
			else
1545
				$context[$type] = nl2br($context[$type]);
1546
1547
			continue;
1548
		}
1549
		elseif ($action['type'] == 'require-dir')
1550
		{
1551
			// Do this one...
1552
			$thisAction = array(
1553
				'type' => $txt['package_extract'] . ' ' . ($action['type'] == 'require-dir' ? $txt['package_tree'] : $txt['package_file']),
1554
				'action' => $smcFunc['htmlspecialchars'](strtr($action['destination'], array($boarddir => '.')))
1555
			);
1556
1557
			$file =  $packagesdir . '/temp/' . $base_path . $action['filename'];
1558
			if (isset($action['filename']) && (!file_exists($file) || !is_writable(dirname($action['destination']))))
1559
			{
1560
				$context['has_failure'] = true;
1561
1562
				$thisAction += array(
1563
					'description' => $txt['package_action_error'],
1564
					'failed' => true,
1565
				);
1566
			}
1567
			// @todo None given?
1568 View Code Duplication
			if (empty($thisAction['description']))
1569
				$thisAction['description'] = isset($action['description']) ? $action['description'] : '';
1570
1571
			$context['actions'][] = $thisAction;
1572
		}
1573 View Code Duplication
		elseif ($action['type'] == 'credits')
1574
		{
1575
			// Time to build the billboard
1576
			$credits_tag = array(
1577
				'url' => $action['url'],
1578
				'license' => $action['license'],
1579
				'copyright' => $action['copyright'],
1580
				'title' => $action['title'],
1581
			);
1582
		}
1583
	}
1584
1585
	if ($testing)
1586
	{
1587
		$context['sub_template'] = 'view_package';
1588
		$context['uninstalling'] = false;
1589
		$context['is_installed'] = false;
1590
		$context['package_name'] = $smileyInfo['name'];
1591
		loadTemplate('Packages');
1592
	}
1593
	// Do the actual install
1594
	else
1595
	{
1596
		// @TODO Does this call have side effects? ($actions is not used)
1597
		$actions = parsePackageInfo($smileyInfo['xml'], false, 'install');
0 ignored issues
show
$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...
1598
		foreach ($context['actions'] as $action)
1599
		{
1600
			updateSettings(array(
1601
				'smiley_sets_known' => $modSettings['smiley_sets_known'] . ',' . basename($action['action']),
1602
				'smiley_sets_names' => $modSettings['smiley_sets_names'] . "\n" . $smileyInfo['name'] . (count($context['actions']) > 1 ? ' ' .  (!empty($action['description']) ? $smcFunc['htmlspecialchars']($action['description']) : basename($action['action'])) : ''),
1603
			));
1604
		}
1605
1606
		package_flush_cache();
1607
1608
		// Credits tag?
1609
		$credits_tag = (empty($credits_tag)) ? '' : $smcFunc['json_encode']($credits_tag);
1610
		$smcFunc['db_insert']('',
1611
			'{db_prefix}log_packages',
1612
			array(
1613
				'filename' => 'string', 'name' => 'string', 'package_id' => 'string', 'version' => 'string',
1614
				'id_member_installed' => 'int', 'member_installed' => 'string','time_installed' => 'int',
1615
				'install_state' => 'int', 'failed_steps' => 'string', 'themes_installed' => 'string',
1616
				'member_removed' => 'int', 'db_changes' => 'string', 'credits' => 'string',
1617
			),
1618
			array(
1619
				$smileyInfo['filename'], $smileyInfo['name'], $smileyInfo['id'], $smileyInfo['version'],
1620
				$user_info['id'], $user_info['name'], time(),
1621
				1, '', '',
1622
				0, '', $credits_tag,
1623
			),
1624
			array('id_install')
1625
		);
1626
1627
		logAction('install_package', array('package' => $smcFunc['htmlspecialchars']($smileyInfo['name']), 'version' => $smcFunc['htmlspecialchars']($smileyInfo['version'])), 'admin');
1628
1629
		cache_put_data('parsing_smileys', null, 480);
1630
		cache_put_data('posting_smileys', null, 480);
1631
	}
1632
1633
	if (file_exists($packagesdir . '/temp'))
1634
		deltree($packagesdir . '/temp');
1635
1636
	if (!$testing)
1637
		redirectexit('action=admin;area=smileys');
1638
}
1639
1640
/**
1641
 * A function to import new smileys from an existing directory into the database.
1642
 *
1643
 * @param string $smileyPath The path to the directory to import smileys from
1644
 */
1645
function ImportSmileys($smileyPath)
1646
{
1647
	global $modSettings, $smcFunc;
1648
1649
	if (empty($modSettings['smileys_dir']) || !is_dir($modSettings['smileys_dir'] . '/' . $smileyPath))
1650
		fatal_lang_error('smiley_set_unable_to_import');
1651
1652
	$smileys = array();
1653
	$dir = dir($modSettings['smileys_dir'] . '/' . $smileyPath);
1654 View Code Duplication
	while ($entry = $dir->read())
1655
	{
1656
		if (in_array(strrchr($entry, '.'), array('.jpg', '.gif', '.jpeg', '.png')))
1657
			$smileys[strtolower($entry)] = $entry;
1658
	}
1659
	$dir->close();
1660
1661
	// Exclude the smileys that are already in the database.
1662
	$request = $smcFunc['db_query']('', '
1663
		SELECT filename
1664
		FROM {db_prefix}smileys
1665
		WHERE filename IN ({array_string:smiley_list})',
1666
		array(
1667
			'smiley_list' => $smileys,
1668
		)
1669
	);
1670 View Code Duplication
	while ($row = $smcFunc['db_fetch_assoc']($request))
1671
		if (isset($smileys[strtolower($row['filename'])]))
1672
			unset($smileys[strtolower($row['filename'])]);
1673
	$smcFunc['db_free_result']($request);
1674
1675
	$request = $smcFunc['db_query']('', '
1676
		SELECT MAX(smiley_order)
1677
		FROM {db_prefix}smileys
1678
		WHERE hidden = {int:postform}
1679
			AND smiley_row = {int:first_row}',
1680
		array(
1681
			'postform' => 0,
1682
			'first_row' => 0,
1683
		)
1684
	);
1685
	list ($smiley_order) = $smcFunc['db_fetch_row']($request);
1686
	$smcFunc['db_free_result']($request);
1687
1688
	$new_smileys = array();
1689
	foreach ($smileys as $smiley)
1690
		if (strlen($smiley) <= 48)
1691
			$new_smileys[] = array(':' . strtok($smiley, '.') . ':', $smiley, strtok($smiley, '.'), 0, ++$smiley_order);
1692
1693
	if (!empty($new_smileys))
1694
	{
1695
		$smcFunc['db_insert']('',
1696
			'{db_prefix}smileys',
1697
			array(
1698
				'code' => 'string-30', 'filename' => 'string-48', 'description' => 'string-80', 'smiley_row' => 'int', 'smiley_order' => 'int',
1699
			),
1700
			$new_smileys,
1701
			array('id_smiley')
1702
		);
1703
1704
		cache_put_data('parsing_smileys', null, 480);
1705
		cache_put_data('posting_smileys', null, 480);
1706
	}
1707
}
1708
1709
/**
1710
 * Handles editing message icons
1711
 */
1712
function EditMessageIcons()
1713
{
1714
	global $context, $settings, $txt;
1715
	global $smcFunc, $scripturl, $sourcedir;
1716
1717
	// Get a list of icons.
1718
	$context['icons'] = array();
1719
	$request = $smcFunc['db_query']('', '
1720
		SELECT m.id_icon, m.title, m.filename, m.icon_order, m.id_board, b.name AS board_name
1721
		FROM {db_prefix}message_icons AS m
1722
			LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
1723
		WHERE ({query_see_board} OR b.id_board IS NULL)
1724
		ORDER BY m.icon_order',
1725
		array(
1726
		)
1727
	);
1728
	$last_icon = 0;
1729
	$trueOrder = 0;
1730
	while ($row = $smcFunc['db_fetch_assoc']($request))
1731
	{
1732
		$context['icons'][$row['id_icon']] = array(
1733
			'id' => $row['id_icon'],
1734
			'title' => $row['title'],
1735
			'filename' => $row['filename'],
1736
			'image_url' => $settings[file_exists($settings['theme_dir'] . '/images/post/' . $row['filename'] . '.png') ? 'actual_images_url' : 'default_images_url'] . '/post/' . $row['filename'] . '.png',
1737
			'board_id' => $row['id_board'],
1738
			'board' => empty($row['board_name']) ? $txt['icons_edit_icons_all_boards'] : $row['board_name'],
1739
			'order' => $row['icon_order'],
1740
			'true_order' => $trueOrder++,
1741
			'after' => $last_icon,
1742
		);
1743
		$last_icon = $row['id_icon'];
1744
	}
1745
	$smcFunc['db_free_result']($request);
1746
1747
	// Submitting a form?
1748
	if (isset($_POST['icons_save']) || isset($_POST['delete']))
1749
	{
1750
		checkSession();
1751
1752
		// Deleting icons?
1753
		if (isset($_POST['delete']) && !empty($_POST['checked_icons']))
1754
		{
1755
			$deleteIcons = array();
1756
			foreach ($_POST['checked_icons'] as $icon)
1757
				$deleteIcons[] = (int) $icon;
1758
1759
			// Do the actual delete!
1760
			$smcFunc['db_query']('', '
1761
				DELETE FROM {db_prefix}message_icons
1762
				WHERE id_icon IN ({array_int:icon_list})',
1763
				array(
1764
					'icon_list' => $deleteIcons,
1765
				)
1766
			);
1767
		}
1768
		// Editing/Adding an icon?
1769
		elseif ($context['sub_action'] == 'editicon' && isset($_GET['icon']))
1770
		{
1771
			$_GET['icon'] = (int) $_GET['icon'];
1772
1773
			// Do some preperation with the data... like check the icon exists *somewhere*
1774
			if (strpos($_POST['icon_filename'], '.png') !== false)
1775
				$_POST['icon_filename'] = substr($_POST['icon_filename'], 0, -4);
1776
			if (!file_exists($settings['default_theme_dir'] . '/images/post/' . $_POST['icon_filename'] . '.png'))
1777
				fatal_lang_error('icon_not_found');
1778
			// There is a 16 character limit on message icons...
1779
			elseif (strlen($_POST['icon_filename']) > 16)
1780
				fatal_lang_error('icon_name_too_long');
1781
			elseif ($_POST['icon_location'] == $_GET['icon'] && !empty($_GET['icon']))
1782
				fatal_lang_error('icon_after_itself');
1783
1784
			// First do the sorting... if this is an edit reduce the order of everything after it by one ;)
1785
			if ($_GET['icon'] != 0)
1786
			{
1787
				$oldOrder = $context['icons'][$_GET['icon']]['true_order'];
1788
				foreach ($context['icons'] as $id => $data)
1789
					if ($data['true_order'] > $oldOrder)
1790
						$context['icons'][$id]['true_order']--;
1791
			}
1792
1793
			// If there are no existing icons and this is a new one, set the id to 1 (mainly for non-mysql)
1794
			if (empty($_GET['icon']) && empty($context['icons']))
1795
				$_GET['icon'] = 1;
1796
1797
			// Get the new order.
1798
			$newOrder = $_POST['icon_location'] == 0 ? 0 : $context['icons'][$_POST['icon_location']]['true_order'] + 1;
1799
			// Do the same, but with the one that used to be after this icon, done to avoid conflict.
1800
			foreach ($context['icons'] as $id => $data)
1801
				if ($data['true_order'] >= $newOrder)
1802
					$context['icons'][$id]['true_order']++;
1803
1804
			// Finally set the current icon's position!
1805
			$context['icons'][$_GET['icon']]['true_order'] = $newOrder;
1806
1807
			// Simply replace the existing data for the other bits.
1808
			$context['icons'][$_GET['icon']]['title'] = $_POST['icon_description'];
1809
			$context['icons'][$_GET['icon']]['filename'] = $_POST['icon_filename'];
1810
			$context['icons'][$_GET['icon']]['board_id'] = (int) $_POST['icon_board'];
1811
1812
			// Do a huge replace ;)
1813
			$iconInsert = array();
1814
			$iconInsert_new = array();
1815
			foreach ($context['icons'] as $id => $icon)
1816
			{
1817
				if ($id != 0)
1818
				{
1819
					$iconInsert[] = array($id, $icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']);
1820
				}
1821
				else
1822
				{
1823
					$iconInsert_new[] = array($icon['board_id'], $icon['title'], $icon['filename'], $icon['true_order']);
1824
				}
1825
			}
1826
1827
			$smcFunc['db_insert']('replace',
1828
				'{db_prefix}message_icons',
1829
				array('id_icon' => 'int', 'id_board' => 'int', 'title' => 'string-80', 'filename' => 'string-80', 'icon_order' => 'int'),
1830
				$iconInsert,
1831
				array('id_icon')
1832
			);
1833
1834
			if (!empty($iconInsert_new))
1835
			{
1836
				$smcFunc['db_insert']('replace',
1837
					'{db_prefix}message_icons',
1838
					array('id_board' => 'int', 'title' => 'string-80', 'filename' => 'string-80', 'icon_order' => 'int'),
1839
					$iconInsert_new,
1840
					array('id_icon')
1841
				);
1842
			}
1843
		}
1844
1845
		// Unless we're adding a new thing, we'll escape
1846
		if (!isset($_POST['add']))
1847
			redirectexit('action=admin;area=smileys;sa=editicons');
1848
	}
1849
1850
	$context[$context['admin_menu_name']]['current_subsection'] = 'editicons';
1851
1852
	$listOptions = array(
1853
		'id' => 'message_icon_list',
1854
		'title' => $txt['icons_edit_message_icons'],
1855
		'base_href' => $scripturl . '?action=admin;area=smileys;sa=editicons',
1856
		'get_items' => array(
1857
			'function' => 'list_getMessageIcons',
1858
		),
1859
		'no_items_label' => $txt['icons_no_entries'],
1860
		'columns' => array(
1861
			'icon' => array(
1862
				'data' => array(
1863
					'function' => function ($rowData) use ($settings, $smcFunc)
1864
					{
1865
						$images_url = $settings[file_exists(sprintf('%1$s/images/post/%2$s.png', $settings['theme_dir'], $rowData['filename'])) ? 'actual_images_url' : 'default_images_url'];
1866
						return sprintf('<img src="%1$s/post/%2$s.png" alt="%3$s">', $images_url, $rowData['filename'], $smcFunc['htmlspecialchars']($rowData['title']));
1867
					},
1868
					'class' => 'centercol',
1869
				),
1870
			),
1871
			'filename' => array(
1872
				'header' => array(
1873
					'value' => $txt['smileys_filename'],
1874
				),
1875
				'data' => array(
1876
					'sprintf' => array(
1877
						'format' => '%1$s.png',
1878
						'params' => array(
1879
							'filename' => true,
1880
						),
1881
					),
1882
				),
1883
			),
1884
			'tooltip' => array(
1885
				'header' => array(
1886
					'value' => $txt['smileys_description'],
1887
				),
1888
				'data' => array(
1889
					'db_htmlsafe' => 'title',
1890
				),
1891
			),
1892
			'board' => array(
1893
				'header' => array(
1894
					'value' => $txt['icons_board'],
1895
				),
1896
				'data' => array(
1897
					'function' => function ($rowData) use ($txt)
1898
					{
1899
						return empty($rowData['board_name']) ? $txt['icons_edit_icons_all_boards'] : $rowData['board_name'];
1900
					},
1901
				),
1902
			),
1903
			'modify' => array(
1904
				'header' => array(
1905
					'value' => $txt['smileys_modify'],
1906
					'class' => 'centercol',
1907
				),
1908
				'data' => array(
1909
					'sprintf' => array(
1910
						'format' => '<a href="' . $scripturl . '?action=admin;area=smileys;sa=editicon;icon=%1$s">' . $txt['smileys_modify'] . '</a>',
1911
						'params' => array(
1912
							'id_icon' => false,
1913
						),
1914
					),
1915
					'class' => 'centercol',
1916
				),
1917
			),
1918
			'check' => array(
1919
				'header' => array(
1920
					'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" class="input_check">',
1921
					'class' => 'centercol',
1922
				),
1923
				'data' => array(
1924
					'sprintf' => array(
1925
						'format' => '<input type="checkbox" name="checked_icons[]" value="%1$d" class="input_check">',
1926
						'params' => array(
1927
							'id_icon' => false,
1928
						),
1929
					),
1930
					'class' => 'centercol',
1931
				),
1932
			),
1933
		),
1934
		'form' => array(
1935
			'href' => $scripturl . '?action=admin;area=smileys;sa=editicons',
1936
		),
1937
		'additional_rows' => array(
1938
			array(
1939
				'position' => 'below_table_data',
1940
				'value' => '<input type="submit" name="delete" value="' . $txt['quickmod_delete_selected'] . '" class="button_submit"> <a class="button_link" href="' . $scripturl . '?action=admin;area=smileys;sa=editicon">' . $txt['icons_add_new'] . '</a>',
1941
			),
1942
		),
1943
	);
1944
1945
	require_once($sourcedir . '/Subs-List.php');
1946
	createList($listOptions);
1947
1948
	// If we're adding/editing an icon we'll need a list of boards
1949
	if ($context['sub_action'] == 'editicon' || isset($_POST['add']))
1950
	{
1951
		// Force the sub_template just in case.
1952
		$context['sub_template'] = 'editicon';
1953
1954
		$context['new_icon'] = !isset($_GET['icon']);
1955
1956
		// Get the properties of the current icon from the icon list.
1957
		if (!$context['new_icon'])
1958
			$context['icon'] = $context['icons'][$_GET['icon']];
1959
1960
		// Get a list of boards needed for assigning this icon to a specific board.
1961
		$boardListOptions = array(
1962
			'use_permissions' => true,
1963
			'selected_board' => isset($context['icon']['board_id']) ? $context['icon']['board_id'] : 0,
1964
		);
1965
		require_once($sourcedir . '/Subs-MessageIndex.php');
1966
		$context['categories'] = getBoardList($boardListOptions);
1967
	}
1968
}
1969
1970
/**
1971
 * Callback function for createList().
1972
 *
1973
 * @param int $start The item to start with (not used here)
1974
 * @param int $items_per_page The number of items to display per page (not used here)
1975
 * @param string $sort A string indicating how to sort the items (not used here)
1976
 * @return array An array of information about message icons
1977
 */
1978 View Code Duplication
function list_getMessageIcons($start, $items_per_page, $sort)
1979
{
1980
	global $smcFunc;
1981
1982
	$request = $smcFunc['db_query']('', '
1983
		SELECT m.id_icon, m.title, m.filename, m.icon_order, m.id_board, b.name AS board_name
1984
		FROM {db_prefix}message_icons AS m
1985
			LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
1986
		WHERE ({query_see_board} OR b.id_board IS NULL)
1987
		ORDER BY m.icon_order',
1988
		array()
1989
	);
1990
1991
	$message_icons = array();
1992
	while ($row = $smcFunc['db_fetch_assoc']($request))
1993
		$message_icons[] = $row;
1994
	$smcFunc['db_free_result']($request);
1995
1996
	return $message_icons;
1997
}
1998
1999
?>