Completed
Push — dev ( 0e6173...228dac )
by Darko
10:06
created

Utility   F

Complexity

Total Complexity 130

Size/Duplication

Total Lines 698
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 130
eloc 310
dl 0
loc 698
ccs 0
cts 282
cp 0
rs 2
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A cutStringUsingLast() 0 20 4
A clearScreen() 0 4 2
A hasCommand() 0 5 1
A getThemesList() 0 14 5
A isCLI() 0 3 1
A canExecuteRead() 0 14 5
C getDirFiles() 0 40 12
A isGZipped() 0 14 4
B curlSslContextOptions() 0 22 8
B streamSslContextOptions() 0 25 8
A stripNonPrintingChars() 0 5 1
A unzipGzipFile() 0 19 5
B setCoversConstant() 0 13 10
B objectsIntoArray() 0 23 7
A getCount() 0 5 2
A cp437toUTF() 0 3 1
A getRange() 0 8 2
A responseXmlToObject() 0 5 1
A checkStatus() 0 3 1
F xmlToArray() 0 80 18
A safeFilename() 0 3 1
A fileInfo() 0 17 5
A imdb_trailers() 0 8 3
A getCoverURL() 0 23 4
A htmlfmt() 0 3 1
D showApiError() 0 85 18

How to fix   Complexity   

Complex Class

Complex classes like Utility often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Utility, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Blacklight\utility;
4
5
use App\Models\Settings;
6
use Illuminate\Support\Str;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Support\Facades\File;
9
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
10
11
/**
12
 * Class Utility.
13
 */
14
class Utility
15
{
16
    /**
17
     *  Regex for detecting multi-platform path. Use it where needed so it can be updated in one location as required characters get added.
18
     */
19
    public const PATH_REGEX = '(?P<drive>[A-Za-z]:|)(?P<path>[/\w.-]+|)';
20
21
    public const VERSION_REGEX = '#(?P<all>v(?P<digits>(?P<major>\d+)\.(?P<minor>\d+)\.(?P<revision>\d+)(?:\.(?P<fix>\d+))?)(?:-(?P<suffix>(?:RC\d+|dev)))?)#';
22
23
    /**
24
     * Checks all levels of the supplied path are readable and executable by current user.
25
     *
26
     * @todo Make this recursive with a switch to only check end point.
27
     * @param $path	*nix path to directory or file
28
     *
29
     * @return bool|string True is successful, otherwise the part of the path that failed testing.
30
     */
31
    public static function canExecuteRead($path)
32
    {
33
        $paths = explode('#/#', $path);
34
        $fullPath = DS;
35
        foreach ($paths as $singlePath) {
36
            if ($singlePath !== '') {
37
                $fullPath .= $singlePath.DS;
38
                if (! is_readable($fullPath) || ! is_executable($fullPath)) {
39
                    return "The '$fullPath' directory must be readable and executable by all .".PHP_EOL;
40
                }
41
            }
42
        }
43
44
        return true;
45
    }
46
47
    public static function clearScreen(): void
48
    {
49
        if (self::isCLI()) {
50
            passthru('clear');
51
        }
52
    }
53
54
    /**
55
     * Removes the preceeding or proceeding portion of a string
56
     * relative to the last occurrence of the specified character.
57
     * The character selected may be retained or discarded.
58
     *
59
     * @param string $character      the character to search for.
60
     * @param string $string         the string to search through.
61
     * @param string $side           determines whether text to the left or the right of the character is returned.
62
     *                               Options are: left, or right.
63
     * @param bool   $keep_character determines whether or not to keep the character.
64
     *                               Options are: true, or false.
65
     *
66
     * @return string
67
     */
68
    public static function cutStringUsingLast($character, $string, $side, $keep_character = true): string
69
    {
70
        $offset = ($keep_character ? 1 : 0);
71
        $whole_length = \strlen($string);
72
        $right_length = (\strlen(strrchr($string, $character)) - 1);
73
        $left_length = ($whole_length - $right_length - 1);
74
        switch ($side) {
75
            case 'left':
76
                $piece = substr($string, 0, $left_length + $offset);
77
                break;
78
            case 'right':
79
                $start = (0 - ($right_length + $offset));
80
                $piece = substr($string, $start);
81
                break;
82
            default:
83
                $piece = false;
84
                break;
85
        }
86
87
        return $piece;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $piece could return the type false which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
88
    }
89
90
    /**
91
     * @param array|null $options
92
     *
93
     * @return array|null
94
     */
95
    public static function getDirFiles(array $options = null): ?array
96
    {
97
        $defaults = [
98
            'dir'   => false,
99
            'ext'   => '', // no full stop (period) separator should be used.
100
            'file'    => true,
101
            'path'  => '',
102
            'regex' => '',
103
        ];
104
        $options += $defaults;
105
        if (! $options['dir'] && ! $options['file']) {
106
            return null;
107
        }
108
109
        // Replace windows style path separators with unix style.
110
        $iterator = new \FilesystemIterator(
111
            str_replace('\\', '/', $options['path']),
112
            \FilesystemIterator::KEY_AS_PATHNAME |
113
            \FilesystemIterator::SKIP_DOTS |
114
            \FilesystemIterator::UNIX_PATHS
115
        );
116
117
        $files = [];
118
        foreach ($iterator as $fileInfo) {
119
            $file = $iterator->key();
120
            switch (true) {
121
                case ! $options['dir'] && $fileInfo->isDir():
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
122
                    break;
123
                case ! empty($options['ext']) && $fileInfo->getExtension() !== $options['ext']:
124
                    break;
125
                case empty($options['regex']) || ! preg_match($options['regex'], $file):
126
                    break;
127
                case ! $options['file'] && $fileInfo->isFile():
128
                    break;
129
                default:
130
                    $files[] = $file;
131
            }
132
        }
133
134
        return $files;
135
    }
136
137
    /**
138
     * @return array
139
     */
140
    public static function getThemesList(): array
141
    {
142
        $ignoredThemes = ['admin', 'shared'];
143
        $themes = scandir(base_path().'/resources/views/themes', SCANDIR_SORT_ASCENDING);
0 ignored issues
show
Bug introduced by
Are you sure the usage of base_path() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
144
        $themeList[] = 'None';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$themeList was never initialized. Although not strictly required by PHP, it is generally a good practice to add $themeList = array(); before regardless.
Loading history...
145
        foreach ($themes as $theme) {
146
            if (strpos($theme, '.') === false && ! \in_array($theme, $ignoredThemes, false) && File::isDirectory(base_path().'/resources/views/themes/'.$theme)) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of base_path() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
147
                $themeList[] = $theme;
148
            }
149
        }
150
151
        sort($themeList);
152
153
        return $themeList;
154
    }
155
156
    /**
157
     * Detect if the command is accessible on the system.
158
     *
159
     *
160
     * @param $cmd
161
     *
162
     * @return bool
163
     */
164
    public static function hasCommand($cmd): bool
165
    {
166
        $returnVal = shell_exec("which $cmd");
167
168
        return $returnVal !== null;
169
    }
170
171
    /**
172
     * Check if user is running from CLI.
173
     *
174
     * @return bool
175
     */
176
    public static function isCLI(): bool
177
    {
178
        return strtolower(PHP_SAPI) === 'cli';
179
    }
180
181
    /**
182
     * @param $filename
183
     *
184
     * @return bool|null|string
185
     */
186
    public static function isGZipped($filename)
187
    {
188
        $gzipped = null;
189
        if (($fp = fopen($filename, 'rb')) !== false) {
190
            if (@fread($fp, 2) === "\x1F\x8B") { // this is a gzip'd file
191
                fseek($fp, -4, SEEK_END);
192
                if (\strlen($datum = @fread($fp, 4)) === 4) {
193
                    $gzipped = $datum;
194
                }
195
            }
196
            fclose($fp);
197
        }
198
199
        return $gzipped;
200
    }
201
202
    /**
203
     * Strips non-printing characters from a string.
204
     *
205
     * Operates directly on the text string, but also returns the result for situations requiring a
206
     * return value (use in ternary, etc.)/
207
     *
208
     * @param string $text String variable to strip.
209
     *
210
     * @return string    The stripped variable.
211
     */
212
    public static function stripNonPrintingChars(&$text): string
213
    {
214
        $text = str_replace('/[[:^print:]]/', '', $text);
215
216
        return $text;
217
    }
218
219
    /**
220
     * Unzip a gzip file, return the output. Return false on error / empty.
221
     *
222
     * @param string $filePath
223
     *
224
     * @return bool|string
225
     */
226
    public static function unzipGzipFile($filePath)
227
    {
228
        $string = '';
229
        $gzFile = @gzopen($filePath, 'rb', 0);
230
        if ($gzFile) {
0 ignored issues
show
introduced by
$gzFile is of type resource, thus it always evaluated to false.
Loading history...
231
            while (! gzeof($gzFile)) {
232
                $temp = gzread($gzFile, 1024);
233
                // Check for empty string.
234
                // Without this the loop would be endless and consume 100% CPU.
235
                // Do not set $string empty here, as the data might still be good.
236
                if (! $temp) {
237
                    break;
238
                }
239
                $string .= $temp;
240
            }
241
            gzclose($gzFile);
242
        }
243
244
        return $string === '' ? false : $string;
0 ignored issues
show
introduced by
The condition $string === '' is always true.
Loading history...
245
    }
246
247
    /**
248
     * @param $path
249
     */
250
    public static function setCoversConstant($path): void
251
    {
252
        if (! \defined('NN_COVERS')) {
253
            switch (true) {
254
                case $path[0] === '/' || $path[1] === ':' || $path[0] === '\\':
255
                    \define('NN_COVERS', Str::finish($path, '/'));
256
                    break;
257
                case $path !== '' && $path[0] !== '/' && $path[1] !== ':' && $path[0] !== '\\':
258
                    \define('NN_COVERS', realpath(NN_ROOT.Str::finish($path, '/')));
259
                    break;
260
                case empty($path): // Default to resources location.
261
                default:
262
                    \define('NN_COVERS', NN_RES.'covers/');
263
            }
264
        }
265
    }
266
267
    /**
268
     * Creates an array to be used with stream_context_create() to verify openssl certificates
269
     * when connecting to a tls or ssl connection when using stream functions (fopen/file_get_contents/etc).
270
     *
271
     * @param bool $forceIgnore Force ignoring of verification.
272
     *
273
     * @return array
274
     * @static
275
     */
276
    public static function streamSslContextOptions($forceIgnore = false): array
277
    {
278
        if (config('nntmux_ssl.ssl_cafile') === '' && config('nntmux_ssl.ssl_capath') === '') {
279
            $options = [
280
                'verify_peer'       => false,
281
                'verify_peer_name'  => false,
282
                'allow_self_signed' => true,
283
            ];
284
        } else {
285
            $options = [
286
                'verify_peer'       => $forceIgnore ? false : config('nntmux_ssl.ssl_verify_peer'),
287
                'verify_peer_name'  => $forceIgnore ? false : config('nntmux_ssl.ssl_verify_host'),
288
                'allow_self_signed' => $forceIgnore ? true : config('nntmux_ssl.ssl_allow_self_signed'),
289
            ];
290
            if (config('nntmux_ssl.ssl_cafile') !== '') {
291
                $options['cafile'] = config('nntmux_ssl.ssl_cafile');
292
            }
293
            if (config('nntmux_ssl.ssl_capath') !== '') {
294
                $options['capath'] = config('nntmux_ssl.ssl_capath');
295
            }
296
        }
297
        // If we set the transport to tls and the server falls back to ssl,
298
        // the context options would be for tls and would not apply to ssl,
299
        // so set both tls and ssl context in case the server does not support tls.
300
        return ['tls' => $options, 'ssl' => $options];
301
    }
302
303
    /**
304
     * Set curl context options for verifying SSL certificates.
305
     *
306
     * @param bool $verify false = Ignore config.php and do not verify the openssl cert.
307
     *                     true  = Check config.php and verify based on those settings.
308
     *                     If you know the certificate will be self-signed, pass false.
309
     *
310
     * @return array
311
     * @static
312
     */
313
    public static function curlSslContextOptions($verify = true): array
314
    {
315
        $options = [];
316
        if ($verify && config('nntmux_ssl.ssl_verify_host') && (! empty(config('nntmux_ssl.ssl_cafile')) || ! empty(config('nntmux_ssl.ssl_capath')))) {
317
            $options += [
318
                CURLOPT_SSL_VERIFYPEER => (bool) config('nntmux_ssl.ssl_verify_peer'),
319
                CURLOPT_SSL_VERIFYHOST => config('nntmux_ssl.ssl_verify_host') ? 2 : 0,
320
            ];
321
            if (! empty(config('nntmux_ssl.ssl_cafile'))) {
322
                $options += [CURLOPT_CAINFO => config('nntmux_ssl.ssl_cafile')];
323
            }
324
            if (! empty(config('nntmux_ssl.ssl_capath'))) {
325
                $options += [CURLOPT_CAPATH => config('nntmux_ssl.ssl_capath')];
326
            }
327
        } else {
328
            $options += [
329
                CURLOPT_SSL_VERIFYPEER => false,
330
                CURLOPT_SSL_VERIFYHOST => 0,
331
            ];
332
        }
333
334
        return $options;
335
    }
336
337
    /**
338
     * @param array $options
339
     *
340
     * @return string
341
     */
342
    public static function getCoverURL(array $options = []): string
343
    {
344
        $defaults = [
345
            'id'     => null,
346
            'suffix' => '-cover.jpg',
347
            'type'   => '',
348
        ];
349
        $options += $defaults;
350
        $fileSpecTemplate = '%s/%s%s';
351
        $fileSpec = '';
352
353
        if (! empty($options['id']) && \in_array(
354
            $options['type'],
355
            ['anime', 'audio', 'audiosample', 'book', 'console', 'games', 'movies', 'music', 'preview', 'sample', 'tvrage', 'video', 'xxx'],
356
            false
357
            )
358
        ) {
359
            $fileSpec = sprintf($fileSpecTemplate, $options['type'], $options['id'], $options['suffix']);
360
            $fileSpec = file_exists(NN_COVERS.$fileSpec) ? $fileSpec :
361
                sprintf($fileSpecTemplate, $options['type'], 'no', $options['suffix']);
362
        }
363
364
        return $fileSpec;
365
    }
366
367
    /**
368
     * Converts XML to an associative array with namespace preservation -- use if intending to JSON encode.
369
     * @author Tamlyn from Outlandish.com
370
     *
371
     * @param \SimpleXMLElement $xml The SimpleXML parsed XML string data
372
     * @param array             $options
373
     *
374
     * @return array            The associate array of the XML namespaced file
375
     */
376
    public static function xmlToArray(\SimpleXMLElement $xml, array $options = []): array
377
    {
378
        $defaults = [
379
            'namespaceSeparator' => ':', //you may want this to be something other than a colon
380
            'attributePrefix' => '@',   //to distinguish between attributes and nodes with the same name
381
            'alwaysArray' => [],   //array of xml tag names which should always become arrays
382
            'autoArray' => true,        //only create arrays for tags which appear more than once
383
            'textContent' => '$',       //key used for the text content of elements
384
            'autoText' => true,         //skip textContent key if node has no attributes or child nodes
385
            'keySearch' => false,       //optional search and replace on tag and attribute names
386
            'keyReplace' => false,       //replace values for above search values (as passed to str_replace())
387
        ];
388
        $options = array_merge($defaults, $options);
389
        $namespaces = $xml->getDocNamespaces();
390
        $namespaces[''] = null; //add base (empty) namespace
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% 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...
391
392
        $attributesArray = $tagsArray = [];
393
        foreach ($namespaces as $prefix => $namespace) {
394
            //get attributes from all namespaces
395
            foreach ($xml->attributes($namespace) as $attributeName => $attribute) {
396
                //replace characters in attribute name
397
                if ($options['keySearch']) {
398
                    $attributeName =
399
                    str_replace($options['keySearch'], $options['keyReplace'], $attributeName);
400
                }
401
                $attributeKey = $options['attributePrefix']
402
                    .($prefix ? $prefix.$options['namespaceSeparator'] : '')
403
                    .$attributeName;
404
                $attributesArray[$attributeKey] = (string) $attribute;
405
            }
406
            //get child nodes from all namespaces
407
            foreach ($xml->children($namespace) as $childXml) {
408
                //recurse into child nodes
409
                $childArray = self::xmlToArray($childXml, $options);
410
                $childTagName = key($childArray);
411
                $childProperties = current($childArray);
412
413
                //replace characters in tag name
414
                if ($options['keySearch']) {
415
                    $childTagName =
416
                    str_replace($options['keySearch'], $options['keyReplace'], $childTagName);
417
                }
418
                //add namespace prefix, if any
419
                if ($prefix) {
420
                    $childTagName = $prefix.$options['namespaceSeparator'].$childTagName;
421
                }
422
423
                if (! isset($tagsArray[$childTagName])) {
424
                    //only entry with this key
425
                    //test if tags of this type should always be arrays, no matter the element count
426
                    $tagsArray[$childTagName] =
427
                        \in_array($childTagName, $options['alwaysArray'], false) || ! $options['autoArray']
428
                            ? [$childProperties] : $childProperties;
429
                } elseif (
430
                    \is_array($tagsArray[$childTagName]) && array_keys($tagsArray[$childTagName])
431
                    === range(0, \count($tagsArray[$childTagName]) - 1)
432
                ) {
433
                    //key already exists and is integer indexed array
434
                    $tagsArray[$childTagName][] = $childProperties;
435
                } else {
436
                    //key exists so convert to integer indexed array with previous value in position 0
437
                    $tagsArray[$childTagName] = [$tagsArray[$childTagName], $childProperties];
438
                }
439
            }
440
        }
441
442
        //get text content of node
443
        $textContentArray = [];
444
        $plainText = trim((string) $xml);
445
        if ($plainText !== '') {
446
            $textContentArray[$options['textContent']] = $plainText;
447
        }
448
449
        //stick it all together
450
        $propertiesArray = ! $options['autoText'] || $attributesArray || $tagsArray || ($plainText === '')
451
            ? array_merge($attributesArray, $tagsArray, $textContentArray) : $plainText;
452
453
        //return node as array
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% 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...
454
        return [
455
            $xml->getName() => $propertiesArray,
456
        ];
457
    }
458
459
    /**
460
     * Return file type/info using magic numbers.
461
     * Try using `file` program where available, fallback to using PHP's finfo class.
462
     *
463
     * @param string $path Path to the file / folder to check.
464
     *
465
     * @return string File info. Empty string on failure.
466
     * @throws \Exception
467
     */
468
    public static function fileInfo($path): string
469
    {
470
        $magicPath = Settings::settingValue('apps.indexer.magic_file_path');
471
        if ($magicPath !== null && self::hasCommand('file')) {
472
            $magicSwitch = " -m $magicPath";
473
            $output = runCmd('file'.$magicSwitch.' -b "'.$path.'"');
474
        } else {
475
            $fileInfo = $magicPath === null ? finfo_open(FILEINFO_RAW) : finfo_open(FILEINFO_RAW, $magicPath);
476
477
            $output = finfo_file($fileInfo, $path);
478
            if (empty($output)) {
479
                $output = '';
480
            }
481
            finfo_close($fileInfo);
482
        }
483
484
        return $output;
485
    }
486
487
    /**
488
     * @param $code
489
     *
490
     * @return bool
491
     */
492
    public function checkStatus($code): bool
493
    {
494
        return $code === 0;
495
    }
496
497
    /**
498
     * Convert Code page 437 chars to UTF.
499
     *
500
     * @param string $string
501
     *
502
     * @return string
503
     */
504
    public static function cp437toUTF($string): string
505
    {
506
        return iconv('CP437', 'UTF-8//IGNORE//TRANSLIT', $string);
507
    }
508
509
    /**
510
     * Fetches an embeddable video to a IMDB trailer from http://www.traileraddict.com.
511
     *
512
     * @param $imdbID
513
     *
514
     * @return string
515
     */
516
    public static function imdb_trailers($imdbID): string
517
    {
518
        $xml = getRawHtml('https://api.traileraddict.com/?imdb='.$imdbID);
519
        if ($xml !== false && preg_match('#(v\.traileraddict\.com/\d+)#i', $xml, $html)) {
520
            return $html[1];
521
        }
522
523
        return '';
524
    }
525
526
    /**
527
     * Convert obj to array.
528
     *
529
     * @param       $arrObjData
530
     * @param array $arrSkipIndices
531
     *
532
     * @return array
533
     */
534
    public static function objectsIntoArray($arrObjData, array $arrSkipIndices = []): array
535
    {
536
        $arrData = [];
537
538
        // If input is object, convert into array.
539
        if (\is_object($arrObjData)) {
540
            $arrObjData = get_object_vars($arrObjData);
541
        }
542
543
        if (\is_array($arrObjData)) {
544
            foreach ($arrObjData as $index => $value) {
545
                // Recursive call.
546
                if (\is_object($value) || \is_array($value)) {
547
                    $value = self::objectsIntoArray($value, $arrSkipIndices);
548
                }
549
                if (\in_array($index, $arrSkipIndices, false)) {
550
                    continue;
551
                }
552
                $arrData[$index] = $value;
553
            }
554
        }
555
556
        return $arrData;
557
    }
558
559
    /**
560
     * Remove unsafe chars from a filename.
561
     *
562
     * @param string $filename
563
     *
564
     * @return string
565
     */
566
    public static function safeFilename($filename): string
567
    {
568
        return trim(preg_replace('/[^\w\s.-]*/i', '', $filename));
569
    }
570
571
    /**
572
     * @param $input
573
     *
574
     * @return \SimpleXMLElement
575
     */
576
    public static function responseXmlToObject($input): \SimpleXMLElement
577
    {
578
        $input = str_replace('<newznab:', '<', $input);
579
580
        return @simplexml_load_string($input);
0 ignored issues
show
Bug Best Practice introduced by
The expression return @simplexml_load_string($input) could return the type false which is incompatible with the type-hinted return SimpleXMLElement. Consider adding an additional type-check to rule them out.
Loading history...
581
    }
582
583
    /**
584
     * Display error/error code.
585
     * @param int    $errorCode
586
     * @param string $errorText
587
     */
588
    public static function showApiError($errorCode = 900, $errorText = ''): void
589
    {
590
        $errorHeader = 'HTTP 1.1 400 Bad Request';
591
        if ($errorText === '') {
592
            switch ($errorCode) {
593
                case 100:
594
                    $errorText = 'Incorrect user credentials';
595
                    $errorHeader = 'HTTP 1.1 401 Unauthorized';
596
                    break;
597
                case 101:
598
                    $errorText = 'Account suspended';
599
                    $errorHeader = 'HTTP 1.1 403 Forbidden';
600
                    break;
601
                case 102:
602
                    $errorText = 'Insufficient privileges/not authorized';
603
                    $errorHeader = 'HTTP 1.1 401 Unauthorized';
604
                    break;
605
                case 103:
606
                    $errorText = 'Registration denied';
607
                    $errorHeader = 'HTTP 1.1 403 Forbidden';
608
                    break;
609
                case 104:
610
                    $errorText = 'Registrations are closed';
611
                    $errorHeader = 'HTTP 1.1 403 Forbidden';
612
                    break;
613
                case 105:
614
                    $errorText = 'Invalid registration (Email Address Taken)';
615
                    $errorHeader = 'HTTP 1.1 403 Forbidden';
616
                    break;
617
                case 106:
618
                    $errorText = 'Invalid registration (Email Address Bad Format)';
619
                    $errorHeader = 'HTTP 1.1 403 Forbidden';
620
                    break;
621
                case 107:
622
                    $errorText = 'Registration Failed (Data error)';
623
                    $errorHeader = 'HTTP 1.1 400 Bad Request';
624
                    break;
625
                case 200:
626
                    $errorText = 'Missing parameter';
627
                    $errorHeader = 'HTTP 1.1 400 Bad Request';
628
                    break;
629
                case 201:
630
                    $errorText = 'Incorrect parameter';
631
                    $errorHeader = 'HTTP 1.1 400 Bad Request';
632
                    break;
633
                case 202:
634
                    $errorText = 'No such function';
635
                    $errorHeader = 'HTTP 1.1 404 Not Found';
636
                    break;
637
                case 203:
638
                    $errorText = 'Function not available';
639
                    $errorHeader = 'HTTP 1.1 400 Bad Request';
640
                    break;
641
                case 300:
642
                    $errorText = 'No such item';
643
                    $errorHeader = 'HTTP 1.1 404 Not Found';
644
                    break;
645
                case 500:
646
                    $errorText = 'Request limit reached';
647
                    $errorHeader = 'HTTP 1.1 429 Too Many Requests';
648
                    break;
649
                case 501:
650
                    $errorText = 'Download limit reached';
651
                    $errorHeader = 'HTTP 1.1 429 Too Many Requests';
652
                    break;
653
                case 910:
654
                    $errorText = 'API disabled';
655
                    $errorHeader = 'HTTP 1.1 401 Unauthorized';
656
                    break;
657
                default:
658
                    $errorText = 'Unknown error';
659
                    $errorHeader = 'HTTP 1.1 400 Bad Request';
660
                    break;
661
            }
662
        }
663
664
        $response =
665
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".
666
            '<error code="'.$errorCode.'" description="'.$errorText."\"/>\n";
667
        header('Content-type: text/xml');
668
        header('Content-Length: '.\strlen($response));
669
        header('X-NNTmux: API ERROR ['.$errorCode.'] '.$errorText);
670
        header($errorHeader);
671
672
        exit($response);
673
    }
674
675
    /**
676
     * Simple function to reduce duplication in html string formatting.
677
     *
678
     * @param $string
679
     *
680
     * @return string
681
     */
682
    public static function htmlfmt($string): string
683
    {
684
        return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
685
    }
686
687
    /**
688
     * @param $tableName
689
     *
690
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
691
     */
692
    public static function getRange($tableName): LengthAwarePaginator
693
    {
694
        $range = DB::table($tableName);
695
        if ($tableName === 'xxxinfo') {
696
            $range->selectRaw('UNCOMPRESS(plot) AS plot');
697
        }
698
699
        return $range->orderByDesc('created_at')->paginate(config('nntmux.items_per_page'));
700
    }
701
702
    /**
703
     * @param $tableName
704
     *
705
     * @return int
706
     */
707
    public static function getCount($tableName): int
708
    {
709
        $res = DB::table($tableName)->count('id');
710
711
        return $res === false ? 0 : $res;
0 ignored issues
show
introduced by
The condition $res === false is always false.
Loading history...
712
    }
713
}
714