Skip to content

Commit 6826517

Browse files
committed
Release 3.0.0
- Switched from Singleton, because it made testing more complicated and did not provide any improvements compared to a "normal" class - Added new method setByteCacheMaxLength() - Updated test - Updated dependencies (composer.lock) - Updated readme
1 parent 9aca177 commit 6826517

File tree

5 files changed

+114
-82
lines changed

5 files changed

+114
-82
lines changed

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Short answer: I have just little experience in unit testing. This project was a
2929
- PHP 7.1 or newer
3030
- [Composer](https://getcomposer.org)
3131

32+
If you are looking for a solution that works on older PHP versions (5.3.2+), head over to the [oldphp](https://github.com/SoftCreatR/php-mime-detector/tree/oldphp) branch.
33+
3234
## Installation
3335

3436
Require this package using [Composer](https://getcomposer.org/), in the root directory of your project:
@@ -46,7 +48,7 @@ use SoftCreatR\MimeDetector\MimeDetector;
4648
use SoftCreatR\MimeDetector\MimeDetectorException;
4749

4850
// create an instance of the MimeDetector
49-
$mimeDetector = MimeDetector::getInstance();
51+
$mimeDetector = new MimeDetector();
5052

5153
// set our file to read
5254
try {
@@ -62,6 +64,19 @@ $fileData = $mimeDetector->getFileType();
6264
echo '<pre>' . print_r($fileData, true) . '</pre>';
6365
```
6466

67+
Or short:
68+
69+
```php
70+
use SoftCreatR\MimeDetector\MimeDetector;
71+
use SoftCreatR\MimeDetector\MimeDetectorException;
72+
73+
try {
74+
echo '<pre>' . print_r((new MimeDetector())->setFile('foo.bar')->getFileType(), true) . '</pre>';
75+
} catch (MimeDetectorException $e) {
76+
die('An error occured while trying to load the given file.');
77+
}
78+
```
79+
6580
## Testing
6681

6782
Testing utilizes PHPUnit (what else?) by running this command:

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"issues": "https://github.com/SoftCreatR/php-mime-detector/issues",
2424
"forum": "https://support.softcreatr.com"
2525
},
26-
"version": "2.0.1",
26+
"version": "3.0.0",
2727
"require": {
2828
"php": ">=7.1.0"
2929
},

composer.lock

Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/SoftCreatR/MimeDetector/MimeDetector.php

Lines changed: 43 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@
1212
*/
1313
class MimeDetector
1414
{
15-
/**
16-
* Current instance
17-
*
18-
* @var MimeDetector
19-
*/
20-
private static $instance;
21-
2215
/**
2316
* Cached first X bytes of the given file
2417
*
@@ -33,6 +26,13 @@ class MimeDetector
3326
*/
3427
private $byteCacheLen = 0;
3528

29+
/**
30+
* Maximum number of bytes to cache
31+
*
32+
* @var integer
33+
*/
34+
private $maxByteCacheLen = 0;
35+
3636
/**
3737
* Path to the given file
3838
*
@@ -74,69 +74,20 @@ class MimeDetector
7474
];
7575

7676
/**
77-
* Singletons do not support a public constructor. Override init() if
78-
* you need to initialize components on creation.
79-
*
80-
* @codeCoverageIgnore
81-
*/
82-
final protected function __construct()
83-
{
84-
$this->init();
85-
}
86-
87-
/**
88-
* Called within __construct(), override if necessary.
89-
*
90-
* @codeCoverageIgnore
77+
* Create a new MimeDetector object.
9178
*/
92-
protected function init()
79+
public function __construct()
9380
{
9481
}
9582

96-
/**
97-
* Object cloning is disallowed.
98-
*
99-
* @codeCoverageIgnore
100-
*/
101-
final protected function __clone()
102-
{
103-
}
104-
105-
/**
106-
* Object serializing is disallowed.
107-
*
108-
* @throws MimeDetectorException
109-
* @codeCoverageIgnore
110-
*/
111-
final public function __sleep()
112-
{
113-
throw new MimeDetectorException('Serializing of Singletons is not allowed');
114-
}
115-
116-
/**
117-
* Returns an unique instance of the MimeDetector class.
118-
*
119-
* @return MimeDetector
120-
*/
121-
public static function getInstance(): MimeDetector
122-
{
123-
// @codeCoverageIgnoreStart
124-
if (empty(self::$instance)) {
125-
self::$instance = new MimeDetector();
126-
}
127-
// @codeCoverageIgnoreEnd
128-
129-
return self::$instance;
130-
}
131-
13283
/**
13384
* Setter for the file to be checked.
13485
*
13586
* @param string $filePath
13687
* @return MimeDetector
13788
* @throws MimeDetectorException
13889
*/
139-
public function setFile(string $filePath): MimeDetector
90+
public function setFile(string $filePath): self
14091
{
14192
if (!file_exists($filePath)) {
14293
throw new MimeDetectorException("File '" . $filePath . "' does not exist.");
@@ -147,6 +98,7 @@ public function setFile(string $filePath): MimeDetector
14798
if ($this->fileHash !== $fileHash) {
14899
$this->byteCache = [];
149100
$this->byteCacheLen = 0;
101+
$this->maxByteCacheLen = $this->maxByteCacheLen ?: 4096;
150102
$this->file = $filePath;
151103
$this->fileHash = $fileHash;
152104

@@ -249,12 +201,11 @@ public function getFileType(): array
249201
// Need to be before the `zip` check
250202
if ($this->checkForBytes([0x50, 0x4B, 0x3, 0x4])) {
251203
if ($this->checkForBytes([
252-
0x6D, 0x69, 0x6D, 0x65, 0x74, 0x79, 0x70,
253-
0x65, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63,
254-
0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x65,
255-
0x70, 0x75, 0x62, 0x2B, 0x7A, 0x69, 0x70
256-
], 30)
257-
) {
204+
0x6D, 0x69, 0x6D, 0x65, 0x74, 0x79, 0x70,
205+
0x65, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63,
206+
0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x65,
207+
0x70, 0x75, 0x62, 0x2B, 0x7A, 0x69, 0x70
208+
], 30)) {
258209
return [
259210
'ext' => 'epub',
260211
'mime' => 'application/epub+zip'
@@ -1112,6 +1063,30 @@ public function toBytes(string $str): array
11121063
{
11131064
return array_values(unpack('C*', $str));
11141065
}
1066+
1067+
/**
1068+
* Allows to define the max byte cache length for a file. This can be useful in cases,
1069+
* when you expect files, where the magic number should be found within the first X bytes.
1070+
* However, the byte cache should have at least a length of 4 for a proper detection.
1071+
*
1072+
* @param int $maxLength
1073+
* @return MimeDetector
1074+
* @throws MimeDetectorException
1075+
*/
1076+
public function setByteCacheMaxLength(int $maxLength): self
1077+
{
1078+
if ($this->byteCacheLen > 0) {
1079+
throw new MimeDetectorException('setByteCacheMaxLength() must be called before setFile().');
1080+
}
1081+
1082+
if ($maxLength < 4) {
1083+
throw new MimeDetectorException('Maximum byte cache length must not be smaller than 4.');
1084+
}
1085+
1086+
$this->maxByteCacheLen = $maxLength;
1087+
1088+
return $this;
1089+
}
11151090

11161091
/**
11171092
* Checks the byte sequence of a given string.
@@ -1181,7 +1156,8 @@ protected function checkForBytes(array $bytes, int $offset = 0, array $mask = []
11811156
}
11821157

11831158
/**
1184-
* Caches the first 4096 bytes of the given file, so we don't have to read the whole file on every iteration.
1159+
* Caches the first X bytes (4096 by default) of the given file,
1160+
* so we don't have to read the whole file on every iteration.
11851161
*
11861162
* @return void
11871163
* @throws MimeDetectorException
@@ -1197,7 +1173,7 @@ protected function createByteCache(): void
11971173
}
11981174

11991175
$handle = fopen($this->file, 'rb');
1200-
$data = fread($handle, 4096);
1176+
$data = fread($handle, $this->maxByteCacheLen);
12011177
fclose($handle);
12021178

12031179
foreach (str_split($data) as $i => $char) {

tests/SoftCreatR/MimeDetector/MimeDetectorTest.php

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class MimeDetectorTest extends TestCaseImplementation
1919
*/
2020
public function getInstance(): MimeDetector
2121
{
22-
return MimeDetector::getInstance();
22+
return new MimeDetector();
2323
}
2424

2525
/**
@@ -57,6 +57,7 @@ public function testSetFile($testFiles): void
5757

5858
self::assertAttributeNotEmpty('byteCache', $mimeDetector);
5959
self::assertAttributeGreaterThanOrEqual(1, 'byteCacheLen', $mimeDetector);
60+
self::assertAttributeEquals(4096, 'maxByteCacheLen', $mimeDetector);
6061
self::assertAttributeSame($testFile['file'], 'file', $mimeDetector);
6162
self::assertAttributeSame($testFile['hash'], 'fileHash', $mimeDetector);
6263
}
@@ -185,7 +186,7 @@ public function testGetHashFile(): void
185186
{
186187
self::assertNotFalse($this->getInstance()->getHash(__FILE__));
187188
}
188-
189+
189190
/**
190191
* @return void
191192
*/
@@ -202,6 +203,46 @@ public function testToBytes(): void
202203
self::assertEquals([112, 104, 112], $this->getInstance()->toBytes('php'));
203204
}
204205

206+
/**
207+
* Test, if `setByteCacheMaxLength` throws an exception, when being called too late.
208+
*
209+
* @return void
210+
* @throws MimeDetectorException
211+
*/
212+
public function testSetByteCacheMaxLengthThrowsExceptionWrongOrder(): void
213+
{
214+
$this->expectException(MimeDetectorException::class);
215+
$this->getInstance()->setFile(__FILE__)->setByteCacheMaxLength(123);
216+
}
217+
218+
/**
219+
* Test, if `setByteCacheMaxLength` throws an exception, if the given max length is too small.
220+
*
221+
* @return void
222+
* @throws MimeDetectorException
223+
*/
224+
public function testSetByteCacheMaxLengthThrowsExceptionTooSmall(): void
225+
{
226+
$this->expectException(MimeDetectorException::class);
227+
$this->getInstance()->setByteCacheMaxLength(3);
228+
}
229+
230+
/**
231+
* @return void
232+
* @throws MimeDetectorException
233+
*/
234+
public function testSetByteCacheMaxLength(): void
235+
{
236+
$mimeDetector = $this->getInstance();
237+
238+
$mimeDetector->setByteCacheMaxLength(5);
239+
$mimeDetector->setFile(__FILE__);
240+
241+
self::assertAttributeEquals(5, 'maxByteCacheLen', $mimeDetector);
242+
self::assertAttributeEquals(5, 'byteCacheLen', $mimeDetector);
243+
self::assertAttributeSame($mimeDetector->toBytes('<?php'), 'byteCache', $mimeDetector);
244+
}
245+
205246
/**
206247
* @return void
207248
* @throws ReflectionException

0 commit comments

Comments
 (0)