Completed
Branch development (176841)
by Elk
06:59
created

Language.subs.php ➔ cleanLangString()   F

Complexity

Conditions 47
Paths 397

Size

Total Lines 202

Duplication

Lines 56
Ratio 27.72 %

Code Coverage

Tests 0
CRAP Score 2256

Importance

Changes 0
Metric Value
cc 47
nc 397
nop 2
dl 56
loc 202
rs 0.6966
c 0
b 0
f 0
ccs 0
cts 139
cp 0
crap 2256

How to fix   Long Method    Complexity   

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 contains the database work for languages.
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * @version 2.0 dev
11
 *
12
 */
13
14
/**
15
 * Removes the given language from all members..
16
 *
17
 * @package Languages
18
 * @param int $lang_id
19
 */
20
function removeLanguageFromMember($lang_id)
21
{
22
	$db = database();
23
24
	$db->query('', '
25
		UPDATE {db_prefix}members
26
		SET lngfile = {string:empty_string}
27
		WHERE lngfile = {string:current_language}',
28
		array(
29
			'empty_string' => '',
30
			'current_language' => $lang_id,
31
		)
32
	);
33
}
34
35
/**
36
 * How many languages?
37
 *
38
 * - Callback for the list in action_edit().
39
 *
40
 * @package Languages
41
 */
42
function list_getNumLanguages()
43
{
44
	return count(getLanguages());
45
}
46
47
/**
48
 * Fetch the actual language information.
49
 *
50
 * What it does:
51
 *
52
 * - Callback for $listOptions['get_items']['function'] in action_edit.
53
 * - Determines which languages are available by looking for the "index.{language}.php" file.
54
 * - Also figures out how many users are using a particular language.
55
 *
56
 * @package Languages
57
 */
58
function list_getLanguages()
59
{
60
	global $settings, $language, $txt;
61
62
	$db = database();
63
64
	$languages = array();
65
	// Keep our old entries.
66
	$old_txt = $txt;
67
	$backup_actual_theme_dir = $settings['actual_theme_dir'];
68
	$backup_base_theme_dir = !empty($settings['base_theme_dir']) ? $settings['base_theme_dir'] : '';
69
70
	// Override these for now.
71
	$settings['actual_theme_dir'] = $settings['base_theme_dir'] = $settings['default_theme_dir'];
72
	$all_languages = getLanguages();
73
74
	// Put them back.
75
	$settings['actual_theme_dir'] = $backup_actual_theme_dir;
76
	if (!empty($backup_base_theme_dir))
77
		$settings['base_theme_dir'] = $backup_base_theme_dir;
78
	else
79
		unset($settings['base_theme_dir']);
80
81
	// Get the language files and data...
82
	foreach ($all_languages as $lang)
83
	{
84
		// Load the file to get the character set.
85
		require($lang['location']);
86
87
		$languages[$lang['filename']] = array(
88
			'id' => $lang['filename'],
89
			'count' => 0,
90
			'char_set' => 'UTF-8',
91
			'default' => $language == $lang['filename'] || ($language == '' && $lang['filename'] == 'english'),
92
			'locale' => $txt['lang_locale'],
93
			'name' => \ElkArte\Util::ucwords(strtr($lang['filename'], array('_' => ' ', '-utf8' => ''))),
94
		);
95
	}
96
97
	// Work out how many people are using each language.
98
	$request = $db->query('', '
99
		SELECT lngfile, COUNT(*) AS num_users
100
		FROM {db_prefix}members
101
		GROUP BY lngfile',
102
		array(
103
		)
104
	);
105
	while ($row = $db->fetch_assoc($request))
106
	{
107
		// Default?
108
		if (empty($row['lngfile']) || !isset($languages[$row['lngfile']]))
109
			$row['lngfile'] = $language;
110
111
		if (!isset($languages[$row['lngfile']]) && isset($languages['english']))
112
			$languages['english']['count'] += $row['num_users'];
113
		elseif (isset($languages[$row['lngfile']]))
114
			$languages[$row['lngfile']]['count'] += $row['num_users'];
115
	}
116
	$db->free_result($request);
117
118
	// Restore the current users language.
119
	$txt = $old_txt;
120
121
	// Return how many we have.
122
	return $languages;
123
}
124
125
/**
126
 * This function cleans language entries to/from display.
127
 *
128
 * @package Languages
129
 *
130
 * @param string $string
131
 * @param boolean $to_display
132
 *
133
 * @return null|string|string[]
134
 */
135
function cleanLangString($string, $to_display = true)
136
{
137
	// If going to display we make sure it doesn't have any HTML in it - etc.
138
	$new_string = '';
139
	if ($to_display)
140
	{
141
		// Are we in a string (0 = no, 1 = single quote, 2 = parsed)
142
		$in_string = 0;
143
		$is_escape = false;
144
		$str_len = strlen($string);
145
		for ($i = 0; $i < $str_len; $i++)
146
		{
147
			// Handle escapes first.
148
			if ($string[$i] == '\\')
149
			{
150
				// Toggle the escape.
151
				$is_escape = !$is_escape;
152
153
				// If we're now escaped don't add this string.
154
				if ($is_escape)
155
					continue;
156
			}
157
			// Special case - parsed string with line break etc?
158
			elseif (($string[$i] == 'n' || $string[$i] == 't') && $in_string == 2 && $is_escape)
159
			{
160
				// Put the escape back...
161
				$new_string .= $string[$i] == 'n' ? "\n" : "\t";
162
				$is_escape = false;
163
				continue;
164
			}
165
			// Have we got a single quote?
166 View Code Duplication
			elseif ($string[$i] == '\'')
167
			{
168
				// Already in a parsed string, or escaped in a linear string, means we print it - otherwise something special.
169
				if ($in_string != 2 && ($in_string != 1 || !$is_escape))
170
				{
171
					// Is it the end of a single quote string?
172
					if ($in_string == 1)
173
						$in_string = 0;
174
					// Otherwise it's the start!
175
					else
176
						$in_string = 1;
177
178
					// Don't actually include this character!
179
					continue;
180
				}
181
			}
182
			// Otherwise a double quote?
183 View Code Duplication
			elseif ($string[$i] == '"')
184
			{
185
				// Already in a single quote string, or escaped in a parsed string, means we print it - otherwise something special.
186
				if ($in_string != 1 && ($in_string != 2 || !$is_escape))
187
				{
188
					// Is it the end of a double quote string?
189
					if ($in_string == 2)
190
						$in_string = 0;
191
					// Otherwise it's the start!
192
					else
193
						$in_string = 2;
194
195
					// Don't actually include this character!
196
					continue;
197
				}
198
			}
199
			// A join/space outside of a string is simply removed.
200
			elseif ($in_string == 0 && (empty($string[$i]) || $string[$i] == '.'))
201
				continue;
202
			// Start of a variable?
203
			elseif ($in_string == 0 && $string[$i] == '$')
204
			{
205
				// Find the whole of it!
206
				preg_match('~([\$A-Za-z0-9\'\[\]_-]+)~', substr($string, $i), $matches);
207
				if (!empty($matches[1]))
208
				{
209
					// Come up with some pseudo thing to indicate this is a var.
210
					// @todo Do better than this, please!
211
					$new_string .= '{%' . $matches[1] . '%}';
212
213
					// We're not going to re-parse this.
214
					$i += strlen($matches[1]) - 1;
215
				}
216
217
				continue;
218
			}
219
			// Right, if we're outside of a string we have DANGER, DANGER!
220
			elseif ($in_string == 0)
221
			{
222
				continue;
223
			}
224
225
			// Actually add the character to the string!
226
			$new_string .= $string[$i];
227
228
			// If anything was escaped it ain't any longer!
229
			$is_escape = false;
230
		}
231
232
		// Un-html then re-html the whole thing!
233
		$new_string = \ElkArte\Util::htmlspecialchars(un_htmlspecialchars($new_string));
234
	}
235
	else
236
	{
237
		// Keep track of what we're doing...
238
		$in_string = 0;
239
240
		// This is for deciding whether to HTML a quote.
241
		$in_html = false;
242
		$str_len = strlen($string);
243
		for ($i = 0; $i < $str_len; $i++)
244
		{
245
			// We don't do parsed strings apart from for breaks.
246
			if ($in_string == 2)
247
			{
248
				$in_string = 0;
249
				$new_string .= '"';
250
			}
251
252
			// Not in a string yet?
253
			if ($in_string != 1)
254
			{
255
				$in_string = 1;
256
				$new_string .= ($new_string ? ' . ' : '') . '\'';
257
			}
258
259
			// Is this a variable?
260
			if ($string[$i] == '{' && $string[$i + 1] == '%' && $string[$i + 2] == '$')
261
			{
262
				// Grab the variable.
263
				preg_match('~\{%([\$A-Za-z0-9\'\[\]_-]+)%\}~', substr($string, $i), $matches);
264
				if (!empty($matches[1]))
265
				{
266
					if ($in_string == 1)
267
						$new_string .= '\' . ';
268
					elseif ($new_string)
269
						$new_string .= ' . ';
270
271
					$new_string .= $matches[1];
272
					$i += strlen($matches[1]) + 3;
273
					$in_string = 0;
274
				}
275
276
				continue;
277
			}
278
			// Is this a lt sign?
279 View Code Duplication
			elseif ($string[$i] == '<')
280
			{
281
				// Probably HTML?
282
				if ($string[$i + 1] != ' ')
283
					$in_html = true;
284
				// Assume we need an entity...
285
				else
286
				{
287
					$new_string .= '&lt;';
288
					continue;
289
				}
290
			}
291
			// What about gt?
292 View Code Duplication
			elseif ($string[$i] == '>')
293
			{
294
				// Will it be HTML?
295
				if ($in_html)
296
					$in_html = false;
297
				// Otherwise we need an entity...
298
				else
299
				{
300
					$new_string .= '&gt;';
301
					continue;
302
				}
303
			}
304
			// Is it a slash? If so escape it...
305
			if ($string[$i] == '\\')
306
				$new_string .= '\\';
307
			// The infamous double quote?
308
			elseif ($string[$i] == '"')
309
			{
310
				// If we're in HTML we leave it as a quote - otherwise we entity it.
311
				if (!$in_html)
312
				{
313
					$new_string .= '&quot;';
314
					continue;
315
				}
316
			}
317
			// A single quote?
318
			elseif ($string[$i] == '\'')
319
			{
320
				// Must be in a string so escape it.
321
				$new_string .= '\\';
322
			}
323
324
			// Finally add the character to the string!
325
			$new_string .= $string[$i];
326
		}
327
328
		// If we ended as a string then close it off.
329
		if ($in_string == 1)
330
			$new_string .= '\'';
331
		elseif ($in_string == 2)
332
			$new_string .= '"';
333
	}
334
335
	return $new_string;
336
}
337
338
/**
339
 * Gets a list of available languages from the mother ship
340
 *
341
 * - Will return a subset if searching, otherwise all available
342
 *
343
 * @package Languages
344
 * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be null|array? 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...
345
 */
346
function list_getLanguagesList()
347
{
348
	global $context, $txt, $scripturl;
349
350
	// We're going to use this URL.
351
	// @todo no we are not, this needs to be changed - again
352
	$url = 'http://download.elkarte.net/fetch_language.php?version=' . urlencode(strtr(FORUM_VERSION, array('ElkArte ' => '')));
353
354
	// Load the class file and stick it into an array.
355
	$language_list = new \ElkArte\XmlArray(fetch_web_data($url), true);
356
357
	// Check that the site responded and that the language exists.
358
	if (!$language_list->exists('languages'))
359
		$context['langfile_error'] = 'no_response';
360
	elseif (!$language_list->exists('languages/language'))
361
		$context['langfile_error'] = 'no_files';
362
	else
363
	{
364
		$language_list = $language_list->path('languages[0]');
365
		$lang_files = $language_list->set('language');
366
		$languages = array();
367
		foreach ($lang_files as $file)
368
		{
369
			// Were we searching?
370
			if (!empty($context['elk_search_term']) && strpos($file->fetch('name'), \ElkArte\Util::strtolower($context['elk_search_term'])) === false)
371
				continue;
372
373
			$languages[] = array(
374
				'id' => $file->fetch('id'),
375
				'name' => \ElkArte\Util::ucwords($file->fetch('name')),
376
				'version' => $file->fetch('version'),
377
				'utf8' => $txt['yes'],
378
				'description' => $file->fetch('description'),
379
				'install_link' => '<a href="' . $scripturl . '?action=admin;area=languages;sa=downloadlang;did=' . $file->fetch('id') . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . $txt['add_language_elk_install'] . '</a>',
380
			);
381
		}
382
		if (empty($languages))
383
			$context['langfile_error'] = 'no_files';
384
		else
385
			return $languages;
386
	}
387
}
388
389
/**
390
 * Finds installed language files of type lang
391
 *
392
 * @param string $lang
393
 *
394
 * @return array|bool
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
395
 */
396
function findPossiblePackages($lang)
397
{
398
	$db = database();
399
400
	$request = $db->query('', '
401
		SELECT 
402
			id_install, filename
403
		FROM {db_prefix}log_packages
404
		WHERE package_id LIKE {string:contains_lang}
405
			AND install_state = {int:installed}',
406
		array(
407
			'contains_lang' => 'elk_' . $lang . '_contribs:elk_' . $lang . '',
408
			'installed' => 1,
409
		)
410
	);
411
	$file_name = '';
412
	if ($db->num_rows($request) > 0)
413
	{
414
		list ($pid, $file_name) = $db->fetch_row($request);
415
	}
416
	$db->free_result($request);
417
418
	if (!empty($pid))
419
		return array($pid, $file_name);
420
	else
421
		return false;
422
}
423