Failed Conditions
Branch release-2.1 (4e22cf)
by Rick
07:22
created

Subs-Themes.php ➔ remove_theme()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 61
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 25
nc 3
nop 1
dl 0
loc 61
rs 8.9392
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Helper file for handling themes.
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
 * Gets a single theme's info.
21
 *
22
 * @param int $id The theme ID to get the info from.
23
 * @return array The theme info as an array.
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
24
 */
25
function get_single_theme($id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
26
{
27
	global $smcFunc, $modSettings;
28
29
	// No data, no fun!
30
	if (empty($id))
31
		return false;
32
33
	// Make sure $id is an int.
34
	$id = (int) $id;
35
36
	// List of all possible  values.
37
	$themeValues = array(
38
		'theme_dir',
39
		'images_url',
40
		'theme_url',
41
		'name',
42
		'theme_layers',
43
		'theme_templates',
44
		'version',
45
		'install_for',
46
		'based_on',
47
	);
48
49
	// Make changes if you really want it.
50
	call_integration_hook('integrate_get_single_theme', array(&$themeValues, $id));
51
52
	$single = array(
53
		'id' => $id,
54
	);
55
56
	// Make our known/enable themes a little easier to work with.
57
	$knownThemes = !empty($modSettings['knownThemes']) ? explode(',', $modSettings['knownThemes']) : array();
58
	$enableThemes = !empty($modSettings['enableThemes']) ? explode(',', $modSettings['enableThemes']) : array();
59
60
	$request = $smcFunc['db_query']('', '
61
		SELECT id_theme, variable, value
62
		FROM {db_prefix}themes
63
		WHERE variable IN ({array_string:theme_values})
64
			AND id_theme = ({int:id_theme})
65
			AND id_member = {int:no_member}',
66
		array(
67
			'theme_values' => $themeValues,
68
			'id_theme' => $id,
69
			'no_member' => 0,
70
		)
71
	);
72
73
	while ($row = $smcFunc['db_fetch_assoc']($request))
74
	{
75
		$single[$row['variable']] = $row['value'];
76
77
		// Fix the path and tell if its a valid one.
78
		if ($row['variable'] == 'theme_dir')
79
		{
80
			$single['theme_dir'] = realpath($row['value']);
81
			$single['valid_path'] = file_exists($row['value']) && is_dir($row['value']);
82
		}
83
	}
84
85
	// Is this theme installed and enabled?
86
	$single['known'] = in_array($single['id'], $knownThemes);
87
	$single['enable'] = in_array($single['id'], $enableThemes);
88
89
	// It should at least return if the theme is a known one or if its enable.
90
	return $single;
91
}
92
93
/**
94
 * Loads and returns all installed themes.
95
 *
96
 * Stores all themes on $context['themes'] for easier use.
97
 * @param bool $enable_only false by default for getting all themes. If true the function will return all themes that are currently enable.
98
 * @return array With the theme's IDs as key.
0 ignored issues
show
Documentation introduced by
Should the return type not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
99
 */
100
function get_all_themes($enable_only = false)
0 ignored issues
show
Coding Style introduced by
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
101
{
102
	global $modSettings, $context, $smcFunc;
103
104
	// Make our known/enable themes a little easier to work with.
105
	$knownThemes = !empty($modSettings['knownThemes']) ? explode(',', $modSettings['knownThemes']) : array();
106
	$enableThemes = !empty($modSettings['enableThemes']) ? explode(',', $modSettings['enableThemes']) : array();
107
108
	// List of all possible themes values.
109
	$themeValues = array(
110
		'theme_dir',
111
		'images_url',
112
		'theme_url',
113
		'name',
114
		'theme_layers',
115
		'theme_templates',
116
		'version',
117
		'install_for',
118
		'based_on',
119
	);
120
121
	// Make changes if you really want it.
122
	call_integration_hook('integrate_get_all_themes', array(&$themeValues, $enable_only));
123
124
	// So, what is it going to be?
125
	$query_where = $enable_only ? $enableThemes : $knownThemes;
126
127
	// Perform the query as requested.
128
	$request = $smcFunc['db_query']('', '
129
		SELECT id_theme, variable, value
130
		FROM {db_prefix}themes
131
		WHERE variable IN ({array_string:theme_values})
132
			AND id_theme IN ({array_string:query_where})
133
			AND id_member = {int:no_member}',
134
		array(
135
			'query_where' => $query_where,
136
			'theme_values' => $themeValues,
137
			'no_member' => 0,
138
		)
139
	);
140
141
	$context['themes'] = array();
142
143
	while ($row = $smcFunc['db_fetch_assoc']($request))
144
	{
145
		$context['themes'][$row['id_theme']]['id'] = (int) $row['id_theme'];
146
147
		// Fix the path and tell if its a valid one.
148
		if ($row['variable'] == 'theme_dir')
149
		{
150
			$context['themes'][$row['id_theme']][$row['variable']] = realpath($row['value']);
151
			$context['themes'][$row['id_theme']]['valid_path'] = file_exists(realpath($row['value'])) && is_dir(realpath($row['value']));
152
		}
153
154
		$context['themes'][$row['id_theme']]['known'] = in_array($row['id_theme'], $knownThemes);
155
		$context['themes'][$row['id_theme']]['enable'] = in_array($row['id_theme'], $enableThemes);
156
		$context['themes'][$row['id_theme']][$row['variable']] = $row['value'];
157
	}
158
159
	$smcFunc['db_free_result']($request);
160
}
161
162
/**
163
 * Reads an .xml file and returns the data as an array
164
 *
165
 * Removes the entire theme if the .xml file couldn't be found or read.
166
 * @param string $path The absolute path to the xml file.
167
 * @return array An array with all the info extracted from the xml file.
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
168
 */
169
function get_theme_info($path)
0 ignored issues
show
Coding Style introduced by
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
170
{
171
	global $smcFunc, $sourcedir, $forum_version, $txt, $scripturl, $context;
172
	global $explicit_images;
173
174
	if (empty($path))
175
		return false;
176
177
	$xml_data = array();
178
	$explicit_images = false;
179
180
	// Perhaps they are trying to install a mod, lets tell them nicely this is the wrong function.
181
	if (file_exists($path . '/package-info.xml'))
182
	{
183
		loadLanguage('Errors');
184
185
		// We need to delete the dir otherwise the next time you try to install a theme you will get the same error.
186
		remove_dir($path);
187
188
		$txt['package_get_error_is_mod'] = str_replace('{MANAGEMODURL}', $scripturl . '?action=admin;area=packages;' . $context['session_var'] . '=' . $context['session_id'], $txt['package_get_error_is_mod']);
189
		fatal_lang_error('package_theme_upload_error_broken', false, $txt['package_get_error_is_mod']);
190
	}
191
192
	// Parse theme-info.xml into an xmlArray.
193
	require_once($sourcedir . '/Class-Package.php');
194
	$theme_info_xml = new xmlArray(file_get_contents($path . '/theme_info.xml'));
195
196
	// Error message, there isn't any valid info.
197
	if (!$theme_info_xml->exists('theme-info[0]'))
198
	{
199
		remove_dir($path);
200
		fatal_lang_error('package_get_error_packageinfo_corrupt', false);
201
	}
202
203
	// Check for compatibility with 2.1 or greater.
204
	if (!$theme_info_xml->exists('theme-info/install'))
205
	{
206
		remove_dir($path);
207
		fatal_lang_error('package_get_error_theme_not_compatible', false, $forum_version);
208
	}
209
210
	// So, we have an install tag which is cool and stuff but we also need to check it and match your current SMF version...
211
	$the_version = strtr($forum_version, array('SMF ' => ''));
212
	$install_versions = $theme_info_xml->path('theme-info/install/@for');
213
214
	// The theme isn't compatible with the current SMF version.
215
	if (!$install_versions || !matchPackageVersion($the_version, $install_versions))
216
	{
217
		remove_dir($path);
218
		fatal_lang_error('package_get_error_theme_not_compatible', false, $forum_version);
219
	}
220
221
	$theme_info_xml = $theme_info_xml->path('theme-info[0]');
222
	$theme_info_xml = $theme_info_xml->to_array();
223
224
	$xml_elements = array(
225
		'theme_layers' => 'layers',
226
		'theme_templates' => 'templates',
227
		'based_on' => 'based-on',
228
		'version' => 'version',
229
	);
230
231
	// Assign the values to be stored.
232
	foreach ($xml_elements as $var => $name)
233
		if (!empty($theme_info_xml[$name]))
234
			$xml_data[$var] = $theme_info_xml[$name];
235
236
	// Add the supported versions.
237
	$xml_data['install_for'] = $install_versions;
238
239
	// Overwrite the default images folder.
240
	if (!empty($theme_info_xml['images']))
241
	{
242
		$xml_data['images_url'] = $path . '/' . $theme_info_xml['images'];
243
		$explicit_images = true;
244
	}
245
246
	if (!empty($theme_info_xml['extra']))
247
		$xml_data += $smcFunc['json_decode']($theme_info_xml['extra'], true);
248
249
	return $xml_data;
250
}
251
252
/**
253
 * Inserts a theme's data to the DataBase.
254
 *
255
 * Ends execution with fatal_lang_error() if an error appears.
256
 * @param array $to_install An array containing all values to be stored into the DB.
257
 * @return int The newly created theme ID.
258
 */
259
function theme_install($to_install = array())
0 ignored issues
show
Coding Style introduced by
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
260
{
261
	global $smcFunc, $context, $modSettings;
262
	global $settings, $explicit_images;
263
264
	// External use? no problem!
265
	if ($to_install)
0 ignored issues
show
Bug Best Practice introduced by
The expression $to_install of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
266
		$context['to_install'] = $to_install;
267
268
	// One last check.
269
	if (empty($context['to_install']['theme_dir']) || basename($context['to_install']['theme_dir']) == 'Themes')
270
		fatal_lang_error('theme_install_invalid_dir', false);
271
272
	// OK, is this a newer version of an already installed theme?
273
	if (!empty($context['to_install']['version']))
274
	{
275
		$request = $smcFunc['db_query']('', '
276
			SELECT id_theme, variable, value
277
			FROM {db_prefix}themes
278
			WHERE id_member = {int:no_member}
279
				AND variable = {string:name}
280
				AND value LIKE {string:name_value}
281
			LIMIT 1',
282
			array(
283
				'no_member' => 0,
284
				'name' => 'name',
285
				'version' => 'version',
286
				'name_value' => '%' . $context['to_install']['name'] . '%',
287
			)
288
		);
289
290
		$to_update = $smcFunc['db_fetch_assoc']($request);
291
		$smcFunc['db_free_result']($request);
292
293
		// Got something, lets figure it out what to do next.
294
		if (!empty($to_update) && !empty($to_update['version']))
295
			switch (compareVersions($context['to_install']['version'], $to_update['version']))
296
			{
297
				case 1: // Got a newer version, update the old entry.
298
					$smcFunc['db_query']('', '
299
						UPDATE {db_prefix}themes
300
						SET value = {string:new_value}
301
						WHERE variable = {string:version}
302
							AND id_theme = {int:id_theme}',
303
						array(
304
							'new_value' => $context['to_install']['version'],
305
							'version' => 'version',
306
							'id_theme' => $to_update['id_theme'],
307
						)
308
					);
309
310
					// Done with the update, tell the user about it.
311
					$context['to_install']['updated'] = true;
312
313
					return $to_update['id_theme'];
314
					break; // Just for reference.
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
315
				case 0: // This is exactly the same theme.
316
				case -1: // The one being installed is older than the one already installed.
317
				default: // Any other possible result.
318
					fatal_lang_error('package_get_error_theme_no_new_version', false, array($context['to_install']['version'], $to_update['version']));
319
			}
320
	}
321
322
	if (!empty($context['to_install']['based_on']))
323
	{
324
		// No need for elaborated stuff when the theme is based on the default one.
325
		if ($context['to_install']['based_on'] == 'default')
326
		{
327
			$context['to_install']['theme_url'] = $settings['default_theme_url'];
328
			$context['to_install']['images_url'] = $settings['default_images_url'];
329
		}
330
331
		// Custom theme based on another custom theme, lets get some info.
332
		elseif ($context['to_install']['based_on'] != '')
333
		{
334
			$context['to_install']['based_on'] = preg_replace('~[^A-Za-z0-9\-_ ]~', '', $context['to_install']['based_on']);
335
336
			// Get the theme info first.
337
			$request = $smcFunc['db_query']('', '
338
				SELECT id_theme
339
				FROM {db_prefix}themes
340
				WHERE id_member = {int:no_member}
341
					AND (value LIKE {string:based_on} OR value LIKE {string:based_on_path})
342
				LIMIT 1',
343
				array(
344
					'no_member' => 0,
345
					'based_on' => '%/' . $context['to_install']['based_on'],
346
					'based_on_path' => '%' . "\\" . $context['to_install']['based_on'],
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal \\ does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
347
				)
348
			);
349
350
			$based_on = $smcFunc['db_fetch_assoc']($request);
351
			$smcFunc['db_free_result']($request);
352
353
			$request = $smcFunc['db_query']('', '
354
				SELECT variable, value
355
				FROM {db_prefix}themes
356
					WHERE variable IN ({array_string:theme_values})
357
						AND id_theme = ({int:based_on})
358
				LIMIT 1',
359
				array(
360
					'no_member' => 0,
361
					'theme__values' => array('theme_url', 'images_url', 'theme_dir',),
362
					'based_on' => $based_on['id_theme'],
363
				)
364
			);
365
			$temp = $smcFunc['db_fetch_assoc']($request);
366
			$smcFunc['db_free_result']($request);
367
368
			// Found the based on theme info, add it to the current one being installed.
369
			if (is_array($temp))
370
			{
371
				$context['to_install']['base_theme_url'] = $temp['theme_url'];
372
				$context['to_install']['base_theme_dir'] = $temp['theme_dir'];
373
374
				if (empty($explicit_images) && !empty($context['to_install']['base_theme_url']))
375
					$context['to_install']['theme_url'] = $context['to_install']['base_theme_url'];
376
			}
377
378
			// Nope, sorry, couldn't find any theme already installed.
379
			else
380
				fatal_lang_error('package_get_error_theme_no_based_on_found', false, $context['to_install']['based_on']);
381
		}
382
383
		unset($context['to_install']['based_on']);
384
	}
385
386
	// Find the newest id_theme.
387
	$result = $smcFunc['db_query']('', '
388
		SELECT MAX(id_theme)
389
		FROM {db_prefix}themes',
390
		array(
391
		)
392
	);
393
	list ($id_theme) = $smcFunc['db_fetch_row']($result);
394
	$smcFunc['db_free_result']($result);
395
396
	// This will be theme number...
397
	$id_theme++;
398
399
	// Last minute changes? although, the actual array is a context value you might want to use the new ID.
400
	call_integration_hook('integrate_theme_install', array(&$context['to_install'], $id_theme));
401
402
	$inserts = array();
403
	foreach ($context['to_install'] as $var => $val)
404
		$inserts[] = array($id_theme, $var, $val);
405
406
	if (!empty($inserts))
407
		$smcFunc['db_insert']('insert',
408
			'{db_prefix}themes',
409
			array('id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'),
410
			$inserts,
411
			array('id_theme', 'variable')
412
		);
413
414
	// Update the known and enable Theme's settings.
415
	$known = strtr($modSettings['knownThemes'] . ',' . $id_theme, array(',,' => ','));
416
	$enable = strtr($modSettings['enableThemes'] . ',' . $id_theme, array(',,' => ','));
417
	updateSettings(array('knownThemes' => $known, 'enableThemes' => $enable));
418
419
	return $id_theme;
420
}
421
422
/**
423
 * Removes a directory from the themes dir.
424
 *
425
 * This is a recursive function, it will call itself if there are subdirs inside the main directory.
426
 * @param string $path The absolute path to the directory to be removed
427
 * @return bool true when success, false on error.
0 ignored issues
show
Documentation introduced by
Should the return type not be false|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
428
 */
429
function remove_dir($path)
0 ignored issues
show
Coding Style introduced by
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
430
{
431
	if (empty($path))
432
		return false;
433
434
	if (is_dir($path))
435
	{
436
		$objects = scandir($path);
437
438
		foreach ($objects as $object)
439
			if ($object != '.' && $object != '..')
440
			{
441
				if (filetype($path . '/' . $object) == 'dir')
442
					remove_dir($path . '/' . $object);
443
444
				else
445
					unlink($path . '/' . $object);
446
			}
447
	}
448
449
	reset($objects);
450
	rmdir($path);
451
}
452
453
/**
454
 * Removes a theme from the DB, includes all possible places where the theme might be used.
455
 *
456
 * @param int $themeID The theme ID
457
 * @return bool true when success, false on error.
458
 */
459
function remove_theme($themeID)
0 ignored issues
show
Coding Style introduced by
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
460
{
461
	global $smcFunc, $modSettings;
462
463
	// Can't delete the default theme, sorry!
464
	if (empty($themeID) || $themeID == 1)
465
		return false;
466
467
	$known = explode(',', $modSettings['knownThemes']);
468
	$enable = explode(',', $modSettings['enableThemes']);
469
470
	// Remove it from the themes table.
471
	$smcFunc['db_query']('', '
472
		DELETE FROM {db_prefix}themes
473
		WHERE id_theme = {int:current_theme}',
474
		array(
475
			'current_theme' => $themeID,
476
		)
477
	);
478
479
	// Update users preferences.
480
	$smcFunc['db_query']('', '
481
		UPDATE {db_prefix}members
482
		SET id_theme = {int:default_theme}
483
		WHERE id_theme = {int:current_theme}',
484
		array(
485
			'default_theme' => 0,
486
			'current_theme' => $themeID,
487
		)
488
	);
489
490
	// Some boards may have it as preferred theme.
491
	$smcFunc['db_query']('', '
492
		UPDATE {db_prefix}boards
493
		SET id_theme = {int:default_theme}
494
		WHERE id_theme = {int:current_theme}',
495
		array(
496
			'default_theme' => 0,
497
			'current_theme' => $themeID,
498
		)
499
	);
500
501
	// Remove it from the list of known themes.
502
	$known = array_diff($known, array($themeID));
503
504
	// And the enable list too.
505
	$enable = array_diff($enable, array($themeID));
506
507
	// Back to good old comma separated string.
508
	$known = strtr(implode(',', $known), array(',,' => ','));
509
	$enable = strtr(implode(',', $enable), array(',,' => ','));
510
511
	// Update the enableThemes list.
512
	updateSettings(array('enableThemes' => $enable, 'knownThemes' => $known));
513
514
	// Fix it if the theme was the overall default theme.
515
	if ($modSettings['theme_guests'] == $themeID)
516
		updateSettings(array('theme_guests' => '1'));
517
518
	return true;
519
}
520
521
/**
522
 * Generates a file listing for a given directory
523
 *
524
 * @param string $path The full path to the directory
525
 * @param string $relative The relative path (relative to the Themes directory)
526
 * @return array An array of information about the files and directories found
527
 */
528
function get_file_listing($path, $relative)
0 ignored issues
show
Coding Style introduced by
As per coding-style, this function should be in camelCase.

CamelCase (...) is the practice of writing compound words or phrases such that
each word or abbreviation begins with a capital letter.

Learn more about camelCase.

Loading history...
529
{
530
	global $scripturl, $txt, $context;
531
532
	// Is it even a directory?
533
	if (!is_dir($path))
534
		fatal_lang_error('error_invalid_dir', 'critical');
535
536
	$dir = dir($path);
537
	$entries = array();
538
	while ($entry = $dir->read())
539
		$entries[] = $entry;
540
	$dir->close();
541
542
	natcasesort($entries);
543
544
	$listing1 = array();
545
	$listing2 = array();
546
547
	foreach ($entries as $entry)
548
	{
549
		// Skip all dot files, including .htaccess.
550
		if (substr($entry, 0, 1) == '.' || $entry == 'CVS')
551
			continue;
552
553
		if (is_dir($path . '/' . $entry))
554
			$listing1[] = array(
555
				'filename' => $entry,
556
				'is_writable' => is_writable($path . '/' . $entry),
557
				'is_directory' => true,
558
				'is_template' => false,
559
				'is_image' => false,
560
				'is_editable' => false,
561
				'href' => $scripturl . '?action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;directory=' . $relative . $entry,
562
				'size' => '',
563
			);
564
		else
565
		{
566
			$size = filesize($path . '/' . $entry);
567
			if ($size > 2048 || $size == 1024)
568
				$size = comma_format($size / 1024) . ' ' . $txt['themeadmin_edit_kilobytes'];
569
			else
570
				$size = comma_format($size) . ' ' . $txt['themeadmin_edit_bytes'];
571
572
			$listing2[] = array(
573
				'filename' => $entry,
574
				'is_writable' => is_writable($path . '/' . $entry),
575
				'is_directory' => false,
576
				'is_template' => preg_match('~\.template\.php$~', $entry) != 0,
577
				'is_image' => preg_match('~\.(jpg|jpeg|gif|bmp|png)$~', $entry) != 0,
578
				'is_editable' => is_writable($path . '/' . $entry) && preg_match('~\.(php|pl|css|js|vbs|xml|xslt|txt|xsl|html|htm|shtm|shtml|asp|aspx|cgi|py)$~', $entry) != 0,
579
				'href' => $scripturl . '?action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;filename=' . $relative . $entry,
580
				'size' => $size,
581
				'last_modified' => timeformat(filemtime($path . '/' . $entry)),
582
			);
583
		}
584
	}
585
586
	return array_merge($listing1, $listing2);
587
}
588
589
?>