├── .travis.yml ├── bin └── console ├── composer.json ├── config ├── db.sql ├── parameters.yml.dist └── services.yml ├── log └── touch ├── phpunit.xml ├── readme.md ├── src └── IngoWalther │ └── ImageMinifyApi │ ├── Command │ ├── AddUserCommand.php │ ├── ListUserCommand.php │ └── SetupCommand.php │ ├── Compressor │ ├── Compressor.php │ ├── GifsicleCompressor.php │ ├── MozJpegCompressor.php │ ├── PngquantCompressor.php │ └── SVGOCompressor.php │ ├── Database │ ├── AbstractRepository.php │ └── UserRepository.php │ ├── DependencyInjection │ ├── CompilerPass │ │ ├── CommandPass.php │ │ └── CompressorPass.php │ └── ContainerBuilder.php │ ├── Error │ └── ErrorHandler.php │ ├── File │ ├── FileHandler.php │ ├── FileSizeFormatter.php │ └── SavingCalculator.php │ ├── Minify │ └── Minify.php │ ├── Response │ └── CompressedFileResponse.php │ ├── Security │ ├── ApiKeyCheck.php │ ├── ApiKeyGenerator.php │ └── RandomStringGenerator.php │ ├── Test │ ├── Error │ │ └── ErrorHandlerTest.php │ ├── File │ │ ├── FileSizeFormatterTest.php │ │ └── SavingCalculatorTest.php │ ├── Minify │ │ └── MinifyTest.php │ ├── Security │ │ ├── ApiKeyCheckTest.php │ │ └── ApiKeyGeneratorTest.php │ └── Validator │ │ └── RequestValidatorTest.php │ └── Validator │ └── RequestValidator.php └── web ├── .htaccess └── index.php /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.6 4 | - 7.0 5 | - hhvm 6 | - nightly 7 | 8 | matrix: 9 | allow_failures: 10 | - php: nightly 11 | 12 | before_script: 13 | - composer install --no-dev -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | build(realpath(__DIR__ . '/../')); 10 | 11 | /** @var \Symfony\Component\Console\Application $console */ 12 | $console = $container->get('console'); 13 | $console->run(); -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ingowalther/image-minify-api", 3 | "homepage": "https://github.com/ingowalther/image-minify-api", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Ingo Walther", 8 | "email": "ingowalther@iwebspace.net" 9 | } 10 | ], 11 | "require": { 12 | "silex/silex": "~1.3", 13 | "adambrett/shell-wrapper": "0.6", 14 | "symfony/dependency-injection": "2.7.6", 15 | "symfony/yaml": "2.7.6", 16 | "symfony/config": "2.7.6", 17 | "symfony/console": "2.7.6", 18 | "doctrine/dbal": "2.5.2", 19 | "monolog/monolog": "1.17.2", 20 | "incenteev/composer-parameter-handler": "~2.1" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "5.0.*" 24 | }, 25 | "scripts": { 26 | "post-install-cmd": [ 27 | "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", 28 | "php bin/console image-minify-api:setup" 29 | ], 30 | "post-update-cmd": [ 31 | "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters" 32 | ] 33 | }, 34 | "extra": { 35 | "incenteev-parameters": { 36 | "file": "config/parameters.yml" 37 | } 38 | }, 39 | "autoload": { 40 | "psr-0": { 41 | "IngoWalther\\ImageMinifyApi\\": "src/" 42 | } 43 | }, 44 | "minimum-stability": "dev" 45 | } -------------------------------------------------------------------------------- /config/db.sql: -------------------------------------------------------------------------------- 1 | -- Adminer 4.2.2 MySQL dump 2 | 3 | SET NAMES utf8; 4 | SET time_zone = '+00:00'; 5 | SET foreign_key_checks = 0; 6 | SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; 7 | 8 | SET NAMES utf8mb4; 9 | 10 | CREATE TABLE `user` ( 11 | `id` int(11) NOT NULL AUTO_INCREMENT, 12 | `name` varchar(32) NOT NULL, 13 | `api_key` varchar(32) NOT NULL, 14 | PRIMARY KEY (`id`) 15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 16 | 17 | 18 | -- 2015-11-03 22:22:52 -------------------------------------------------------------------------------- /config/parameters.yml.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | db_config.database: image-minify-api 3 | db_config.user: root 4 | db_config.password: root 5 | db_config.host: localhost 6 | compressor.mozjpeg.binary_path: '/opt/mozjpeg/bin/cjpeg' 7 | compressor.mozjpeg.command: '%compressor.mozjpeg.binary_path% -quality 82 %s > %s' 8 | compressor.gifsicle.binary_path: 'gifsicle' 9 | compressor.gifsicle.command: '%compressor.gifsicle.binary_path% -O3 %s -o %s' 10 | compressor.pngquant.binary_path: 'pngquant' 11 | compressor.pngquant.command: '%compressor.pngquant.binary_path% --quality=60-90 %s --ext=%s -s1' 12 | compressor.svgo.binary_path: 'svgo' 13 | compressor.svgo.command: '%compressor.svgo.binary_path% %s %s' -------------------------------------------------------------------------------- /config/services.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: 'parameters.yml' } 3 | 4 | parameters: 5 | db: 6 | url: mysql://%db_config.user%:%db_config.password%@%db_config.host%/%db_config.database% 7 | configPath: %basePath%/config 8 | logPath: %basePath%/log 9 | 10 | services: 11 | minify: 12 | class: IngoWalther\ImageMinifyApi\Minify\Minify 13 | arguments: [@fileHandler, @logger] 14 | 15 | mozJpegCompressor: 16 | class: IngoWalther\ImageMinifyApi\Compressor\MozJpegCompressor 17 | arguments: ['%compressor.mozjpeg.binary_path%', '%compressor.mozjpeg.command%'] 18 | tags: 19 | - { name: image.compressor, alias: jpeg} 20 | 21 | pngquantCompressor: 22 | class: IngoWalther\ImageMinifyApi\Compressor\PngquantCompressor 23 | arguments: ['%compressor.pngquant.binary_path%', '%compressor.pngquant.command%'] 24 | tags: 25 | - { name: image.compressor, alias: png} 26 | 27 | svgoCompressor: 28 | class: IngoWalther\ImageMinifyApi\Compressor\SVGOCompressor 29 | arguments: ['%compressor.svgo.binary_path%', '%compressor.svgo.command%'] 30 | tags: 31 | - { name: image.compressor, alias: svgo} 32 | 33 | gifsicleCompressor: 34 | class: IngoWalther\ImageMinifyApi\Compressor\GifsicleCompressor 35 | arguments: ['%compressor.gifsicle.binary_path%', '%compressor.gifsicle.command%'] 36 | tags: 37 | - { name: image.compressor, alias: gif} 38 | 39 | fileHandler: 40 | class: IngoWalther\ImageMinifyApi\File\FileHandler 41 | 42 | randomStringGenerator: 43 | class: IngoWalther\ImageMinifyApi\Security\RandomStringGenerator 44 | 45 | apiKeyCheck: 46 | class: IngoWalther\ImageMinifyApi\Security\ApiKeyCheck 47 | arguments: [@userRepository] 48 | 49 | apiKeyGenerator: 50 | class: IngoWalther\ImageMinifyApi\Security\ApiKeyGenerator 51 | arguments: [@userRepository, @randomStringGenerator] 52 | 53 | userRepository: 54 | class: IngoWalther\ImageMinifyApi\Database\UserRepository 55 | arguments: [@dbConnection] 56 | 57 | dbConfig: 58 | class: Doctrine\DBAL\Configuration 59 | 60 | dbConnection: 61 | class: Doctrine\DBAL\Connection 62 | factory_class: Doctrine\DBAL\DriverManager 63 | factory_method: getConnection 64 | arguments: [%db%, @dbConfig] 65 | 66 | errorHandler: 67 | class: IngoWalther\ImageMinifyApi\Error\ErrorHandler 68 | arguments: [@logger] 69 | 70 | logger: 71 | class: Monolog\Logger 72 | arguments: ['ImageMinifyApi'] 73 | calls: 74 | - [pushHandler, [@logHandler]] 75 | 76 | logHandler: 77 | class: Monolog\Handler\RotatingFileHandler 78 | arguments: [%logPath%/app.log, 7] 79 | 80 | console: 81 | class: Symfony\Component\Console\Application 82 | 83 | addUserCommand: 84 | class: IngoWalther\ImageMinifyApi\Command\AddUserCommand 85 | calls: 86 | - [setApiKeyGenerator, [@apiKeyGenerator]] 87 | tags: 88 | - { name: console.command, alias: user} 89 | 90 | listUserCommand: 91 | class: IngoWalther\ImageMinifyApi\Command\ListUserCommand 92 | calls: 93 | - [setUserRepository, [@userRepository]] 94 | tags: 95 | - { name: console.command, alias: listUser} 96 | 97 | setupCommand: 98 | class: IngoWalther\ImageMinifyApi\Command\SetupCommand 99 | calls: 100 | - [setConnection, [@dbConnection]] 101 | - [setConfigPath, [%configPath%]] 102 | tags: 103 | - { name: console.command, alias: setup} 104 | -------------------------------------------------------------------------------- /log/touch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ingowalther/image-minify-api/8e69699d7f45659a03dabfa5d07e0c95bb5a27cc/log/touch -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | src 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Image Minify API 2 | 3 | Install an Image-Compression-Service (like TinyPng, JPEGMini) on your own Server! 4 | 5 | [![Build Status](https://travis-ci.org/ingowalther/image-minify-api.svg?branch=master)](https://travis-ci.org/ingowalther/image-minify-api) 6 | 7 | - [Image Minify API](#) 8 | - [Installation](#installation) 9 | - [Create Database](#create-database) 10 | - [Install Project](#install-project) 11 | - [Set permissions for files](#set-permissions-for-files) 12 | - [Setup Webserver](#setup-webserver) 13 | - [Usage](#usage) 14 | - [Create API-Key](#create-api-key) 15 | - [Compress an Image](#compress-an-image) 16 | - [Response](#response) 17 | - [List all user](#list-all-user) 18 | - [Clients](#api-clients) 19 | - [PHP](#api-clients) 20 | - [Grunt-Task](#api-clients) 21 | - [TODO](#todo) 22 | 23 | Currently supports: 24 | - jpeg (mozJpeg, Installation Instructions: http://mozjpeg.codelove.de/binaries.html) 25 | - png (pngquant, https://pngquant.org/) 26 | - svg (SVGO, https://github.com/svg/svgo) 27 | - gif (Gifsicle, https://www.lcdf.org/gifsicle/) 28 | 29 | ## Installation 30 | 31 | ### Create Database 32 | You should create a database first. In this database Image Minify API will create all necessary tables during composer install. 33 | 34 | ### Install Project 35 | ```sh 36 | composer create-project ingowalther/image-minify-api %installation-folder-name% 37 | ``` 38 | 39 | ### Set permissions for files 40 | ```sh 41 | chmod a+rw log 42 | ``` 43 | 44 | ### Setup Webserver 45 | ``` 46 | vHost DocRoot -> web/ 47 | ``` 48 | 49 | ## Usage 50 | 51 | ### Create API-Key 52 | ```sh 53 | bin/console user:add 54 | ``` 55 | Enter a Username. 56 | If the user is created correctly you will see the API-Key in your Terminal. 57 | 58 | ### Compress an Image 59 | 60 | POST with Params "api_key" and File with Name "image" to http://yourserver/minify 61 | 62 | Example: 63 | ```sh 64 | curl --form "image=@test.jpg" --form api_key=VVDFNNflLIQdCH5vnx0RkmCxxjhHIL6 http://localhost/minify > result.json 65 | ``` 66 | 67 | #### Response 68 | You will get a Json-Response like this: 69 | ```json 70 | { 71 | "success":true, 72 | "oldSize":539, 73 | "newSize":394, 74 | "saving": 26, 75 | "image":"\/9j\/4AAQSkZJRgABAQAAAQABAAD\/\/gATQ3JlYXRlZCB3aXRoIEdJTVD\/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u\/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+\/\/CABEIAAEAAQMBIgACEQEDEQH\/xAAUAAEAAAAAAAAAAAAAAAAAAAAH\/9oACAEBAAAAAGb\/xAAUAQEAAAAAAAAAAAAAAAAAAAAA\/9oACAECEAAAAH\/\/xAAUAQEAAAAAAAAAAAAAAAAAAAAA\/9oACAEDEAAAAH\/\/xAAUEAEAAAAAAAAAAAAAAAAAAAAA\/9oACAEBAAE\/AH\/\/xAAUEQEAAAAAAAAAAAAAAAAAAAAA\/9oACAECAQE\/AH\/\/xAAUEQEAAAAAAAAAAAAAAAAAAAAA\/9oACAEDAQE\/AH\/\/2Q==" 76 | } 77 | ``` 78 | | Parameter | Description | 79 | | ------------- | ------------- | 80 | | success | true or false | 81 | | oldSize | ImageSize before compressing (in Byte) | 82 | | newSize | ImageSize after compressing (in Byte) | 83 | | saving | The saving of bytes in percent | 84 | | image | The binarydata of the compressed image (base64 encoded) | 85 | 86 | ### List all user 87 | ```sh 88 | bin/console user:list 89 | ``` 90 | Output: 91 | 92 | ![Console output](http://i.imgur.com/6SKcBcF.png) 93 | 94 | ## API-Clients 95 | 96 | PHP: https://github.com/ingowalther/image-minify-php-client 97 | 98 | Grunt-Task: https://github.com/yannicstadler/image-minify-api-grunt-task 99 | 100 | ## TODO 101 | - Quota 102 | 103 | -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Command/AddUserCommand.php: -------------------------------------------------------------------------------- 1 | apiKeyGenerator = $apiKeyGenerator; 26 | } 27 | 28 | 29 | protected function configure() 30 | { 31 | $this 32 | ->setName('user:add') 33 | ->setDescription('Creates a new User/API-Key') 34 | ->addArgument( 35 | 'name', 36 | InputArgument::OPTIONAL, 37 | 'Username?' 38 | ); 39 | } 40 | 41 | /** 42 | * @param InputInterface $input 43 | * @param OutputInterface $output 44 | * @throws \Exception 45 | */ 46 | protected function execute(InputInterface $input, OutputInterface $output) 47 | { 48 | if(!$this->apiKeyGenerator) { 49 | throw new \Exception('ApiKeyGenerator is not set!'); 50 | } 51 | 52 | $name = $input->getArgument('name'); 53 | 54 | if(!$name) { 55 | /** @var QuestionHelper $helper */ 56 | $helper = $this->getHelper('question'); 57 | $question = new Question('Username? '); 58 | 59 | $name = $helper->ask($input, $output, $question); 60 | } 61 | 62 | $key = $this->apiKeyGenerator->generate($name); 63 | 64 | $output->writeln(sprintf('User "%s" succesfully created', $name)); 65 | $output->writeln(sprintf('API-Key: %s', $key)); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Command/ListUserCommand.php: -------------------------------------------------------------------------------- 1 | userRepository = $userRepository; 24 | } 25 | 26 | protected function configure() 27 | { 28 | $this 29 | ->setName('user:list') 30 | ->setDescription('Lists all user'); 31 | } 32 | 33 | /** 34 | * @param InputInterface $input 35 | * @param OutputInterface $output 36 | */ 37 | protected function execute(InputInterface $input, OutputInterface $output) 38 | { 39 | $table = new Table($output); 40 | $table->setHeaders(['ID', 'Username', 'API-Key']) 41 | ->addRows($this->userRepository->findAll()); 42 | 43 | $table->render(); 44 | } 45 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Command/SetupCommand.php: -------------------------------------------------------------------------------- 1 | configPath = $configPath; 28 | } 29 | 30 | /** 31 | * @param Connection $connection 32 | */ 33 | public function setConnection(Connection $connection) 34 | { 35 | $this->connection = $connection; 36 | } 37 | 38 | protected function configure() 39 | { 40 | $this 41 | ->setName('image-minify-api:setup') 42 | ->setDescription('Setups the project'); 43 | } 44 | 45 | /** 46 | * @param InputInterface $input 47 | * @param OutputInterface $output 48 | * @throws \Exception 49 | */ 50 | protected function execute(InputInterface $input, OutputInterface $output) 51 | { 52 | $dump = file_get_contents($this->configPath . '/db.sql'); 53 | 54 | $statement = $this->connection->prepare($dump); 55 | $statement->execute(); 56 | 57 | if ($statement->errorCode() != 0) { 58 | throw new \Exception('Error while creating Database'); 59 | } 60 | 61 | $output->writeln('Database created successfully'); 62 | } 63 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Compressor/Compressor.php: -------------------------------------------------------------------------------- 1 | binaryPath = $binaryPath; 35 | $this->command = $command; 36 | } 37 | 38 | /** 39 | * @return string 40 | */ 41 | public function getFileTypeToHandle() 42 | { 43 | return 'image/gif'; 44 | } 45 | 46 | /** 47 | * @param UploadedFile $file 48 | * @return string 49 | */ 50 | public function compress(UploadedFile $file) 51 | { 52 | $shell = new Exec(); 53 | 54 | $command = new Command( 55 | sprintf($this->command, $file->getRealPath(), $file->getRealPath() . 'compressed') 56 | ); 57 | 58 | $shell->run($command); 59 | 60 | if (!file_exists($file->getRealPath() . 'compressed')) { 61 | throw new \RuntimeException('No compressed Image created!'); 62 | } 63 | 64 | return $file->getRealPath() . 'compressed'; 65 | } 66 | 67 | /** 68 | * @return bool 69 | */ 70 | public function checkLibaryIsInstalled() 71 | { 72 | $shell = new Exec(); 73 | 74 | $command = new Command($this->binaryPath); 75 | $command->addFlag(new Command\Flag('-version')); 76 | 77 | $shell->run($command); 78 | 79 | if ($shell->getReturnValue() === 0) { 80 | return true; 81 | } 82 | 83 | return false; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Compressor/MozJpegCompressor.php: -------------------------------------------------------------------------------- 1 | binaryPath = $binaryPath; 33 | $this->command = $command; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function getFileTypeToHandle() 40 | { 41 | return 'image/jpeg'; 42 | } 43 | 44 | /** 45 | * @param UploadedFile $file 46 | * @return string 47 | */ 48 | public function compress(UploadedFile $file) 49 | { 50 | $shell = new Exec(); 51 | 52 | $command = new Command( 53 | sprintf($this->command, $file->getRealPath(), $file->getRealPath() . 'compressed') 54 | ); 55 | 56 | $shell->run($command); 57 | 58 | if (!file_exists($file->getRealPath() . 'compressed')) { 59 | throw new \RuntimeException('No compressed Image created!'); 60 | } 61 | 62 | return $file->getRealPath() . 'compressed'; 63 | } 64 | 65 | /** 66 | * @return bool 67 | */ 68 | public function checkLibaryIsInstalled() 69 | { 70 | $shell = new Exec(); 71 | 72 | $command = new Command($this->binaryPath); 73 | $command->addFlag(new Command\Flag('version')); 74 | 75 | $shell->run($command); 76 | 77 | if ($shell->getReturnValue() === 0) { 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Compressor/PngquantCompressor.php: -------------------------------------------------------------------------------- 1 | binaryPath = $binaryPath; 33 | $this->command = $command; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function getFileTypeToHandle() 40 | { 41 | return 'image/png'; 42 | } 43 | 44 | /** 45 | * @param UploadedFile $file 46 | * @return string 47 | */ 48 | public function compress(UploadedFile $file) 49 | { 50 | $shell = new Exec(); 51 | 52 | $command = new Command( 53 | sprintf($this->command, $file->getRealPath(), 'compressed') 54 | ); 55 | 56 | $shell->run($command); 57 | 58 | if (!file_exists($file->getRealPath() . 'compressed')) { 59 | throw new \RuntimeException('No compressed Image created!'); 60 | } 61 | 62 | return $file->getRealPath() . 'compressed'; 63 | } 64 | 65 | /** 66 | * @return bool 67 | */ 68 | public function checkLibaryIsInstalled() 69 | { 70 | $shell = new Exec(); 71 | 72 | $command = new Command($this->binaryPath); 73 | $command->addArgument(new Command\Argument('version')); 74 | 75 | $shell->run($command); 76 | 77 | if ($shell->getReturnValue() === 0) { 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Compressor/SVGOCompressor.php: -------------------------------------------------------------------------------- 1 | binaryPath = $binaryPath; 33 | $this->command = $command; 34 | } 35 | 36 | /** 37 | * @return string 38 | */ 39 | public function getFileTypeToHandle() 40 | { 41 | return 'image/svg+xml'; 42 | } 43 | 44 | /** 45 | * @param UploadedFile $file 46 | * @return string 47 | */ 48 | public function compress(UploadedFile $file) 49 | { 50 | $shell = new Exec(); 51 | 52 | $command = new Command( 53 | sprintf($this->command, $file->getRealPath(), $file->getRealPath() . 'compressed') 54 | ); 55 | 56 | $shell->run($command); 57 | 58 | if (!file_exists($file->getRealPath() . 'compressed')) { 59 | throw new \RuntimeException('No compressed Image created!'); 60 | } 61 | 62 | return $file->getRealPath() . 'compressed'; 63 | } 64 | 65 | /** 66 | * @return bool 67 | */ 68 | public function checkLibaryIsInstalled() 69 | { 70 | $shell = new Exec(); 71 | 72 | $command = new Command($this->binaryPath); 73 | $command->addFlag(new Command\Flag('v')); 74 | 75 | $shell->run($command); 76 | 77 | if ($shell->getReturnValue() === 0) { 78 | return true; 79 | } 80 | return false; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Database/AbstractRepository.php: -------------------------------------------------------------------------------- 1 | connection = $connection; 24 | $this->setTableName(); 25 | } 26 | 27 | /** 28 | * @param int $fetchType 29 | */ 30 | public function findAll($fetchMode = \PDO::FETCH_ASSOC) 31 | { 32 | $query = sprintf('SELECT * FROM `%s`', $this->tableName); 33 | return $this->fetch($query, array(), $fetchMode); 34 | } 35 | 36 | /** 37 | * @param $query 38 | * @param array $params 39 | * @param int $fetchMode 40 | * @return array 41 | * @throws \Doctrine\DBAL\DBALException 42 | */ 43 | protected function fetch($query, $params = array(), $fetchMode= \PDO::FETCH_ASSOC) 44 | { 45 | $statement = $this->connection->prepare($query); 46 | $statement->execute($params); 47 | 48 | return $statement->fetchAll($fetchMode); 49 | } 50 | 51 | protected abstract function setTableName(); 52 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Database/UserRepository.php: -------------------------------------------------------------------------------- 1 | tableName = 'user'; 14 | } 15 | 16 | /** 17 | * @param string $userName 18 | * @return bool|array 19 | */ 20 | public function findUserByName($userName) 21 | { 22 | $query = 'SELECT * FROM `user` WHERE `name` = ?'; 23 | 24 | $result = $this->fetch($query, array($userName)); 25 | if (count($result) == 0) { 26 | return false; 27 | } 28 | return array_pop($result); 29 | } 30 | 31 | /** 32 | * @param string $key 33 | * @return bool|array 34 | */ 35 | public function findUserByKey($key) 36 | { 37 | $query = 'SELECT * FROM `user` WHERE `api_key` = ?'; 38 | 39 | $result = $this->fetch($query, array($key)); 40 | if (count($result) == 0) { 41 | return false; 42 | } 43 | return array_pop($result); 44 | } 45 | 46 | /** 47 | * @param $username 48 | * @param $key 49 | */ 50 | public function addUser($username, $key) 51 | { 52 | $statement = $this->connection->prepare('INSERT INTO `user` (`id`, `name`, `api_key`) VALUES (NULL, ?, ?)'); 53 | $statement->execute(array($username, $key)); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/DependencyInjection/CompilerPass/CommandPass.php: -------------------------------------------------------------------------------- 1 | has('console')) { 18 | return; 19 | } 20 | 21 | $definition = $container->findDefinition('console'); 22 | $taggedServices = $container->findTaggedServiceIds('console.command'); 23 | 24 | foreach ($taggedServices as $id => $tags) { 25 | foreach ($tags as $attributes) { 26 | $definition->addMethodCall( 27 | 'add', 28 | array(new Reference($id)) 29 | ); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/DependencyInjection/CompilerPass/CompressorPass.php: -------------------------------------------------------------------------------- 1 | has('minify')) { 18 | return; 19 | } 20 | 21 | $definition = $container->findDefinition('minify'); 22 | $taggedServices = $container->findTaggedServiceIds('image.compressor'); 23 | 24 | foreach ($taggedServices as $id => $tags) { 25 | foreach ($tags as $attributes) { 26 | $definition->addMethodCall( 27 | 'addCompressor', 28 | array(new Reference($id)) 29 | ); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/DependencyInjection/ContainerBuilder.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new CompressorPass()); 25 | $container->addCompilerPass(new CommandPass()); 26 | $container->setParameter('basePath', $basePath); 27 | $loader = new YamlFileLoader($container, new FileLocator($basePath .'/config')); 28 | $loader->load('services.yml'); 29 | $container->compile(); 30 | 31 | return $container; 32 | } 33 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Error/ErrorHandler.php: -------------------------------------------------------------------------------- 1 | logger = $logger; 26 | } 27 | 28 | /** 29 | * @param \Exception $e 30 | * @param $code 31 | * @return \Symfony\Component\HttpFoundation\JsonResponse 32 | */ 33 | public function handle(\Exception $e, $code) 34 | { 35 | switch ($code) { 36 | case 404: 37 | $data = array( 38 | 'success' => false, 39 | 'code' => '404', 40 | 'message' => 'The requested page could not be found.', 41 | ); 42 | break; 43 | default: 44 | $data = array( 45 | 'success' => false, 46 | 'code' => $code, 47 | 'message' => $e->getMessage(), 48 | ); 49 | } 50 | 51 | $this->logger->error( 52 | sprintf('%s: %s', get_class($e), $e->getMessage()) 53 | ); 54 | 55 | return new JsonResponse($data, $code); 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/File/FileHandler.php: -------------------------------------------------------------------------------- 1 | file($path); 19 | } 20 | 21 | /** 22 | * @param $path 23 | * @return int 24 | */ 25 | public function getFileSize($path) 26 | { 27 | return filesize($path); 28 | } 29 | 30 | /** 31 | * @param $path 32 | * @return string 33 | */ 34 | public function getFileContent($path) 35 | { 36 | return file_get_contents($path); 37 | } 38 | 39 | /** 40 | * @param $path 41 | * @return bool 42 | */ 43 | public function delete($path) 44 | { 45 | return unlink($path); 46 | } 47 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/File/FileSizeFormatter.php: -------------------------------------------------------------------------------- 1 | fileHandler = $fileHandler; 41 | $this->logger = $logger; 42 | } 43 | 44 | /** 45 | * @param Compressor $compressor 46 | */ 47 | public function addCompressor(Compressor $compressor) 48 | { 49 | $this->compressors[] = $compressor; 50 | } 51 | 52 | /** 53 | * Minifies the given Image 54 | * 55 | * @param UploadedFile $file 56 | * @param array $user 57 | * @return CompressedFileResponse 58 | */ 59 | public function minify(UploadedFile $file, $user) 60 | { 61 | $fileType = $this->fileHandler->getFileType($file->getRealPath()); 62 | 63 | $compressorToUse = $this->getCompressorToUse($fileType); 64 | $path = $compressorToUse->compress($file); 65 | 66 | $oldSize = $this->fileHandler->getFileSize($file->getRealPath()); 67 | $newSize = $this->fileHandler->getFileSize($path); 68 | 69 | if ($newSize < $oldSize) { 70 | return $this->handleSuccess($file, $user, $path, $oldSize, $newSize); 71 | } 72 | 73 | return $this->handleNewFileBigger($file, $user, $path, $oldSize, $newSize); 74 | } 75 | 76 | /** 77 | * @param $fileType 78 | * @return Compressor 79 | */ 80 | private function getCompressorToUse($fileType) 81 | { 82 | foreach ($this->compressors as $compressor) { 83 | if ($compressor->getFileTypeToHandle() == $fileType) { 84 | if ($compressor->checkLibaryIsInstalled()) { 85 | return $compressor; 86 | } 87 | } 88 | } 89 | 90 | throw new \InvalidArgumentException( 91 | sprintf('Filetype "%s" not supported', $fileType) 92 | ); 93 | } 94 | 95 | /** 96 | * @param UploadedFile $file 97 | * @param $user 98 | * @param $path 99 | * @param $oldSize 100 | * @param $newSize 101 | * @return CompressedFileResponse 102 | */ 103 | private function handleSuccess(UploadedFile $file, $user, $path, $oldSize, $newSize) 104 | { 105 | $binaryContent = $this->fileHandler->getFileContent($path); 106 | $this->fileHandler->delete($path); 107 | 108 | $savingCalculator = new SavingCalculator(); 109 | $saving = $savingCalculator->calculate($oldSize, $newSize); 110 | 111 | $fomatter = new FileSizeFormatter(); 112 | 113 | $this->logger->info( 114 | sprintf('[%s] Succesfully compressed Image (%s) - Old: %s, New: %s, Saving: %d%%', 115 | $user['name'], 116 | $file->getClientOriginalName(), 117 | $fomatter->humanReadable($oldSize), 118 | $fomatter->humanReadable($newSize), 119 | $saving) 120 | ); 121 | 122 | return new CompressedFileResponse($oldSize, $newSize, $saving, $binaryContent); 123 | } 124 | 125 | /** 126 | * @param UploadedFile $file 127 | * @param $user 128 | * @param $oldSize 129 | * @param $newSize 130 | * @param $path 131 | * @return CompressedFileResponse 132 | */ 133 | private function handleNewFileBigger(UploadedFile $file, $user, $path, $oldSize, $newSize) 134 | { 135 | $savingCalculator = new SavingCalculator(); 136 | $saving = $savingCalculator->calculate($oldSize, $newSize); 137 | 138 | $fomatter = new FileSizeFormatter(); 139 | 140 | $this->logger->info( 141 | sprintf('[%s] New image is bigger than the original one - returning original image (%s) - Old: %s, New: %s, Saving: %d%%', 142 | $user['name'], 143 | $file->getClientOriginalName(), 144 | $fomatter->humanReadable($oldSize), 145 | $fomatter->humanReadable($newSize), 146 | $saving) 147 | ); 148 | 149 | $binaryContent = $this->fileHandler->getFileContent($file->getRealPath()); 150 | $this->fileHandler->delete($path); 151 | $newSize = $oldSize; 152 | $saving = 0; 153 | 154 | return new CompressedFileResponse($oldSize, $newSize, $saving, $binaryContent); 155 | } 156 | 157 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Response/CompressedFileResponse.php: -------------------------------------------------------------------------------- 1 | true, 17 | 'oldSize' => $oldSize, 18 | 'newSize' => $newSize, 19 | 'saving' => $saving, 20 | 'image' => base64_encode($binaryContent) 21 | ]; 22 | 23 | parent::__construct($data, $status, $headers); 24 | } 25 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Security/ApiKeyCheck.php: -------------------------------------------------------------------------------- 1 | userRepository = $userRepository; 26 | } 27 | 28 | /** 29 | * Checks for valid API-Key 30 | * @param string $apiKey 31 | */ 32 | public function check($apiKey) 33 | { 34 | $user = $this->isKeyValid($apiKey); 35 | return $user; 36 | } 37 | 38 | /** 39 | * Checks if API-Key is valid 40 | * @param string $apiKey 41 | */ 42 | private function isKeyValid($apiKey) 43 | { 44 | $user = $this->userRepository->findUserByKey($apiKey); 45 | 46 | if(!$user) { 47 | throw new AccessDeniedHttpException('Your API key is not valid'); 48 | } 49 | return $user; 50 | } 51 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Security/ApiKeyGenerator.php: -------------------------------------------------------------------------------- 1 | userRepository = $userRepository; 31 | $this->randomStringGenerator = $randomStringGenerator; 32 | } 33 | 34 | /** 35 | * @param $username 36 | * @return string 37 | */ 38 | public function generate($username) 39 | { 40 | $this->checkUsername($username); 41 | 42 | do { 43 | $key = $this->randomStringGenerator->generate(); 44 | } while (!$this->checkKey($key)); 45 | 46 | $this->userRepository->addUser($username, $key); 47 | return $key; 48 | } 49 | 50 | /** 51 | * @param $username 52 | */ 53 | private function checkUsername($username) 54 | { 55 | $user = $this->userRepository->findUserByName($username); 56 | if ($user) { 57 | throw new Exception('This username is taken'); 58 | } 59 | } 60 | 61 | private function checkKey($key) 62 | { 63 | $user = $this->userRepository->findUserByKey($key); 64 | if($user) { 65 | return false; 66 | } 67 | return true; 68 | } 69 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Security/RandomStringGenerator.php: -------------------------------------------------------------------------------- 1 | characters) - 1; 24 | for ($i = 0; $i < $length; $i++) { 25 | $string .= $this->characters[rand(0,$max)]; 26 | } 27 | return $string; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Test/Error/ErrorHandlerTest.php: -------------------------------------------------------------------------------- 1 | getMockBuilder('Monolog\Logger') 17 | ->disableOriginalConstructor() 18 | ->getMock(); 19 | 20 | $this->object = new ErrorHandler($logger); 21 | } 22 | 23 | public function testWith404() 24 | { 25 | $exception = new \Exception(); 26 | $response = $this->object->handle($exception, '404'); 27 | 28 | $this->assertEquals(404, $response->getStatusCode()); 29 | 30 | $data = array( 31 | 'success' => false, 32 | 'code' => '404', 33 | 'message' => 'The requested page could not be found.', 34 | ); 35 | 36 | $expected = json_encode($data); 37 | $this->assertEquals($expected, $response->getContent()); 38 | } 39 | 40 | public function testDefault() 41 | { 42 | $message = 'This is my test error'; 43 | 44 | $exception = new \Exception($message); 45 | $response = $this->object->handle($exception, '500'); 46 | 47 | $this->assertEquals(500, $response->getStatusCode()); 48 | 49 | $data = array( 50 | 'success' => false, 51 | 'code' => '500', 52 | 'message' => $message, 53 | ); 54 | 55 | $expected = json_encode($data); 56 | $this->assertEquals($expected, $response->getContent()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Test/File/FileSizeFormatterTest.php: -------------------------------------------------------------------------------- 1 | 800, 'expected' => '800.00B'], 13 | ['test' => 1200, 'expected' => '1.17kB'], 14 | ['test' => 8000000, 'expected' => '7.63MB'], 15 | ['test' => 8000000000, 'expected' => '7.45GB'], 16 | ['test' => 0, 'expected' => '0.00B'], 17 | ]; 18 | 19 | $fomatter = new FileSizeFormatter(); 20 | 21 | foreach($testData as $entry) { 22 | $result = $fomatter->humanReadable($entry['test']); 23 | $this->assertEquals($entry['expected'], $result); 24 | } 25 | } 26 | 27 | public function testHumanReadableWithBytesSmallerZero() 28 | { 29 | $fomatter = new FileSizeFormatter(); 30 | $this->setExpectedException('InvalidArgumentException'); 31 | $fomatter->humanReadable(-1); 32 | } 33 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Test/File/SavingCalculatorTest.php: -------------------------------------------------------------------------------- 1 | object = new SavingCalculator(); 17 | } 18 | 19 | public function testWithOldAndNewSizeZero() 20 | { 21 | $result = $this->object->calculate(0, 0); 22 | $this->assertEquals(0, $result); 23 | } 24 | 25 | public function testWithOldSizeZeroAndNewSizeSet() 26 | { 27 | $result = $this->object->calculate(0, 50); 28 | $this->assertEquals(0, $result); 29 | } 30 | 31 | public function testWithOldSizeSetAndNewSizeZero() 32 | { 33 | $result = $this->object->calculate(50, 0); 34 | $this->assertEquals(0, $result); 35 | } 36 | 37 | public function testWithOldAndNewSizeSet() 38 | { 39 | $result = $this->object->calculate(100, 50); 40 | $this->assertEquals(50, $result); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Test/Minify/MinifyTest.php: -------------------------------------------------------------------------------- 1 | fileHandler = $this->getMock( 18 | 'IngoWalther\ImageMinifyApi\File\FileHandler', 19 | array(), 20 | array(), 21 | '', 22 | false 23 | ); 24 | 25 | $logger = $this->getMockBuilder('Monolog\Logger') 26 | ->disableOriginalConstructor() 27 | ->getMock(); 28 | 29 | $this->object = new Minify($this->fileHandler, $logger); 30 | } 31 | 32 | public function testWithNoCompressor() 33 | { 34 | $this->fileHandler->expects($this->once()) 35 | ->method('getFileType') 36 | ->with('/tmp/foobar') 37 | ->will($this->returnValue('image/jpeg')); 38 | 39 | $this->setExpectedException('InvalidArgumentException'); 40 | $this->object->minify($this->createMockFile(), ['name' => 'foobar']); 41 | } 42 | 43 | public function testWithNoMatchingCompressor() 44 | { 45 | $this->fileHandler->expects($this->once()) 46 | ->method('getFileType') 47 | ->with('/tmp/foobar') 48 | ->will($this->returnValue('image/png')); 49 | 50 | $this->setExpectedException('InvalidArgumentException'); 51 | 52 | $this->object->addCompressor($this->createMockCompressor('image/jpeg')); 53 | $this->object->minify($this->createMockFile(), ['name' => 'foobar']); 54 | } 55 | 56 | public function testWithNoCompressorButLibaryNotInstalled() 57 | { 58 | $this->fileHandler->expects($this->once()) 59 | ->method('getFileType') 60 | ->with('/tmp/foobar') 61 | ->will($this->returnValue('image/png')); 62 | 63 | $this->setExpectedException('InvalidArgumentException'); 64 | 65 | $this->object->addCompressor($this->createMockCompressor('image/jpeg', $installed = false)); 66 | $this->object->minify($this->createMockFile(), ['name' => 'foobar']); 67 | } 68 | 69 | public function testWithMatchingCompressor() 70 | { 71 | $image = $this->createMockFile(); 72 | 73 | $this->fileHandler->expects($this->once()) 74 | ->method('getFileType') 75 | ->with('/tmp/foobar') 76 | ->will($this->returnValue('image/jpeg')); 77 | 78 | $compressor = $this->createMockCompressor('image/jpeg'); 79 | 80 | $compressor->expects($this->once()) 81 | ->method('compress') 82 | ->with($image) 83 | ->will($this->returnValue('/tmp/foobar_compressed')); 84 | 85 | $this->fileHandler->expects($this->at(1)) 86 | ->method('getFileSize') 87 | ->with('/tmp/foobar') 88 | ->will($this->returnValue(1000)); 89 | 90 | $this->fileHandler->expects($this->at(2)) 91 | ->method('getFileSize') 92 | ->with('/tmp/foobar_compressed') 93 | ->will($this->returnValue(500)); 94 | 95 | $this->fileHandler->expects($this->at(3)) 96 | ->method('getFileContent') 97 | ->with('/tmp/foobar_compressed') 98 | ->will($this->returnValue('Foobar')); 99 | 100 | $this->fileHandler->expects($this->at(4)) 101 | ->method('delete') 102 | ->with('/tmp/foobar_compressed'); 103 | 104 | $this->object->addCompressor($compressor); 105 | $result = $this->object->minify($image, ['name' => 'foobar']); 106 | 107 | $this->assertEquals('IngoWalther\ImageMinifyApi\Response\CompressedFileResponse', get_class($result)); 108 | } 109 | 110 | public function testWithMatchingCompressorAndNewFileBigger() 111 | { 112 | $image = $this->createMockFile(); 113 | 114 | $this->fileHandler->expects($this->once()) 115 | ->method('getFileType') 116 | ->with('/tmp/foobar') 117 | ->will($this->returnValue('image/jpeg')); 118 | 119 | $compressor = $this->createMockCompressor('image/jpeg'); 120 | 121 | $compressor->expects($this->once()) 122 | ->method('compress') 123 | ->with($image) 124 | ->will($this->returnValue('/tmp/foobar_compressed')); 125 | 126 | $this->fileHandler->expects($this->at(1)) 127 | ->method('getFileSize') 128 | ->with('/tmp/foobar') 129 | ->will($this->returnValue(1000)); 130 | 131 | $this->fileHandler->expects($this->at(2)) 132 | ->method('getFileSize') 133 | ->with('/tmp/foobar_compressed') 134 | ->will($this->returnValue(1001)); 135 | 136 | $this->fileHandler->expects($this->at(3)) 137 | ->method('getFileContent') 138 | ->with('/tmp/foobar') 139 | ->will($this->returnValue('Foobar')); 140 | 141 | $this->fileHandler->expects($this->at(4)) 142 | ->method('delete') 143 | ->with('/tmp/foobar_compressed'); 144 | 145 | $this->object->addCompressor($compressor); 146 | $result = $this->object->minify($image, ['name' => 'foobar']); 147 | 148 | $this->assertEquals('IngoWalther\ImageMinifyApi\Response\CompressedFileResponse', get_class($result)); 149 | 150 | $resultData = json_decode($result->getContent()); 151 | 152 | $this->assertEquals(1000, $resultData->newSize); 153 | $this->assertEquals(0, $resultData->saving); 154 | } 155 | 156 | private function createMockFile() 157 | { 158 | $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile') 159 | ->setConstructorArgs(array('/tmp/test', 'test', null, null, 'test')) 160 | ->getMock(); 161 | 162 | $file->expects($this->any()) 163 | ->method('getRealPath') 164 | ->will($this->returnValue('/tmp/foobar')); 165 | 166 | return $file; 167 | } 168 | 169 | private function createMockCompressor($type, $installed = true) 170 | { 171 | $compressor = $this->getMockBuilder('IngoWalther\ImageMinifyApi\Compressor\MozJpegCompressor') 172 | ->disableOriginalConstructor(true) 173 | ->getMock(); 174 | 175 | $compressor->expects($this->any()) 176 | ->method('getFileTypeToHandle') 177 | ->will($this->returnValue($type)); 178 | 179 | $compressor->expects($this->any()) 180 | ->method('checkLibaryIsInstalled') 181 | ->will($this->returnValue($installed)); 182 | 183 | return $compressor; 184 | } 185 | 186 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Test/Security/ApiKeyCheckTest.php: -------------------------------------------------------------------------------- 1 | userRepository = $this->getMockBuilder('IngoWalther\ImageMinifyApi\Database\UserRepository') 23 | ->disableOriginalConstructor(true) 24 | ->getMock(); 25 | 26 | $this->object = new ApiKeyCheck($this->userRepository); 27 | } 28 | 29 | public function testCheckWithInvalidAPIKey() 30 | { 31 | $this->userRepository->expects($this->once()) 32 | ->method('findUserByKey') 33 | ->with('invalid') 34 | ->will($this->returnValue(false)); 35 | 36 | $this->setExpectedException('Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException'); 37 | $this->object->check('invalid'); 38 | } 39 | 40 | public function testWithValidAPIKey() 41 | { 42 | $fakeUser = array('fakeuser' => true); 43 | 44 | $this->userRepository->expects($this->once()) 45 | ->method('findUserByKey') 46 | ->with('valid') 47 | ->will($this->returnValue($fakeUser)); 48 | 49 | $result = $this->object->check('valid'); 50 | $this->assertEquals($fakeUser, $result); 51 | } 52 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Test/Security/ApiKeyGeneratorTest.php: -------------------------------------------------------------------------------- 1 | userRepository = $this->getMockBuilder('IngoWalther\ImageMinifyApi\Database\UserRepository') 27 | ->disableOriginalConstructor(true) 28 | ->getMock(); 29 | 30 | $this->randomStringGenerator = $this->getMockBuilder('IngoWalther\ImageMinifyApi\Security\RandomStringGenerator') 31 | ->getMock(); 32 | 33 | $this->object = new ApiKeyGenerator($this->userRepository, $this->randomStringGenerator); 34 | } 35 | 36 | public function testWithTakenUsername() 37 | { 38 | $username = 'taken'; 39 | 40 | $this->userRepository->expects($this->once()) 41 | ->method('findUserByName') 42 | ->with($username) 43 | ->will($this->returnValue(array('user' => 'peter'))); 44 | 45 | $this->setExpectedException('Exception'); 46 | $this->object->generate($username); 47 | } 48 | 49 | public function testWithFreeUsername() 50 | { 51 | $username = 'free'; 52 | 53 | $this->userRepository->expects($this->at(0)) 54 | ->method('findUserByName') 55 | ->with($username) 56 | ->will($this->returnValue(false)); 57 | 58 | $this->randomStringGenerator->expects($this->at(0)) 59 | ->method('generate') 60 | ->will($this->returnValue('taken1')); 61 | 62 | $this->randomStringGenerator->expects($this->at(1)) 63 | ->method('generate') 64 | ->will($this->returnValue('taken2')); 65 | 66 | $this->randomStringGenerator->expects($this->at(2)) 67 | ->method('generate') 68 | ->will($this->returnValue('freeKey')); 69 | 70 | $this->userRepository->expects($this->at(1)) 71 | ->method('findUserByKey') 72 | ->with('taken1') 73 | ->will($this->returnValue(array('user' => 'peter'))); 74 | 75 | $this->userRepository->expects($this->at(2)) 76 | ->method('findUserByKey') 77 | ->with('taken2') 78 | ->will($this->returnValue(array('user' => 'peter2'))); 79 | 80 | $this->userRepository->expects($this->at(3)) 81 | ->method('findUserByKey') 82 | ->with('freeKey') 83 | ->will($this->returnValue(false)); 84 | 85 | $this->userRepository->expects($this->at(4)) 86 | ->method('addUser') 87 | ->with('free', 'freeKey'); 88 | 89 | $key = $this->object->generate($username); 90 | 91 | $this->assertEquals('freeKey', $key); 92 | } 93 | 94 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Test/Validator/RequestValidatorTest.php: -------------------------------------------------------------------------------- 1 | object = new RequestValidator(); 18 | } 19 | 20 | public function testWithOnePostFieldNotSet() 21 | { 22 | $this->object->setRequiredPostFields(['foo', 'bar', 'baz']); 23 | $this->object->setRequiredFileFields([]); 24 | 25 | $request = new Request(); 26 | $request->request->set('foo', '1'); 27 | $request->request->set('bar', '2'); 28 | 29 | $this->setExpectedException('InvalidArgumentException'); 30 | $this->object->validateRequest($request); 31 | } 32 | 33 | public function testWithAllPostFieldSetAndNoFileFieldRequired() 34 | { 35 | $this->object->setRequiredPostFields(['foo', 'bar', 'baz']); 36 | $this->object->setRequiredFileFields([]); 37 | 38 | $request = new Request(); 39 | $request->request->set('foo', '1'); 40 | $request->request->set('bar', '2'); 41 | $request->request->set('baz', '3'); 42 | 43 | $this->object->validateRequest($request); 44 | } 45 | 46 | public function testWithAllPostFieldSetAndRequiredFileFieldNotSet() 47 | { 48 | $this->object->setRequiredPostFields(['foo', 'bar', 'baz']); 49 | $this->object->setRequiredFileFields(['file', 'file2']); 50 | 51 | $request = new Request(); 52 | $request->request->set('foo', '1'); 53 | $request->request->set('bar', '2'); 54 | $request->request->set('baz', '3'); 55 | 56 | $request->files->set('file', array()); 57 | 58 | $this->setExpectedException('InvalidArgumentException'); 59 | $this->object->validateRequest($request); 60 | } 61 | 62 | public function testWithAllPostFieldSetAndAllFileFieldsSet() 63 | { 64 | $this->object->setRequiredPostFields(['foo', 'bar', 'baz']); 65 | $this->object->setRequiredFileFields(['file', 'file2']); 66 | 67 | $request = new Request(); 68 | $request->request->set('foo', '1'); 69 | $request->request->set('bar', '2'); 70 | $request->request->set('baz', '3'); 71 | 72 | $request->files->set('file', array()); 73 | $request->files->set('file2', array()); 74 | 75 | $this->object->validateRequest($request); 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/IngoWalther/ImageMinifyApi/Validator/RequestValidator.php: -------------------------------------------------------------------------------- 1 | validatePostFields($request); 29 | $this->validateFileFields($request); 30 | } 31 | 32 | /** 33 | * @param Request $request 34 | */ 35 | private function validatePostFields(Request $request) 36 | { 37 | foreach($this->requiredPostFields as $field) { 38 | $this->validatePostField($request, $field); 39 | } 40 | } 41 | 42 | /** 43 | * @param Request $request 44 | * @param $field 45 | */ 46 | private function validatePostField(Request $request, $field) 47 | { 48 | if (!$request->request->has($field)) { 49 | throw new \InvalidArgumentException(sprintf('Postfield "%s" must be set', $field)); 50 | } 51 | } 52 | 53 | /** 54 | * @param Request $request 55 | */ 56 | private function validateFileFields(Request $request) 57 | { 58 | foreach($this->requiredFileFields as $field) { 59 | $this->validateFileField($request, $field); 60 | } 61 | } 62 | 63 | /** 64 | * @param Request $request 65 | * @param $field 66 | */ 67 | private function validateFileField(Request $request, $field) 68 | { 69 | if (!$request->files->has($field)) { 70 | throw new \InvalidArgumentException(sprintf('Filefield "%s" must be set', $field)); 71 | } 72 | } 73 | 74 | /** 75 | * @param array $requiredFileFields 76 | */ 77 | public function setRequiredFileFields($requiredFileFields) 78 | { 79 | $this->requiredFileFields = $requiredFileFields; 80 | } 81 | 82 | /** 83 | * @param array $requiredPostFields 84 | */ 85 | public function setRequiredPostFields($requiredPostFields) 86 | { 87 | $this->requiredPostFields = $requiredPostFields; 88 | } 89 | } -------------------------------------------------------------------------------- /web/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Options -MultiViews 3 | 4 | RewriteEngine On 5 | RewriteCond %{REQUEST_FILENAME} !-f 6 | RewriteRule ^ index.php [QSA,L] 7 | -------------------------------------------------------------------------------- /web/index.php: -------------------------------------------------------------------------------- 1 | build(realpath(__DIR__ . '/../')); 13 | 14 | $app->post('/minify', function(Request $request) use ($container) { 15 | 16 | $validator = new RequestValidator(); 17 | $validator->validateRequest($request); 18 | 19 | $apiKeyCheck = $container->get('apiKeyCheck'); 20 | $user = $apiKeyCheck->check($request->request->get('api_key')); 21 | 22 | $minify = $container->get('minify'); 23 | $result = $minify->minify($request->files->get('image'), $user); 24 | 25 | return $result; 26 | }); 27 | 28 | $app->error(function (\Exception $e, $code) use ($container) { 29 | $errorHandler = $container->get('errorHandler'); 30 | return $errorHandler->handle($e, $code); 31 | }); 32 | 33 | $app->run(); 34 | --------------------------------------------------------------------------------