• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / assets / 14160133541

30 Mar 2025 09:27PM UTC coverage: 94.853% (-2.0%) from 96.809%
14160133541

push

github

dg
nette/assets

129 of 136 new or added lines in 5 files covered. (94.85%)

129 of 136 relevant lines covered (94.85%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.0
/src/Assets/Helpers.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Nette\Assets;
6

7
use Nette;
8

9

10
/**
11
 * Static helper class providing utility functions for working with assets.
12
 */
13
final class Helpers
14
{
15
        use Nette\StaticClass;
16

17
        /**
18
         * Validates array of options against allowed optional and required keys.
19
         * @throws \InvalidArgumentException if there are unsupported or missing options
20
         */
21
        public static function checkOptions(array $array, array $optional = [], array $required = []): void
1✔
22
        {
23
                if ($keys = array_diff(array_keys($array), $optional, $required)) {
1✔
24
                        throw new \InvalidArgumentException('Unsupported asset options: ' . implode(', ', $keys));
1✔
25
                }
26
                if ($keys = array_diff($required, array_keys($array))) {
1✔
NEW
27
                        throw new \InvalidArgumentException('Missing asset options: ' . implode(', ', $keys));
×
28
                }
29
        }
1✔
30

31

32
        /**
33
         * Estimates the duration (in seconds) of an MP3 file, assuming constant bitrate (CBR).
34
         * @throws \RuntimeException If the file cannot be opened, MP3 sync bits aren't found, or bitrate is invalid/unsupported.
35
         */
36
        public static function guessMP3Duration(string $path): int
1✔
37
        {
38
                if (
39
                        ($header = @file_get_contents($path, length: 10000)) === false // @ - file may not exist
1✔
40
                        || ($fileSize = @filesize($path)) === false
1✔
41
                ) {
NEW
42
                        throw new \RuntimeException(sprintf("Failed to open file '%s'. %s", $path, Nette\Utils\Helpers::getLastError()));
×
43
                }
44

45
                $frameOffset = strpos($header, "\xFF\xFB"); // 0xFB indicates MPEG Version 1, Layer III, no protection bit.
1✔
46
                if ($frameOffset === false) {
1✔
47
                        throw new \RuntimeException('Failed to find MP3 frame sync bits.');
1✔
48
                }
49

50
                $frameHeader = substr($header, $frameOffset, 4);
1✔
51
                $headerBits = unpack('N', $frameHeader)[1];
1✔
52
                $bitrateIndex = ($headerBits >> 12) & 0xF;
1✔
53
                $bitrate = [null, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320][$bitrateIndex] ?? null;
1✔
54
                if ($bitrate === null) {
1✔
NEW
55
                        throw new \RuntimeException('Invalid or unsupported bitrate index.');
×
56
                }
57

58
                return (int) round($fileSize * 8 / $bitrate / 1000);
1✔
59
        }
60
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc