fix_charset()   F
last analyzed

Complexity

Conditions 27
Paths 239

Size

Total Lines 113
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 756

Importance

Changes 5
Bugs 1 Features 0
Metric Value
cc 27
eloc 53
c 5
b 1
f 0
nc 239
nop 1
dl 0
loc 113
ccs 0
cts 92
cp 0
crap 756
rs 2.8458

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
 * @name      OpenImporter
4
 * @copyright OpenImporter contributors
5
 * @license   BSD https://opensource.org/licenses/BSD-3-Clause
6
 *
7
 * @version 1.0
8
 *
9
 * This file contains code based on:
10
 *
11
 * Simple Machines Forum (SMF)
12
 * copyright:    2011 Simple Machines (http://www.simplemachines.org)
13
 * license:    BSD, See included LICENSE.TXT for terms and conditions.
14
 */
15
16
/**
17
 * Checks if we've passed a time limit.
18
 *
19
 * @param int|null $substep
20
 * @param int $stop_time
21
 *
22
 * @return null
23
 */
24
function pastTime($substep = null, $stop_time = 5)
25
{
26
	global $oi_import, $time_start;
27
28
	if (isset($_GET['substep']) && $_GET['substep'] < $substep)
29
	{
30
		$_GET['substep'] = $substep;
31
	}
32
33
	// Some details for our progress bar
34
	if (isset($oi_import->count->$substep, $_REQUEST['start'], $substep) && $oi_import->count->$substep > 0 && $_REQUEST['start'] > 0)
35
	{
36
		$bar = round($_REQUEST['start'] / $oi_import->count->$substep * 100, 0);
37
	}
38
	else
39
	{
40
		$bar = false;
41
	}
42
43
	@set_time_limit(300);
44
	if (is_callable('apache_reset_timeout'))
45
	{
46
		apache_reset_timeout();
47
	}
48
49
	if (time() - $time_start < $stop_time)
50
	{
51
		return;
52
	}
53
54
	// @todo maybe throw an exception?
55
	$oi_import->template->time_limit($bar, $_SESSION['import_progress'], $_SESSION['import_overall']);
56
	$oi_import->template->footer();
57
58
	exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
59
}
60
61
/**
62
 * Helper function, simple file copy at all
63
 *
64
 * @param string $source
65
 * @param string $destination
66
 *
67
 * @return boolean
68
 */
69
function copy_file($source, $destination)
70
{
71
	create_folders_recursive(dirname($destination));
72
73
	if (is_file($source))
74
	{
75
		copy($source, $destination);
76
77
		return false;
78
	}
79
80
	return true;
81
}
82
83
function copy_dir_recursive($source, $destination)
84
{
85
	// Create the destination tree
86
	$destination = rtrim($destination, '\\/') . DIRECTORY_SEPARATOR;
87
	create_folders_recursive($destination);
88
89
	$source = rtrim($source, '\\/') . DIRECTORY_SEPARATOR;
90
	$dir = opendir($source);
91
92
	// If we can't open the directory ...
93
	if ($dir === false)
94
	{
95
		return;
96
	}
97
98
	while ($file = readdir($dir))
99
	{
100
		if ($file === '.' || $file === '..')
101
		{
102
			continue;
103
		}
104
105
		if (is_dir($source . $file))
106
		{
107
			copy_dir_recursive($source . $file, $destination . $file);
108
		}
109
		else
110
		{
111
			copy($source . $file, $destination . $file);
112
		}
113
	}
114
}
115
116
/**
117
 * Create attachment folders as deep as needed.
118
 *
119
 * @param $path
120
 */
121
function create_folders_recursive($path)
122
{
123
	$parent = dirname($path);
124
125
	if (!file_exists($parent))
126
	{
127
		create_folders_recursive($parent);
128
	}
129
130
	if (!file_exists($path) && !mkdir($path, 0755) && !is_dir($path))
131
	{
132
		throw new \RuntimeException(sprintf('Directory "%s" was not created', $path));
133
	}
134
}
135
136
/**
137
 * Add slashes recursively...
138
 *
139
 * @param array $var
140
 *
141
 * @return string|array
142
 */
143
function addslashes_recursive($var)
144
{
145
	if (!is_array($var))
0 ignored issues
show
introduced by
The condition is_array($var) is always true.
Loading history...
146
	{
147
		return addslashes($var);
148
	}
149
150
	foreach ($var as $k => $v)
151
	{
152
		$var[$k] = addslashes_recursive($v);
153
	}
154
155
	return $var;
156
}
157
158
/**
159
 * Remove slashes recursively...
160
 *
161
 * @param array $var
162
 *
163
 * @return string|array
164
 */
165
function stripslashes_recursive($var, $level = 0)
166
{
167
	if (!is_array($var))
0 ignored issues
show
introduced by
The condition is_array($var) is always true.
Loading history...
168
	{
169
		return stripslashes($var);
170
	}
171
172
	// Reindex the array without slashes, this time.
173
	$new_var = array();
174
175
	// Strip the slashes from every element.
176
	foreach ($var as $k => $v)
177
	{
178
		$new_var[stripslashes($k)] = $level > 25 ? null : stripslashes_recursive($v, $level + 1);
179
	}
180
181
	return $new_var;
182
}
183
184
/**
185
 * Copies a directory
186
 *
187
 * @param string $source
188
 * @param string $destination
189
 *
190
 * @return null
191
 */
192
function copy_dir($source, $destination)
193
{
194
	if (!is_dir($source) || !($dir = opendir($source)))
195
	{
196
		return;
197
	}
198
199
	while ($file = readdir($dir))
200
	{
201
		if ($file === '.' || $file === '..')
202
		{
203
			continue;
204
		}
205
206
		// If we have a directory create it on the destination and copy contents into it!
207
		if (!is_dir($destination) && !mkdir($destination, 0755) && !is_dir($destination))
208
		{
209
			throw new \RuntimeException(sprintf('Directory "%s" was not created', $destination));
210
		}
211
		if (is_dir($source . DIRECTORY_SEPARATOR . $file))
212
		{
213
			copy_dir($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file);
214
		}
215
		else
216
		{
217
218
			copy($source . DIRECTORY_SEPARATOR . $file, $destination . DIRECTORY_SEPARATOR . $file);
219
		}
220
	}
221
222
	closedir($dir);
223
}
224
225
/**
226
 * Detects, if a string is utf-8 or not
227
 *
228
 * @param string $string
229
 *
230
 * @return boolean
231
 */
232
function is_utf8($string)
233
{
234
	return utf8_encode(utf8_decode($string)) === $string;
235
}
236
237
/**
238
 * Function fix based on ForceUTF8 by Sebastián Grignoli <[email protected]>
239
 * @link http://www.framework2.com.ar/dzone/forceUTF8-es/
240
 * This function leaves UTF8 characters alone, while converting almost all non-UTF8 to UTF8.
241
 *
242
 * It may fail to convert characters to unicode if they fall into one of these scenarios:
243
 *
244
 * 1) when any of these characters:   ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß
245
 *    are followed by any of these:  ("group B")
246
 *                                    ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶•¸¹º»¼½¾¿
247
 * For example:   %ABREPR%C9SENT%C9%BB. «REPRÉSENTÉ»
248
 * The "«" (%AB) character will be converted, but the "É" followed by "»" (%C9%BB)
249
 * is also a valid unicode character, and will be left unchanged.
250
 *
251
 * 2) when any of these: àáâãäåæçèéêëìíîï  are followed by TWO chars from group B,
252
 * 3) when any of these: ðñòó  are followed by THREE chars from group B.
253
 *
254
 * @name fix
255
 *
256
 * @param string|string[] $text Any string.
257
 *
258
 * @return string|string[] The same string, UTF8 encoded
259
 */
260
function fix_charset($text)
261
{
262
	if (is_array($text))
263
	{
264
		foreach ($text as $k => $v)
265
		{
266
			$text[$k] = fix_charset($v);
267
		}
268
269
		return $text;
270
	}
271
	// numeric? There's nothing to do, we simply return our input.
272
	if (is_numeric($text))
273
	{
274
		return $text;
275
	}
276
277
	$max = !empty($text) ? strlen($text) : 0;
278
	$buf = '';
279
280
	for ($i = 0; $i < $max; $i++)
281
	{
282
		$c1 = $text[$i];
283
		if ($c1 >= "\xc0")
284
		{
285
			// Should be converted to UTF8, if it's not UTF8 already
286
			$c2 = $i + 1 >= $max ? "\x00" : $text[$i + 1];
287
			$c3 = $i + 2 >= $max ? "\x00" : $text[$i + 2];
288
			$c4 = $i + 3 >= $max ? "\x00" : $text[$i + 3];
289
			if ($c1 >= "\xc0" & $c1 <= "\xdf")
290
			{
291
				// looks like 2 bytes UTF8
292
				if ($c2 >= "\x80" && $c2 <= "\xbf")
293
				{
294
					// yeah, almost sure it's UTF8 already
295
					$buf .= $c1 . $c2;
296
					$i++;
297
				}
298
				else
299
				{
300
					// not valid UTF8. Convert it.
301
					$cc1 = (chr((int) (ord($c1) / 64)) | "\xc0");
302
					$cc2 = ($c1 & "\x3f") | "\x80";
303
					$buf .= $cc1 . $cc2;
304
				}
305
			}
306
			elseif ($c1 >= "\xe0" & $c1 <= "\xef")
307
			{
308
				// looks like 3 bytes UTF8
309
				if ($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf")
310
				{
311
					// yeah, almost sure it's UTF8 already
312
					$buf .= $c1 . $c2 . $c3;
313
					$i += 2;
314
				}
315
				else
316
				{
317
					// not valid UTF8. Convert it.
318
					$cc1 = (chr((int) (ord($c1) / 64)) | "\xc0");
319
					$cc2 = ($c1 & "\x3f") | "\x80";
320
					$buf .= $cc1 . $cc2;
321
				}
322
			}
323
			elseif ($c1 >= "\xf0" & $c1 <= "\xf7")
324
			{
325
				// Looks like 4-byte UTF8
326
				if ($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf")
327
				{
328
					// Yeah, almost sure it's UTF8 already
329
					$buf .= $c1 . $c2 . $c3;
330
					$i += 2;
331
				}
332
				else
333
				{
334
					// Not valid UTF8. Convert it.
335
					$cc1 = (chr((int) (ord($c1) / 64)) | "\xc0");
336
					$cc2 = ($c1 & "\x3f") | "\x80";
337
					$buf .= $cc1 . $cc2;
338
				}
339
			}
340
			else
341
			{
342
				// Doesn't look like UTF8, but should be converted
343
				$cc1 = (chr((int) (ord($c1) / 64)) | "\xc0");
344
				$cc2 = (($c1 & "\x3f") | "\x80");
345
				$buf .= $cc1 . $cc2;
346
			}
347
		}
348
		elseif (($c1 & "\xc0") === "\x80")
349
		{
350
			// Needs conversion
351
			$cc1 = (chr((int) (ord($c1) / 64)) | "\xc0");
352
			$cc2 = (($c1 & "\x3f") | "\x80");
353
			$buf .= $cc1 . $cc2;
354
		}
355
		else
356
		{
357
			// Doesn't need conversion
358
			$buf .= $c1;
359
		}
360
	}
361
362
	if (function_exists('mb_decode_numericentity'))
363
	{
364
		$buf = mb_decode_numericentity($buf, array(0x80, 0x2ffff, 0, 0xffff), 'UTF-8');
365
	}
366
	else
367
	{
368
		preg_replace_callback('~(&#(\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'replaceEntities__callback', $buf);
369
	}
370
371
	// surprise, surprise... the string
372
	return $buf;
373
}
374
375
/**
376
 * Decode numeric html entities to their UTF8 equivalent character.
377
 *
378
 * What it does:
379
 * - Callback function for preg_replace_callback in subs-members
380
 * - Uses capture group 2 in the supplied array
381
 * - Does basic scan to ensure characters are inside a valid range
382
 *
383
 * @param array $matches matches from a preg_match_all
384
 *
385
 * @return string $string
386
 */
387
function replaceEntities__callback($matches)
388
{
389
	if (!isset($matches[2]))
390
	{
391
		return '';
392
	}
393
394
	$num = $matches[2][0] === 'x' ? hexdec(substr($matches[2], 1)) : (int) $matches[2];
0 ignored issues
show
Bug introduced by
$matches[2] of type array is incompatible with the type string expected by parameter $string of substr(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

394
	$num = $matches[2][0] === 'x' ? hexdec(substr(/** @scrutinizer ignore-type */ $matches[2], 1)) : (int) $matches[2];
Loading history...
395
396
	// Remove left to right / right to left overrides
397
	if ($num === 0x202D || $num === 0x202E)
398
	{
399
		return '';
400
	}
401
402
	// Quote, Ampersand, Apostrophe, Less/Greater Than get html replaced
403
	if (in_array($num, array(0x22, 0x26, 0x27, 0x3C, 0x3E), true))
404
	{
405
		return '&#' . $num . ';';
406
	}
407
408
	// <0x20 are control characters, 0x20 is a space, > 0x10FFFF is past the end of the utf8 character set
409
	// 0xD800 >= $num <= 0xDFFF are surrogate markers (not valid for utf8 text)
410
	if ($num < 0x20 || $num > 0x10FFFF || ($num >= 0xD800 && $num <= 0xDFFF))
411
	{
412
		return '';
413
	}
414
415
	// <0x80 (or less than 128) are standard ascii characters a-z A-Z 0-9 and puncuation
416
	if ($num < 0x80)
417
	{
418
		return chr($num);
0 ignored issues
show
Bug introduced by
It seems like $num can also be of type double; however, parameter $codepoint of chr() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

418
		return chr(/** @scrutinizer ignore-type */ $num);
Loading history...
419
	}
420
421
	// <0x800 (2048)
422
	if ($num < 0x800)
423
	{
424
		return chr(($num >> 6) + 192) . chr(($num & 63) + 128);
425
	}
426
427
	// < 0x10000 (65536)
428
	if ($num < 0x10000)
429
	{
430
		return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
431
	}
432
433
	// <= 0x10FFFF (1114111)
434
	return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128);
435
}
436
437
/**
438
 * Helper function for storing vars that need to be global
439
 *
440
 * @param string $variable
441
 * @param string $value
442
 */
443
function store_global($variable, $value)
444
{
445
	$_SESSION['store_globals'][$variable] = $value;
446
}
447
448
/**
449
 * Output some debug information
450
 *
451
 * @param $val
452
 */
453
function print_dbg($val)
454
{
455
	echo '<pre>';
456
	print_r($val);
457
	echo '</pre>';
458
}
459
460
/**
461
 * Helper function to create an encrypted attachment name
462
 *
463
 * @param string $filename
464
 * @return string
465
 */
466
function createAttachmentFilehash($filename)
467
{
468
	return sha1(md5($filename . time()) . mt_rand());
469
}
470
471
/**
472
 * Used to copy smileys from a source to destination.
473
 *
474
 * @param string $source
475
 * @param string $dest
476
 *
477
 * @return type
478
 */
479
function copy_smileys($source, $dest)
480
{
481
	copy_dir($source, $dest);
482
}
483
484
/**
485
 * Return the attachment extension and mime type
486
 *
487
 * @param string $filename
488
 *
489
 * @return array
490
 */
491
function attachment_type($filename)
492
{
493
	// Is this an image (basic ext sniff)
494
	$path_parts = pathinfo($filename);
495
	$ext = $path_parts['extension'];
496
	$basename = $path_parts['filename'];
497
498
	if (!in_array(strtolower($ext), array('jpg', 'jpeg', 'gif', 'png', 'webp')))
499
	{
500
		$ext = '';
501
		$mime_type = '';
502
	}
503
	elseif (strtolower($ext) === 'jpg')
504
	{
505
		$mime_type = 'image/jpeg';
506
	}
507
	else
508
	{
509
		$mime_type = 'image/' . strtolower($ext);
510
	}
511
512
	return array($ext, $basename, $mime_type);
513
}
514
515
/**
516
 * Convert a binary db value back to a string IP
517
 */
518
function inet_dtop($bin)
519
{
520
	if (empty($bin))
521
	{
522
		return '';
523
	}
524
525
	// Already a String?
526
	$check = filter_var($bin, FILTER_VALIDATE_IP);
527
	if ($check !== false)
528
	{
529
		return $bin;
530
	}
531
532
	return inet_ntop($bin);
533
}
534