.github/workflows/build.yml 0000644 00000001213 15073164573 0011773 0 ustar 00 name: Tests
on: [push]
jobs:
run:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['7.4', '8.0', '8.1']
name: Testing on PHP ${{ matrix.php }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring,bcmath
tools: composer
- name: Install PHP dependencies
run: composer install -q
- name: Run phpunit
run: vendor/bin/phpunit
- name: Run phpstan
run: vendor/bin/phpstan analyze --no-progress --level=5 src/
.gitignore 0000644 00000000102 15073164573 0006540 0 ustar 00 .DS_Store
composer.lock
vendor/
dev/
.idea/
.phpunit.result.cache
Dockerfile 0000644 00000000216 15073164573 0006550 0 ustar 00 FROM php:8-cli
# install composer
#
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
LICENSE 0000644 00000002066 15073164573 0005570 0 ustar 00 The MIT License (MIT)
Copyright (c) 2019 Oliver Vogel
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. README.md 0000755 00000007530 15073164573 0006046 0 ustar 00 # PHP Media type (MIME) detector

Detecting MIME Content-type in PHP is easy with [mime_content_type](https://www.php.net/manual/en/function.mime-content-type.php) or [Fileinfo](https://www.php.net/manual/en/book.fileinfo.php). But Fileinfo as an extension is sometimes not available on the server. The function `mime_content_type` wants a path to the filesystem as argument and doesn't process if we only have a string value. This package makes it easy to detect the mime types of the content of a given file or string, without any extension dependencies.
## Installation
Install the package easily via composer:
```bash
composer require intervention/mimesniffer
```
## Usage
Here are some code samples, to show how the library is handled.
```php
use Intervention\MimeSniffer\MimeSniffer;
use Intervention\MimeSniffer\Types\ImageJpeg;
// detect given string
$sniffer = MimeSniffer::createFromString($content);
// or detect given file
$sniffer = MimeSniffer::createFromFilename('image.jpg');
// returns object of detected type
$type = $sniffer->getType();
$bool = $type->isBinary(); // check if we have binary data
$bool = $type->isImage(); // check if we are dealing with an image
$bool = $type->isVideo(); // check video data was detected
$bool = $type->isAudio(); // check if we have detected audio data
$bool = $type->isArchive(); // check if an archive was detected
$type = (string) $type; // cast type to string (e.g. "image/jpeg")
// you can also check, if the content matches a specific type
$bool = $sniffer->matches(new ImageJpeg);
// or check, if the content matches an array of types
$bool = $sniffer->matches([ImageJpeg::class, ImageGif::class]);
// or check, if the content matches an array of type objects
$bool = $sniffer->matches([new ImageJpeg, $type]);
```
If your prefer non-static initialization:
```php
use Intervention\MimeSniffer\MimeSniffer;
// create instance with constructor
$sniffer = new MimeSniffer($content);
// with setter for given content
$type = $sniffer->setFromString($other_content)->getType();
// or with setter for filename
$type = $sniffer->setFromFilename('images/image.jpg')->getType();
```
**Currently only the following file types can be detected. More will be added in a next release.**
### Images
- Image encoded as JPEG raw or in the JFIF or Exif file format
- Image file encoded in the Graphics Interchange Format (GIF)
- Image encoded in the Portable Network Graphics format (PNG)
- Image encoded as BMP file, a bitmap format
- Image encoded in High Efficiency Image File Format (HEIC/HEIF)
- Icon encoded in ICO file format
- Image in Google WebP image format
- Scalable Vector Graphics (SVG)
- Tagged Image File Format (TIFF)
- Image encoded Photoshop Document file format (PSD)
- AV1 Image File Format (AVIF)
### Archives
- GZIP compressed
- ZIP file
- RAR archive
- TAR file
### Videos
- AVI
- MPEG-1 and MPEG-2 video
- MKV media container
### Audio
- MP3 file
- FLAC file
### Other
- PDF document
- OGG media container
- SQLite Database
- application/octet-stream (default binary)
- text/plain (default)
## Contributing
Contributions are welcome. Please note the following guidelines before submiting your pull request.
- Follow [PSR-2](http://www.php-fig.org/psr/psr-2/) coding standards.
- Write tests for new functions and added features
## Development & Testing
With this package comes a Docker image to build a test suite and analysis container. To build this container you have to have Docker installed on your system. You can run all tests with this command.
```bash
docker-compose run --rm --build tests
```
Run the static analyzer on the code base.
```bash
docker-compose run --rm --build analysis
```
## License
Licensed under the [MIT License](http://opensource.org/licenses/MIT).
Copyright 2019 [Oliver Vogel](https://olivervogel.com/)
composer.json 0000644 00000001422 15073164573 0007300 0 ustar 00 {
"name": "intervention/mimesniffer",
"description": "PHP MIME Type Sniffer",
"homepage": "http://intervention.io/",
"keywords": ["mime", "type", "sniffer", "detector"],
"license": "MIT",
"authors": [
{
"name": "Oliver Vogel",
"email": "oliver@intervention.io",
"homepage": "https://intervention.io/"
}
],
"require": {
"php": "^7.3|^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
"phpstan/phpstan": "^1"
},
"autoload": {
"psr-4": {
"Intervention\\MimeSniffer\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Intervention\\MimeSniffer\\Test\\": "tests"
}
},
"minimum-stability": "stable"
}
docker-compose.yml 0000644 00000000535 15073164573 0010217 0 ustar 00 version: '3'
services:
tests:
build: ./
working_dir: /project
command: bash -c "composer install && ./vendor/bin/phpunit -vvv"
volumes:
- ./:/project
analysis:
build: ./
working_dir: /project
command: bash -c "composer install && ./vendor/bin/phpstan analyze --level=4 ./src"
volumes:
- ./:/project
phpunit.xml 0000644 00000001035 15073164573 0006767 0 ustar 00
./tests/
src/AbstractBinaryType.php 0000644 00000001024 15073164573 0011626 0 ustar 00 pattern, $this->prepareContent($content)) === 1;
}
/**
* Determine if the detected type is an image
*
* @return boolean
*/
public function isImage(): bool
{
return substr($this->name, 0, 5) === 'image';
}
/**
* Determine if the detected type is an video
*
* @return boolean
*/
public function isVideo(): bool
{
return substr($this->name, 0, 5) === 'video';
}
/**
* Determine if the detected type is an audio file
*
* @return boolean
*/
public function isAudio(): bool
{
return substr($this->name, 0, 5) === 'audio';
}
/**
* Determine if the detected type is an archive
*
* @return boolean
*/
public function isArchive(): bool
{
return in_array($this->name, [
'application/zip',
'application/x-rar-compressed',
'application/x-tar',
'application/gzip',
]);
}
/**
* Prepare content (can be extended by child classes)
*
* @param string $content
* @return string
*/
public function prepareContent(string $content): string
{
return substr($content, 0, 1024);
}
/**
* Determine of current type is binary
*
* @return boolean
*/
public function isBinary(): bool
{
return false;
}
/**
* Cast type to string
*
* @return string
*/
public function __toString(): string
{
return $this->name;
}
}
src/Exceptions/NotMatchingException.php 0000644 00000000240 15073164573 0014266 0 ustar 00 setFromString($content);
}
/**
* Create new instance from given string
*
* @param string $content
*
* @return MimeSniffer
*/
public static function createFromString(string $content): MimeSniffer
{
return new self($content);
}
/**
* Load contents of given string into instance
*
* @param string $content
*
* @return MimeSniffer
*/
public function setFromString(string $content): MimeSniffer
{
$this->content = strval($content);
return $this;
}
/**
* Create a new instance and load contents of given filename
*
* @param string $filename
*
* @return MimeSniffer
*/
public static function createFromFilename(string $filename): MimeSniffer
{
return (new self())->setFromFilename($filename);
}
/**
* Load contents of given filename in current instance
*
* @param string $filename
*
* @return MimeSniffer
*/
public function setFromFilename(string $filename): MimeSniffer
{
$fp = fopen($filename, 'r');
$this->setFromString(fread($fp, 1024));
fclose($fp);
return $this;
}
/**
* Return detected type
*
* @return AbstractType
*/
public function getType(): AbstractType
{
foreach ($this->getTypeClassnames() as $classname) {
$type = new $classname();
if ($type->matches($this->content)) {
return $type;
}
}
$binaryType = new Types\ApplicationOctetStream();
if ($this->matches($binaryType)) {
return $binaryType;
}
return new Types\TextPlain();
}
/**
* Determine if content matches the given type
* or any if the given types in array
*
* @param AbstractType|array $types AbstractType or array of AbstractTypes
* @return boolean
*/
public function matches($types): bool
{
if (! is_array($types)) {
$types = [$types];
}
$types = array_map(function ($value) {
if (is_a($value, AbstractType::class)) {
return $value;
}
if (!is_null($value) && class_exists($value)) {
return new $value();
}
}, $types);
$types = array_filter($types, function ($type) {
return is_a($type, AbstractType::class);
});
foreach ($types as $type) {
if ($type->matches($this->content)) {
return true;
}
}
return false;
}
/**
* Return array of type classnames
*
* @return array
*/
private function getTypeClassnames(): array
{
$files = array_diff(scandir(__DIR__ . '/Types'), ['.', '..']);
$classnames = array_map(function ($filename) {
return "Intervention\\MimeSniffer\\Types\\" . substr($filename, 0, -4);
}, $files);
return array_filter($classnames, function ($classname) {
return ! in_array($classname, [
Types\ApplicationOctetStream::class,
Types\TextPlain::class,
]);
});
}
}
src/Types/ApplicationGzip.php 0000644 00000000556 15073164573 0012266 0 ustar 00 ]*\?>.*)?