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

PackageGet.php ➔ PackageGet()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 59
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 34
nc 3
nop 0
dl 0
loc 59
rs 8.9846
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
 * This file handles the package servers and packages download from Package Manager.
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
 * Browse the list of package servers, add servers...
21
 */
22
function PackageGet()
23
{
24
	global $txt, $context, $sourcedir;
25
26
	isAllowedTo('admin_forum');
27
	require_once($sourcedir . '/Subs-Package.php');
28
29
	// Use the Packages template... no reason to separate.
30
	loadLanguage('Packages');
31
	loadTemplate('Packages', 'admin');
32
33
	$context['page_title'] = $txt['package'];
34
35
	// Here is a list of all the potentially valid actions.
36
	$subActions = array(
37
		'servers' => 'PackageServers',
38
		'add' => 'PackageServerAdd',
39
		'browse' => 'PackageGBrowse',
40
		'download' => 'PackageDownload',
41
		'remove' => 'PackageServerRemove',
42
		'upload' => 'PackageUpload',
43
	);
44
45
	// Now let's decide where we are taking this...
46
	if (isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]))
47
		$context['sub_action'] = $_REQUEST['sa'];
48
	// We need to support possible old javascript links...
49
	elseif (isset($_GET['pgdownload']))
50
		$context['sub_action'] = 'download';
51
	else
52
		$context['sub_action'] = 'servers';
53
54
	// We need to force the "Download" tab as selected.
55
	$context['menu_data_' . $context['admin_menu_id']]['current_subsection'] = 'packageget';
56
57
	// Now create the tabs for the template.
58
	$context[$context['admin_menu_name']]['tab_data'] = array(
59
		'title' => $txt['package_manager'],
60
		//'help' => 'registrations',
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
61
		'description' => $txt['package_manager_desc'],
62
		'tabs' => array(
63
			'browse' => array(
64
			),
65
			'packageget' => array(
66
				'description' => $txt['download_packages_desc'],
67
			),
68
			'perms' => array(
69
				'description' => $txt['package_file_perms_desc'],
70
			),
71
			'options' => array(
72
				'description' => $txt['package_install_options_ftp_why'],
73
			),
74
		),
75
	);
76
77
	call_integration_hook('integrate_package_get', array(&$subActions));
78
79
	call_helper($subActions[$context['sub_action']]);
80
}
81
82
/**
83
 * Load a list of package servers.
84
 */
85
function PackageServers()
86
{
87
	global $txt, $context, $sourcedir, $packagesdir, $modSettings, $smcFunc;
88
89
	// Ensure we use the correct template, and page title.
90
	$context['sub_template'] = 'servers';
91
	$context['page_title'] .= ' - ' . $txt['download_packages'];
92
93
	// Load the list of servers.
94
	$request = $smcFunc['db_query']('', '
95
		SELECT id_server, name, url
96
		FROM {db_prefix}package_servers',
97
		array(
98
		)
99
	);
100
	$context['servers'] = array();
101
	while ($row = $smcFunc['db_fetch_assoc']($request))
102
	{
103
		$context['servers'][] = array(
104
			'name' => $row['name'],
105
			'url' => $row['url'],
106
			'id' => $row['id_server'],
107
		);
108
	}
109
	$smcFunc['db_free_result']($request);
110
111
	$context['package_download_broken'] = !is_writable($packagesdir);
112
113
	if ($context['package_download_broken'])
114
	{
115
		smf_chmod($packagesdir, 0777);
116
	}
117
118
	$context['package_download_broken'] = !is_writable($packagesdir);
119
120
	if ($context['package_download_broken'])
121
	{
122 View Code Duplication
		if (isset($_POST['ftp_username']))
123
		{
124
			require_once($sourcedir . '/Class-Package.php');
125
			$ftp = new ftp_connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']);
126
127
			if ($ftp->error === false)
128
			{
129
				// I know, I know... but a lot of people want to type /home/xyz/... which is wrong, but logical.
130
				if (!$ftp->chdir($_POST['ftp_path']))
131
				{
132
					$ftp_error = $ftp->error;
133
					$ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path']));
134
				}
135
			}
136
		}
137
138
		if (!isset($ftp) || $ftp->error !== false)
139
		{
140 View Code Duplication
			if (!isset($ftp))
141
			{
142
				require_once($sourcedir . '/Class-Package.php');
143
				$ftp = new ftp_connection(null);
144
			}
145
			elseif ($ftp->error !== false && !isset($ftp_error))
146
				$ftp_error = $ftp->last_message === null ? '' : $ftp->last_message;
147
148
			list ($username, $detect_path, $found_path) = $ftp->detect_path($packagesdir);
149
150
			if ($found_path || !isset($_POST['ftp_path']))
151
				$_POST['ftp_path'] = $detect_path;
152
153
			if (!isset($_POST['ftp_username']))
154
				$_POST['ftp_username'] = $username;
155
156
			$context['package_ftp'] = array(
157
				'server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : (isset($modSettings['package_server']) ? $modSettings['package_server'] : 'localhost'),
158
				'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : (isset($modSettings['package_port']) ? $modSettings['package_port'] : '21'),
159
				'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : (isset($modSettings['package_username']) ? $modSettings['package_username'] : ''),
160
				'path' => $_POST['ftp_path'],
161
				'error' => empty($ftp_error) ? null : $ftp_error,
162
			);
163
		}
164
		else
165
		{
166
			$context['package_download_broken'] = false;
167
168
			$ftp->chmod('.', 0777);
169
			$ftp->close();
170
		}
171
	}
172
173
	addInlineJavaScript('
174
	$(\'.new_package_content\').hide();
175
	$(\'.download_new_package\').on(\'click\', function() {
176
		var collapseState = $(\'.new_package_content\').css(\'display\');
177
		var icon = $(\'.download_new_package\').children(\'span\');
178
		var collapsedDiv = $(\'.new_package_content\');
179
180
		if (collapseState == \'none\')
181
		{
182
			collapsedDiv.show(\'slow\');
183
			icon.removeClass(\'toggle_down\').addClass(\'toggle_up\');
184
			icon.prop(\'title\', '. JavaScriptEscape($txt['hide']) .');
185
		}
186
187
		else
188
		{
189
			collapsedDiv.hide(\'slow\');
190
			icon.removeClass(\'toggle_up\').addClass(\'toggle_down\');
191
			icon.prop(\'title\', '. JavaScriptEscape($txt['show']) .');
192
		}
193
194
	});', true);
195
}
196
197
/**
198
 * Browse a server's list of packages.
199
 */
200
function PackageGBrowse()
201
{
202
	global $txt, $context, $scripturl, $sourcedir, $forum_version, $smcFunc;
203
204
	if (isset($_GET['server']))
205
	{
206
		if ($_GET['server'] == '')
207
			redirectexit('action=admin;area=packages;get');
208
209
		$server = (int) $_GET['server'];
210
211
		// Query the server list to find the current server.
212
		$request = $smcFunc['db_query']('', '
213
			SELECT name, url
214
			FROM {db_prefix}package_servers
215
			WHERE id_server = {int:current_server}
216
			LIMIT 1',
217
			array(
218
				'current_server' => $server,
219
			)
220
		);
221
		list ($name, $url) = $smcFunc['db_fetch_row']($request);
222
		$smcFunc['db_free_result']($request);
223
224
		// If the server does not exist, dump out.
225
		if (empty($url))
226
			fatal_lang_error('couldnt_connect', false);
227
228
		// If there is a relative link, append to the stored server url.
229
		if (isset($_GET['relative']))
230
			$url = $url . (substr($url, -1) == '/' ? '' : '/') . $_GET['relative'];
231
232
		// Clear any "absolute" URL.  Since "server" is present, "absolute" is garbage.
233
		unset($_GET['absolute']);
234
	}
235
	elseif (isset($_GET['absolute']) && $_GET['absolute'] != '')
236
	{
237
		// Initialize the requried variables.
238
		$server = '';
239
		$url = $_GET['absolute'];
240
		$name = '';
241
		$_GET['package'] = $url . '/packages.xml?language=' . $context['user']['language'];
242
243
		// Clear any "relative" URL.  Since "server" is not present, "relative" is garbage.
244
		unset($_GET['relative']);
245
246
		$token = checkConfirm('get_absolute_url');
247
		if ($token !== true)
248
		{
249
			$context['sub_template'] = 'package_confirm';
250
251
			$context['page_title'] = $txt['package_servers'];
252
			$context['confirm_message'] = sprintf($txt['package_confirm_view_package_content'], $smcFunc['htmlspecialchars']($_GET['absolute']));
253
			$context['proceed_href'] = $scripturl . '?action=admin;area=packages;get;sa=browse;absolute=' . urlencode($_GET['absolute']) . ';confirm=' . $token;
254
255
			return;
256
		}
257
	}
258
	// Minimum required parameter did not exist so dump out.
259
	else
260
		fatal_lang_error('couldnt_connect', false);
261
262
	// Attempt to connect.  If unsuccessful... try the URL.
263
	if (!isset($_GET['package']) || file_exists($_GET['package']))
264
		$_GET['package'] = $url . '/packages.xml?language=' . $context['user']['language'];
0 ignored issues
show
Bug introduced by
The variable $url 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...
265
266
	// Check to be sure the packages.xml file actually exists where it is should be... or dump out.
267
	if ((isset($_GET['absolute']) || isset($_GET['relative'])) && !url_exists($_GET['package']))
268
		fatal_lang_error('packageget_unable', false, array($url . '/index.php'));
269
270
	// Might take some time.
271
	@set_time_limit(600);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
272
273
	// Read packages.xml and parse into xmlArray. (the true tells it to trim things ;).)
274
	require_once($sourcedir . '/Class-Package.php');
275
	$listing = new xmlArray(fetch_web_data($_GET['package']), true);
0 ignored issues
show
Security Bug introduced by
It seems like fetch_web_data($_GET['package']) targeting fetch_web_data() can also be of type false; however, xmlArray::__construct() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
276
277
	// Errm.... empty file?  Try the URL....
278
	if (!$listing->exists('package-list'))
279
		fatal_lang_error('packageget_unable', false, array($url . '/index.php'));
280
281
	// List out the packages...
282
	$context['package_list'] = array();
283
284
	$listing = $listing->path('package-list[0]');
285
286
	// Use the package list's name if it exists.
287
	if ($listing->exists('list-title'))
288
		$name = $smcFunc['htmlspecialchars']($listing->fetch('list-title'));
289
290
	// Pick the correct template.
291
	$context['sub_template'] = 'package_list';
292
293
	$context['page_title'] = $txt['package_servers'] . ($name != '' ? ' - ' . $name : '');
0 ignored issues
show
Bug introduced by
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...
294
	$context['package_server'] = $server;
0 ignored issues
show
Bug introduced by
The variable $server 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...
295
296
	// By default we use an unordered list, unless there are no lists with more than one package.
297
	$context['list_type'] = 'ul';
298
299
	$instmods = loadInstalledPackages();
300
301
	$installed_mods = array();
302
	// Look through the list of installed mods...
303
	foreach ($instmods as $installed_mod)
304
		$installed_mods[$installed_mod['package_id']] = $installed_mod['version'];
305
306
	// Get default author and email if they exist.
307
	if ($listing->exists('default-author'))
308
	{
309
		$default_author = $smcFunc['htmlspecialchars']($listing->fetch('default-author'));
310
		if ($listing->exists('default-author/@email') && filter_var($listing->fetch('default-author/@email'), FILTER_VALIDATE_EMAIL))
311
			$default_email = $smcFunc['htmlspecialchars']($listing->fetch('default-author/@email'));
312
	}
313
314
	// Get default web site if it exists.
315 View Code Duplication
	if ($listing->exists('default-website'))
316
	{
317
		$default_website = $smcFunc['htmlspecialchars']($listing->fetch('default-website'));
318
		if ($listing->exists('default-website/@title'))
319
			$default_title = $smcFunc['htmlspecialchars']($listing->fetch('default-website/@title'));
320
	}
321
322
	$the_version = strtr($forum_version, array('SMF ' => ''));
323
	if (!empty($_SESSION['version_emulate']))
324
		$the_version = $_SESSION['version_emulate'];
325
326
	$packageNum = 0;
327
	$packageSection = 0;
328
329
	$sections = $listing->set('section');
330
	foreach ($sections as $i => $section)
331
	{
332
		$context['package_list'][$packageSection] = array(
333
			'title' => '',
334
			'text' => '',
335
			'items' => array(),
336
		);
337
338
		$packages = $section->set('title|heading|text|remote|rule|modification|language|avatar-pack|theme|smiley-set');
339
		foreach ($packages as $thisPackage)
340
		{
341
			$package = array(
342
				'type' => $thisPackage->name(),
343
			);
344
345
			if (in_array($package['type'], array('title', 'text')))
346
				$context['package_list'][$packageSection][$package['type']] = $smcFunc['htmlspecialchars']($thisPackage->fetch('.'));
347
			// It's a Title, Heading, Rule or Text.
348
			elseif (in_array($package['type'], array('heading', 'rule')))
349
				$package['name'] = $smcFunc['htmlspecialchars']($thisPackage->fetch('.'));
350
			// It's a Remote link.
351
			elseif ($package['type'] == 'remote')
352
			{
353
				$remote_type = $thisPackage->exists('@type') ? $thisPackage->fetch('@type') : 'relative';
354
355
				if ($remote_type == 'relative' && substr($thisPackage->fetch('@href'), 0, 7) != 'http://' && substr($thisPackage->fetch('@href'), 0, 8) != 'https://')
356
				{
357 View Code Duplication
					if (isset($_GET['absolute']))
358
						$current_url = $_GET['absolute'] . '/';
359
					elseif (isset($_GET['relative']))
360
						$current_url = $_GET['relative'] . '/';
361
					else
362
						$current_url = '';
363
364
					$current_url .= $thisPackage->fetch('@href');
365
					if (isset($_GET['absolute']))
366
						$package['href'] = $scripturl . '?action=admin;area=packages;get;sa=browse;absolute=' . $current_url;
367
					else
368
						$package['href'] = $scripturl . '?action=admin;area=packages;get;sa=browse;server=' . $context['package_server'] . ';relative=' . $current_url;
369
				}
370
				else
371
				{
372
					$current_url = $thisPackage->fetch('@href');
373
					$package['href'] = $scripturl . '?action=admin;area=packages;get;sa=browse;absolute=' . $current_url;
374
				}
375
376
				$package['name'] = $smcFunc['htmlspecialchars']($thisPackage->fetch('.'));
377
				$package['link'] = '<a href="' . $package['href'] . '">' . $package['name'] . '</a>';
378
			}
379
			// It's a package...
380
			else
381
			{
382 View Code Duplication
				if (isset($_GET['absolute']))
383
					$current_url = $_GET['absolute'] . '/';
384
				elseif (isset($_GET['relative']))
385
					$current_url = $_GET['relative'] . '/';
386
				else
387
					$current_url = '';
388
389
				$server_att = $server != '' ? ';server=' . $server : '';
390
391
				$package += $thisPackage->to_array();
392
393
				if (isset($package['website']))
394
					unset($package['website']);
395
				$package['author'] = array();
396
397
				if ($package['description'] == '')
398
					$package['description'] = $txt['package_no_description'];
399
				else
400
					$package['description'] = parse_bbc(preg_replace('~\[[/]?html\]~i', '', $smcFunc['htmlspecialchars']($package['description'])));
401
402
				$package['is_installed'] = isset($installed_mods[$package['id']]);
403
				$package['is_current'] = $package['is_installed'] && ($installed_mods[$package['id']] == $package['version']);
404
				$package['is_newer'] = $package['is_installed'] && ($installed_mods[$package['id']] > $package['version']);
405
406
				// This package is either not installed, or installed but old.  Is it supported on this version of SMF?
407
				if (!$package['is_installed'] || (!$package['is_current'] && !$package['is_newer']))
408
				{
409
					if ($thisPackage->exists('version/@for'))
410
						$package['can_install'] = matchPackageVersion($the_version, $thisPackage->fetch('version/@for'));
411
				}
412
				// Okay, it's already installed AND up to date.
413
				else
414
					$package['can_install'] = false;
415
416
				$already_exists = getPackageInfo(basename($package['filename']));
417
				$package['download_conflict'] = is_array($already_exists) && $already_exists['id'] == $package['id'] && $already_exists['version'] != $package['version'];
418
419
				$package['href'] = $url . '/' . $package['filename'];
420
				$package['link'] = '<a href="' . $package['href'] . '">' . $package['name'] . '</a>';
421
				$package['download']['href'] = $scripturl . '?action=admin;area=packages;get;sa=download' . $server_att . ';package=' . $current_url . $package['filename'] . ($package['download_conflict'] ? ';conflict' : '') . ';' . $context['session_var'] . '=' . $context['session_id'];
422
				$package['download']['link'] = '<a href="' . $package['download']['href'] . '">' . $package['name'] . '</a>';
423
424
				if ($thisPackage->exists('author') || isset($default_author))
425
				{
426
					if ($thisPackage->exists('author/@email') && filter_var($thisPackage->fetch('author/@email'), FILTER_VALIDATE_EMAIL))
427
						$package['author']['email'] = $thisPackage->fetch('author/@email');
428
					elseif (isset($default_email))
429
						$package['author']['email'] = $default_email;
430
431
					if ($thisPackage->exists('author') && $thisPackage->fetch('author') != '')
432
						$package['author']['name'] = $smcFunc['htmlspecialchars']($thisPackage->fetch('author'));
433
					else
434
						$package['author']['name'] = $default_author;
0 ignored issues
show
Bug introduced by
The variable $default_author 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...
435
436
					if (!empty($package['author']['email']))
437
						$package['author']['link'] = '<a href="mailto:' . $package['author']['email'] . '">' . $package['author']['name'] . '</a>';
438
				}
439
440
				if ($thisPackage->exists('website') || isset($default_website))
441
				{
442
					if ($thisPackage->exists('website') && $thisPackage->exists('website/@title'))
443
						$package['author']['website']['name'] = $smcFunc['htmlspecialchars']($thisPackage->fetch('website/@title'));
444
					elseif (isset($default_title))
445
						$package['author']['website']['name'] = $default_title;
446
					elseif ($thisPackage->exists('website'))
447
						$package['author']['website']['name'] = $smcFunc['htmlspecialchars']($thisPackage->fetch('website'));
448
					else
449
						$package['author']['website']['name'] = $default_website;
0 ignored issues
show
Bug introduced by
The variable $default_website 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...
450
451 View Code Duplication
					if ($thisPackage->exists('website') && $thisPackage->fetch('website') != '')
452
						$authorhompage = $smcFunc['htmlspecialchars']($thisPackage->fetch('website'));
453
					else
454
						$authorhompage = $default_website;
455
456
					$package['author']['website']['href'] = $authorhompage;
457
					$package['author']['website']['link'] = '<a href="' . $authorhompage . '">' . $package['author']['website']['name'] . '</a>';
458
				}
459
				else
460
				{
461
					$package['author']['website']['href'] = '';
462
					$package['author']['website']['link'] = '';
463
				}
464
			}
465
466
			$package['is_remote'] = $package['type'] == 'remote';
467
			$package['is_title'] = $package['type'] == 'title';
468
			$package['is_heading'] = $package['type'] == 'heading';
469
			$package['is_text'] = $package['type'] == 'text';
470
			$package['is_line'] = $package['type'] == 'rule';
471
472
			$packageNum = in_array($package['type'], array('title', 'heading', 'text', 'remote', 'rule')) ? 0 : $packageNum + 1;
473
			$package['count'] = $packageNum;
474
475
			if (!in_array($package['type'], array('title', 'text')))
476
				$context['package_list'][$packageSection]['items'][] = $package;
477
478
			if ($package['count'] > 1)
479
				$context['list_type'] = 'ol';
480
		}
481
482
		$packageSection++;
483
	}
484
485
	// Lets make sure we get a nice new spiffy clean $package to work with.  Otherwise we get PAIN!
486
	unset($package);
487
488
	foreach ($context['package_list'] as $ps_id => $packageSection)
489
	{
490
		foreach ($packageSection['items'] as $i => $package)
491
		{
492
			if ($package['count'] == 0 || isset($package['can_install']))
493
				continue;
494
495
			$context['package_list'][$ps_id]['items'][$i]['can_install'] = false;
496
497
			$packageInfo = getPackageInfo($url . '/' . $package['filename']);
498
			if (is_array($packageInfo) && $packageInfo['xml']->exists('install'))
499
			{
500
				$installs = $packageInfo['xml']->set('install');
501
				foreach ($installs as $install)
502
				{
503
					if (!$install->exists('@for') || matchPackageVersion($the_version, $install->fetch('@for')))
504
					{
505
						// Okay, this one is good to go.
506
						$context['package_list'][$ps_id]['items'][$i]['can_install'] = true;
507
						break;
508
					}
509
510
					// no install found for this version, lets see if one exists for another
511
					if ($context['package_list'][$ps_id]['items'][$i]['can_install'] === false && $install->exists('@for'))
512
					{
513
						$reset = true;
514
515
						// Get the highest install version that is available from the package
516
						foreach ($installs as $install)
517
						{
518
							$context['package_list'][$ps_id]['items'][$i]['can_emulate_install'] = matchHighestPackageVersion($install->fetch('@for'), $reset, $the_version);
519
							$reset = false;
520
						}
521
					}
522
				}
523
			}
524
		}
525
	}
526
}
527
528
/**
529
 * Download a package.
530
 */
531
function PackageDownload()
532
{
533
	global $txt, $scripturl, $context, $packagesdir, $smcFunc;
534
535
	// Use the downloaded sub template.
536
	$context['sub_template'] = 'downloaded';
537
538
	// Security is good...
539
	checkSession('get');
540
541
	// To download something, we need a valid server or url.
542
	if (empty($_GET['server']) && (!empty($_GET['get']) && !empty($_REQUEST['package'])))
543
		fatal_lang_error('package_get_error_is_zero', false);
544
545
	if (isset($_GET['server']))
546
	{
547
		$server = (int) $_GET['server'];
548
549
		// Query the server table to find the requested server.
550
		$request = $smcFunc['db_query']('', '
551
			SELECT name, url
552
			FROM {db_prefix}package_servers
553
			WHERE id_server = {int:current_server}
554
			LIMIT 1',
555
			array(
556
				'current_server' => $server,
557
			)
558
		);
559
		list ($name, $url) = $smcFunc['db_fetch_row']($request);
0 ignored issues
show
Unused Code introduced by
The assignment to $name is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
560
		$smcFunc['db_free_result']($request);
561
562
		// If server does not exist then dump out.
563
		if (empty($url))
564
			fatal_lang_error('couldnt_connect', false);
565
566
		$url = $url . '/';
567
	}
568
	else
569
	{
570
		// Initialize the requried variables.
571
		$server = '';
572
		$url = '';
573
	}
574
575
	if (isset($_REQUEST['byurl']) && !empty($_POST['filename']))
576
		$package_name = basename($_REQUEST['filename']);
577
	else
578
		$package_name = basename($_REQUEST['package']);
579
580
	if (isset($_REQUEST['conflict']) || (isset($_REQUEST['auto']) && file_exists($packagesdir . '/' . $package_name)))
581
	{
582
		// Find the extension, change abc.tar.gz to abc_1.tar.gz...
583
		if (strrpos(substr($package_name, 0, -3), '.') !== false)
584
		{
585
			$ext = substr($package_name, strrpos(substr($package_name, 0, -3), '.'));
586
			$package_name = substr($package_name, 0, strrpos(substr($package_name, 0, -3), '.')) . '_';
587
		}
588
		else
589
			$ext = '';
590
591
		// Find the first available.
592
		$i = 1;
593
		while (file_exists($packagesdir . '/' . $package_name . $i . $ext))
594
			$i++;
595
596
		$package_name = $package_name . $i . $ext;
597
	}
598
599
	// Use FTP if necessary.
600
	create_chmod_control(array($packagesdir . '/' . $package_name), array('destination_url' => $scripturl . '?action=admin;area=packages;get;sa=download' . (isset($_GET['server']) ? ';server=' . $_GET['server'] : '') . (isset($_REQUEST['auto']) ? ';auto' : '') . ';package=' . $_REQUEST['package'] . (isset($_REQUEST['conflict']) ? ';conflict' : '') . ';' . $context['session_var'] . '=' . $context['session_id'], 'crash_on_error' => true));
601
	package_put_contents($packagesdir . '/' . $package_name, fetch_web_data($url . $_REQUEST['package']));
0 ignored issues
show
Security Bug introduced by
It seems like fetch_web_data($url . $_REQUEST['package']) targeting fetch_web_data() can also be of type false; however, package_put_contents() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
602
603
	// Done!  Did we get this package automatically?
604
	// @ TODO: These are usually update packages.  Allowing both for now until more testing has been done.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
605
	if (preg_match('~^https?://[\w_\-]+\.simplemachines\.org/~', $_REQUEST['package']) == 1 && strpos($_REQUEST['package'], 'dlattach') === false && isset($_REQUEST['auto']))
606
		redirectexit('action=admin;area=packages;sa=install;package=' . $package_name);
607
608
	// You just downloaded a mod from SERVER_NAME_GOES_HERE.
609
	$context['package_server'] = $server;
610
611
	$context['package'] = getPackageInfo($package_name);
612
613
	if (!is_array($context['package']))
614
		fatal_lang_error('package_cant_download', false);
615
616 View Code Duplication
	if ($context['package']['type'] == 'modification')
617
		$context['package']['install']['link'] = '<a href="' . $scripturl . '?action=admin;area=packages;sa=install;package=' . $context['package']['filename'] . '">[ ' . $txt['install_mod'] . ' ]</a>';
618
	elseif ($context['package']['type'] == 'avatar')
619
		$context['package']['install']['link'] = '<a href="' . $scripturl . '?action=admin;area=packages;sa=install;package=' . $context['package']['filename'] . '">[ ' . $txt['use_avatars'] . ' ]</a>';
620
	elseif ($context['package']['type'] == 'language')
621
		$context['package']['install']['link'] = '<a href="' . $scripturl . '?action=admin;area=packages;sa=install;package=' . $context['package']['filename'] . '">[ ' . $txt['add_languages'] . ' ]</a>';
622
	else
623
		$context['package']['install']['link'] = '';
624
625
	// Does a 3rd party hook want to do some additional changes?
626
	call_integration_hook('integrate_package_download');
627
628
	$context['package']['list_files']['link'] = '<a href="' . $scripturl . '?action=admin;area=packages;sa=list;package=' . $context['package']['filename'] . '">[ ' . $txt['list_files'] . ' ]</a>';
629
630
	// Free a little bit of memory...
631
	unset($context['package']['xml']);
632
633
	$context['page_title'] = $txt['download_success'];
634
}
635
636
/**
637
 * Upload a new package to the directory.
638
 */
639
function PackageUpload()
640
{
641
	global $txt, $scripturl, $context, $packagesdir;
642
643
	// Setup the correct template, even though I'll admit we ain't downloading ;)
644
	$context['sub_template'] = 'downloaded';
645
	$allowext = array('.zip','.tgz','.gz');
646
	// @todo Use FTP if the Packages directory is not writable.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
647
648
	// Check the file was even sent!
649
	if (!isset($_FILES['package']['name']) || $_FILES['package']['name'] == '')
650
		fatal_lang_error('package_upload_error_nofile');
651 View Code Duplication
	elseif (!is_uploaded_file($_FILES['package']['tmp_name']) || (ini_get('open_basedir') == '' && !file_exists($_FILES['package']['tmp_name'])))
652
		fatal_lang_error('package_upload_error_failed');
653
654
	// Make sure it has a sane filename.
655
	$_FILES['package']['name'] = preg_replace(array('/\s/', '/\.[\.]+/', '/[^\w_\.\-]/'), array('_', '.', ''), $_FILES['package']['name']);
656
	$extension = substr(strrchr(strtolower($_FILES['package']['name']), '.'), 0);
657
	if(!in_array($extension, $allowext))
658
	{
659
		fatal_lang_error('package_upload_error_supports', false, array('zip, tgz, tar.gz'));
660
	}
661
662
	// We only need the filename...
663
	$extension = ($extension == '.gz') ? '.tar.gz' : $extension ;
664
	$packageName = time() . $extension;
665
666
	// Setup the destination and throw an error if the file is already there!
667
	$destination = $packagesdir . '/' . $packageName;
668
	// @todo Maybe just roll it like we do for downloads?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
669
	if (file_exists($destination))
670
		fatal_lang_error('package_upload_error_exists');
671
672
	// Now move the file.
673
	move_uploaded_file($_FILES['package']['tmp_name'], $destination);
674
	smf_chmod($destination, 0777);
675
676
	// If we got this far that should mean it's available.
677
	$context['package'] = getPackageInfo($packageName);
678
	$context['package_server'] = '';
679
680
	// Not really a package, you lazy bum!
681
	if (!is_array($context['package']))
682
	{
683
		@unlink($destination);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
684
		loadLanguage('Errors');
685
		$txt[$context['package']] = str_replace('{MANAGETHEMEURL}', $scripturl . '?action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id'] . '#theme_install', $txt[$context['package']]);
686
		fatal_lang_error('package_upload_error_broken', false, $txt[$context['package']]);
687
	}
688
	// Is it already uploaded, maybe?
689
	elseif ($dir = @opendir($packagesdir))
690
	{
691
		while ($package = readdir($dir))
692
		{
693 View Code Duplication
			if ($package == '.' || $package == '..' || $package == 'temp' || $package == $packageName || (!(is_dir($packagesdir . '/' . $package) && file_exists($packagesdir . '/' . $package . '/package-info.xml')) && substr(strtolower($package), -7) != '.tar.gz' && substr(strtolower($package), -4) != '.tgz' && substr(strtolower($package), -4) != '.zip'))
694
				continue;
695
696
			$packageInfo = getPackageInfo($package);
697
			if (!is_array($packageInfo))
698
				continue;
699
700
			if ($packageInfo['id'] == $context['package']['id'] && $packageInfo['version'] == $context['package']['version'])
701
			{
702
				@unlink($destination);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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

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

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
703
				loadLanguage('Errors');
704
				fatal_lang_error('package_upload_error_exists');
705
			}
706
		}
707
		closedir($dir);
708
	}
709
710 View Code Duplication
	if ($context['package']['type'] == 'modification')
711
		$context['package']['install']['link'] = '<a href="' . $scripturl . '?action=admin;area=packages;sa=install;package=' . $context['package']['filename'] . '">[ ' . $txt['install_mod'] . ' ]</a>';
712
	elseif ($context['package']['type'] == 'avatar')
713
		$context['package']['install']['link'] = '<a href="' . $scripturl . '?action=admin;area=packages;sa=install;package=' . $context['package']['filename'] . '">[ ' . $txt['use_avatars'] . ' ]</a>';
714
	elseif ($context['package']['type'] == 'language')
715
		$context['package']['install']['link'] = '<a href="' . $scripturl . '?action=admin;area=packages;sa=install;package=' . $context['package']['filename'] . '">[ ' . $txt['add_languages'] . ' ]</a>';
716
	else
717
		$context['package']['install']['link'] = '';
718
719
	// Does a 3rd party hook want to do some additional changes?
720
	call_integration_hook('integrate_package_upload');
721
722
	$context['package']['list_files']['link'] = '<a href="' . $scripturl . '?action=admin;area=packages;sa=list;package=' . $context['package']['filename'] . '">[ ' . $txt['list_files'] . ' ]</a>';
723
724
	unset($context['package']['xml']);
725
726
	$context['page_title'] = $txt['package_uploaded_success'];
727
}
728
729
/**
730
 * Add a package server to the list.
731
 */
732
function PackageServerAdd()
733
{
734
	global $smcFunc;
735
736
	// Validate the user.
737
	checkSession();
738
739
	// If they put a slash on the end, get rid of it.
740
	if (substr($_POST['serverurl'], -1) == '/')
741
		$_POST['serverurl'] = substr($_POST['serverurl'], 0, -1);
742
743
	// Are they both nice and clean?
744
	$servername = trim($smcFunc['htmlspecialchars']($_POST['servername']));
745
	$serverurl = trim($smcFunc['htmlspecialchars']($_POST['serverurl']));
746
747
	// Make sure the URL has the correct prefix.
748
	if (strpos($serverurl, 'http://') !== 0 && strpos($serverurl, 'https://') !== 0)
749
		$serverurl = 'http://' . $serverurl;
750
751
	$smcFunc['db_insert']('',
752
		'{db_prefix}package_servers',
753
		array(
754
			'name' => 'string-255', 'url' => 'string-255',
755
		),
756
		array(
757
			$servername, $serverurl,
758
		),
759
		array('id_server')
760
	);
761
762
	redirectexit('action=admin;area=packages;get');
763
}
764
765
/**
766
 * Remove a server from the list.
767
 */
768
function PackageServerRemove()
769
{
770
	global $smcFunc;
771
772
	checkSession('get');
773
774
	$smcFunc['db_query']('', '
775
		DELETE FROM {db_prefix}package_servers
776
		WHERE id_server = {int:current_server}',
777
		array(
778
			'current_server' => (int) $_GET['server'],
779
		)
780
	);
781
782
	redirectexit('action=admin;area=packages;get');
783
}
784
785
?>