diff --git a/.platform.app.yaml b/.platform.app.yaml index e6a072d..d415a84 100644 --- a/.platform.app.yaml +++ b/.platform.app.yaml @@ -6,6 +6,8 @@ build: runtime: extensions: + # Enable the event PHP extension, which provides a faster core event loop. + - event - newrelic - name: 'blackfire' @@ -42,16 +44,14 @@ relationships: database: "database:mysql" web: - locations: - '/': - # The public directory of the application relative to its root. - root: 'web' - # The front-controller script which determines where to send - # non-static requests. - passthru: '/index.php' + commands: + start: ./console serve + upstream: + socket_family: tcp + protocol: http crons: # Look for new emails every 5 minutes. - drush-queue: + sync: spec: '*/5 * * * *' cmd: './console sync' diff --git a/Makefile b/Makefile index 5571c93..0c17caa 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ preview: - ENV=dev php -S localhost:8000 -t web + ENV=dev ./console serve install: set -e diff --git a/composer.json b/composer.json index 348bff2..43868e7 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,9 @@ "rvdv/nntp": "dev-preserve-empty-lines@dev", "zbateson/mail-mime-parser": "^0.4.3", "vlucas/phpdotenv": "^2.4", - "sentry/sentry": "^1.7" + "sentry/sentry": "^1.7", + "react/http": "^0.7.2", + "blackfire/php-sdk": "^1.8" }, "require-dev": { "phpunit/phpunit": "^6.0" diff --git a/composer.lock b/composer.lock index 20e50df..5d6da8c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "773f53ee7f246794653d94abf1981d37", + "content-hash": "ae88cc9e5f02c6b3129cd87765a2f1fb", "packages": [ { "name": "algolia/algoliasearch-client-php", @@ -106,6 +106,121 @@ ], "time": "2017-03-02T16:34:47+00:00" }, + { + "name": "blackfire/php-sdk", + "version": "v1.8.0", + "source": { + "type": "git", + "url": "https://github.com/blackfireio/php-sdk.git", + "reference": "0a238130577c9c1b91606cb92795f44b7ec077cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/blackfireio/php-sdk/zipball/0a238130577c9c1b91606cb92795f44b7ec077cc", + "reference": "0a238130577c9c1b91606cb92795f44b7ec077cc", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "php": ">=5.2.0" + }, + "suggest": { + "ext-blackfire": "The C version of the Blackfire probe", + "ext-xhprof": "XHProf is required as a fallback", + "ext-zlib": "To push config to remote profiling targets" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "files": [ + "src/autostart.php" + ], + "psr-4": { + "Blackfire\\": "src/Blackfire" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Blackfire.io", + "email": "support@blackfire.io" + } + ], + "description": "Blackfire.io PHP SDK", + "keywords": [ + "performance", + "profiler", + "uprofiler", + "xhprof" + ], + "time": "2017-06-15T14:44:12+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/b17e6153cb7f33c7e44eb59578dc12eee5dc8e12", + "reference": "b17e6153cb7f33c7e44eb59578dc12eee5dc8e12", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.5", + "psr/log": "^1.0", + "symfony/process": "^2.5 || ^3.0" + }, + "suggest": { + "symfony/process": "This is necessary to reliably check whether openssl_x509_parse is vulnerable on older php versions, but can be ignored on PHP 5.5.6+" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "time": "2017-03-06T11:59:08+00:00" + }, { "name": "dflydev/fig-cookies", "version": "v1.0.2", @@ -628,6 +743,52 @@ ], "time": "2014-09-09T13:34:57+00:00" }, + { + "name": "evenement/evenement", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", + "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch", + "homepage": "http://wiedler.ch/igor/" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "time": "2012-11-02T14:49:47+00:00" + }, { "name": "filp/whoops", "version": "2.1.9", @@ -2027,6 +2188,424 @@ ], "time": "2016-05-29T13:39:13+00:00" }, + { + "name": "react/cache", + "version": "v0.4.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "558f614891341b1d817a8cdf9a358948ec49638f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/558f614891341b1d817a8cdf9a358948ec49638f", + "reference": "558f614891341b1d817a8cdf9a358948ec49638f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "~2.0|~1.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src\\" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Async caching.", + "keywords": [ + "cache" + ], + "time": "2016-02-25T18:17:16+00:00" + }, + { + "name": "react/dns", + "version": "v0.4.9", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "288b4f36972cdc2f81dae1d1a58a0467e3f625cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/288b4f36972cdc2f81dae1d1a58a0467e3f625cb", + "reference": "288b4f36972cdc2f81dae1d1a58a0467e3f625cb", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "~0.4.0|~0.3.0", + "react/promise": "~2.1|~1.2", + "react/promise-timer": "~1.1", + "react/socket": "^1.0 || ^0.8 || ^0.7 || ^0.6 || ^0.5 || ^0.4.4", + "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.5" + }, + "require-dev": { + "phpunit/phpunit": "^5.0 || ^4.8.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "dns", + "dns-resolver" + ], + "time": "2017-05-01T17:21:03+00:00" + }, + { + "name": "react/event-loop", + "version": "v0.4.3", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "8bde03488ee897dc6bb3d91e4e17c353f9c5252f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/8bde03488ee897dc6bb3d91e4e17c353f9c5252f", + "reference": "8bde03488ee897dc6bb3d91e4e17c353f9c5252f", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-event": "~1.0", + "ext-libev": "*", + "ext-libevent": ">=0.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Event loop abstraction layer that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "time": "2017-04-27T10:56:23+00:00" + }, + { + "name": "react/http", + "version": "v0.7.2", + "source": { + "type": "git", + "url": "https://github.com/reactphp/http.git", + "reference": "32f0eb3d445b1871b2ba859480ee1981977598f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/http/zipball/32f0eb3d445b1871b2ba859480ee1981977598f4", + "reference": "32f0eb3d445b1871b2ba859480ee1981977598f4", + "shasum": "" + }, + "require": { + "evenement/evenement": "^2.0 || ^1.0", + "php": ">=5.3.0", + "react/promise": "^2.1 || ^1.2.1", + "react/socket": "^1.0 || ^0.8 || ^0.7 || ^0.6 || ^0.5", + "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.6", + "ringcentral/psr7": "^1.2" + }, + "require-dev": { + "clue/block-react": "^1.1", + "phpunit/phpunit": "^4.8.10||^5.0", + "react/promise-stream": "^0.1.1", + "react/socket": "^1.0 || ^0.8 || ^0.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Event-driven, streaming plaintext HTTP and secure HTTPS server for ReactPHP", + "keywords": [ + "event-driven", + "http", + "https", + "reactphp", + "server", + "streaming" + ], + "time": "2017-07-04T13:15:44+00:00" + }, + { + "name": "react/promise", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "62785ae604c8d69725d693eb370e1d67e94c4053" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/62785ae604c8d69725d693eb370e1d67e94c4053", + "reference": "62785ae604c8d69725d693eb370e1d67e94c4053", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "time": "2017-03-25T12:08:31+00:00" + }, + { + "name": "react/promise-timer", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise-timer.git", + "reference": "ddedc67bfd7f579fc83e66ff67e3564b179297dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/ddedc67bfd7f579fc83e66ff67e3564b179297dd", + "reference": "ddedc67bfd7f579fc83e66ff67e3564b179297dd", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/event-loop": "~0.4.0|~0.3.0", + "react/promise": "~2.1|~1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Promise\\Timer\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@lueck.tv" + } + ], + "description": "Trivial timeout implementation for Promises", + "homepage": "https://github.com/react/promise-timer", + "keywords": [ + "async", + "event-loop", + "promise", + "reactphp", + "timeout", + "timer" + ], + "time": "2016-12-27T08:12:19+00:00" + }, + { + "name": "react/socket", + "version": "v0.8.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "8f880ab1a9e1b2eb236a836aa5e1326da3647bcd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/8f880ab1a9e1b2eb236a836aa5e1326da3647bcd", + "reference": "8f880ab1a9e1b2eb236a836aa5e1326da3647bcd", + "shasum": "" + }, + "require": { + "evenement/evenement": "~2.0|~1.0", + "php": ">=5.3.0", + "react/dns": "0.4.*|0.3.*", + "react/event-loop": "0.4.*|0.3.*", + "react/promise": "^2.1 || ^1.2", + "react/promise-timer": "~1.0", + "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.5" + }, + "require-dev": { + "clue/block-react": "^1.1", + "phpunit/phpunit": "~4.8", + "react/stream": "^1.0 || ^0.7 || ^0.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "time": "2017-05-09T11:27:38+00:00" + }, + { + "name": "react/stream", + "version": "v0.7.2", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "a7ea0af02c00f1fc004d654f9ee1e2b900e53d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/a7ea0af02c00f1fc004d654f9ee1e2b900e53d5b", + "reference": "a7ea0af02c00f1fc004d654f9ee1e2b900e53d5b", + "shasum": "" + }, + "require": { + "evenement/evenement": "^2.0|^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^5.0 || ^4.8.10" + }, + "suggest": { + "react/event-loop": "^0.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "time": "2017-06-15T20:26:53+00:00" + }, + { + "name": "ringcentral/psr7", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/ringcentral/psr7.git", + "reference": "2594fb47cdc659f3fcf0aa1559b7355460555303" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ringcentral/psr7/zipball/2594fb47cdc659f3fcf0aa1559b7355460555303", + "reference": "2594fb47cdc659f3fcf0aa1559b7355460555303", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "RingCentral\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2016-03-25T17:36:49+00:00" + }, { "name": "rvdv/nntp", "version": "dev-preserve-empty-lines", diff --git a/console b/console index e371f49..800301d 100755 --- a/console +++ b/console @@ -2,10 +2,14 @@ cli(); +$cli->command('serve', function (\Stratify\Http\Application $http, ContainerInterface $container, OutputInterface $output) { + $loop = React\EventLoop\Factory::create(); + + $db = $container->get(Connection::class); + + $server = new Server(function (ServerRequestInterface $request) use ($http, $db) : ResponseInterface { + // Reset the DB connection + $db->close(); + return $http->handle($request); + }); + $server->listen(new React\Socket\Server($container->get('http.port'), $loop)); + $server->on('error', function (Exception $e) use ($output) { + $output->writeln("Error: {$e->getMessage()}"); + if ($e->getPrevious() !== null) { + $e = $e->getPrevious(); + $output->writeln("Caused by: {$e->getMessage()}"); + } + $output->writeln($e->getTraceAsString()); + }); + + $loop->run(); +}); + $cli->command('db [--force]', [DbCommand::class, 'setup']); $cli->command('db-purge [--force]', [DbCommand::class, 'purge']); $cli->command('db-truncate [--force]', [DbCommand::class, 'truncate']); diff --git a/res/config/config.php b/res/config/config.php index bd72032..9510f3c 100644 --- a/res/config/config.php +++ b/res/config/config.php @@ -11,6 +11,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; use Externals\Application\Database\CustomMySQLPlatform; +use Externals\Application\Middleware\AssetsMiddleware; use Externals\Application\Middleware\MaintenanceMiddleware; use Externals\Search\AlgoliaSearchIndex; use Externals\Search\SearchIndex; @@ -34,6 +35,10 @@ 'debug' => false, 'path.cache' => __DIR__ . '/../../var/cache', 'path.logs' => __DIR__ . '/../../var/log', + 'path.public' => __DIR__ . '/../../web', + + // Platform.sh defines this variable + 'http.port' => env('PORT', 8000), 'version' => env('PLATFORM_TREE_ID', factory(function () { return trim(shell_exec('git rev-parse HEAD')); @@ -113,6 +118,9 @@ return SessionMiddleware::fromSymmetricKeyDefaults($key, 31536000); }, + AssetsMiddleware::class => create() + ->constructor(get('path.public')), + 'sentry.url' => env('SENTRY_URL', null), MaintenanceMiddleware::class => autowire() diff --git a/res/http.php b/res/http.php index 746add6..60129f4 100644 --- a/res/http.php +++ b/res/http.php @@ -4,8 +4,11 @@ use Doctrine\DBAL\Connection; use Externals\Application\Controller\UserController; use Externals\Application\Controller\NotFoundController; +use Externals\Application\Middleware\AssetsMiddleware; use Externals\Application\Middleware\AuthMiddleware; +use Externals\Application\Middleware\BlackfireMiddleware; use Externals\Application\Middleware\MaintenanceMiddleware; +use Externals\Application\Middleware\NewRelicMiddleware; use Externals\Application\Middleware\NotFoundMiddleware; use Externals\Application\Middleware\SessionMiddleware; use Externals\Email\EmailRepository; @@ -27,8 +30,11 @@ * HTTP stack. */ return pipe([ + BlackfireMiddleware::class, + NewRelicMiddleware::class, MaintenanceMiddleware::class, ErrorHandlerMiddleware::class, + AssetsMiddleware::class, NotFoundMiddleware::class, SessionMiddleware::class, AuthMiddleware::class, @@ -141,6 +147,7 @@ // Keep backward compatibility with old URLs (old threads) '/thread/{id}' => route(function (int $id, EmailRepository $emailRepository, Connection $db) { + newrelic_name_transaction('thread_legacy'); $threadSubject = $db->fetchColumn('SELECT `subject` FROM threads_old WHERE id = ?', [$id]); $email = $emailRepository->findBySubject($threadSubject); // Permanent redirection diff --git a/src/Application/Middleware/AssetsMiddleware.php b/src/Application/Middleware/AssetsMiddleware.php new file mode 100644 index 0000000..81e40c6 --- /dev/null +++ b/src/Application/Middleware/AssetsMiddleware.php @@ -0,0 +1,104 @@ + + */ +class AssetsMiddleware implements Middleware +{ + /** + * @var string + */ + private $publicPath; + + public function __construct(string $publicPath) + { + $this->publicPath = rtrim($publicPath, '/') . '/'; + } + + public function __invoke(ServerRequestInterface $request, callable $next) : ResponseInterface + { + $path = $request->getUri()->getPath(); + + $file = $this->publicPath . $path; + + if (!is_file($file)) { + return $next($request); + } + + $body = new Stream($file); + + $array = explode('.', $file); + $extension = strtolower(array_pop($array)); + $mimeType = self::MIME_TYPES[$extension] ?? 'application/octet-stream'; + + return new Response($body, 200, [ + 'Content-Type' => $mimeType, + ]); + } + + private const MIME_TYPES = [ + 'txt' => 'text/plain', + 'htm' => 'text/html', + 'html' => 'text/html', + 'php' => 'text/html', + 'css' => 'text/css', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'xml' => 'application/xml', + 'swf' => 'application/x-shockwave-flash', + 'flv' => 'video/x-flv', + + // images + 'png' => 'image/png', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + 'ico' => 'image/vnd.microsoft.icon', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + + // archives + 'zip' => 'application/zip', + 'rar' => 'application/x-rar-compressed', + 'exe' => 'application/x-msdownload', + 'msi' => 'application/x-msdownload', + 'cab' => 'application/vnd.ms-cab-compressed', + + // audio/video + 'mp3' => 'audio/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + + // adobe + 'pdf' => 'application/pdf', + 'psd' => 'image/vnd.adobe.photoshop', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + + // ms office + 'doc' => 'application/msword', + 'rtf' => 'application/rtf', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + + // open office + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + ]; +} diff --git a/src/Application/Middleware/BlackfireMiddleware.php b/src/Application/Middleware/BlackfireMiddleware.php new file mode 100644 index 0000000..1d09067 --- /dev/null +++ b/src/Application/Middleware/BlackfireMiddleware.php @@ -0,0 +1,41 @@ + + */ +class BlackfireMiddleware +{ + public function __invoke(ServerRequestInterface $request, callable $next) : ResponseInterface + { + $query = $request->getHeaderLine('x-blackfire-query'); + + // Only enable when the X-Blackfire-Query header is present + if (! $query) { + return $next($request); + } + + $probe = new \BlackfireProbe($query); + if (! $probe->enable()) { + return $next($request); + } + + /** @var ResponseInterface $response */ + $response = $next($request); + + // Stop profiling once the request ends + $probe->close(); + + // Return the header + $header = explode(':', $probe->getResponseLine(), 2); + + return $response->withHeader('x-' . $header[0], trim($header[1])); + } +} diff --git a/src/Application/Middleware/NewRelicMiddleware.php b/src/Application/Middleware/NewRelicMiddleware.php new file mode 100644 index 0000000..c97589b --- /dev/null +++ b/src/Application/Middleware/NewRelicMiddleware.php @@ -0,0 +1,28 @@ + + */ +class NewRelicMiddleware +{ + public function __invoke(ServerRequestInterface $request, callable $next) : ResponseInterface + { + newrelic_end_transaction(); + newrelic_start_transaction(ini_get('newrelic.appname')); + + /** @var ResponseInterface $response */ + $response = $next($request); + + newrelic_end_transaction(false); + + return $response; + } +} diff --git a/web/.htaccess b/web/.htaccess deleted file mode 100644 index eaa46cb..0000000 --- a/web/.htaccess +++ /dev/null @@ -1,52 +0,0 @@ -# Use the front controller as index file. It serves as a fallback solution when -# every other rewrite/redirect fails (e.g. in an aliased environment without -# mod_rewrite). Additionally, this reduces the matching process for the -# start page (path "/") because otherwise Apache will apply the rewriting rules -# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). -DirectoryIndex index.php - - - RewriteEngine On - - # Determine the RewriteBase automatically and set it as environment variable. - # If you are using Apache aliases to do mass virtual hosting or installed the - # project in a subdirectory, the base path will be prepended to allow proper - # resolution of the app.php file and to redirect to the correct URI. It will - # work in environments without path prefix as well, providing a safe, one-size - # fits all solution. But as you do not need it in this case, you can comment - # the following 2 lines to eliminate the overhead. - RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ - RewriteRule ^(.*) - [E=BASE:%1] - - # Redirect to URI without front controller to prevent duplicate content - # (with and without `/app.php`). Only do this redirect on the initial - # rewrite by Apache and not on subsequent cycles. Otherwise we would get an - # endless redirect loop (request -> rewrite to front controller -> - # redirect -> request -> ...). - # So in case you get a "too many redirects" error or you always get redirected - # to the start page because your Apache does not expose the REDIRECT_STATUS - # environment variable, you have 2 choices: - # - disable this feature by commenting the following 2 lines or - # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the - # following RewriteCond (best solution) - RewriteCond %{ENV:REDIRECT_STATUS} ^$ - RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L] - - # If the requested filename exists, simply serve it. - # We only want to let Apache serve files and not directories. - RewriteCond %{REQUEST_FILENAME} -f - RewriteRule .? - [L] - - # Rewrite all other queries to the front controller. - RewriteRule .? %{ENV:BASE}/index.php [L] - - - - - # When mod_rewrite is not available, we instruct a temporary redirect of - # the start page to the front controller explicitly so that the website - # and the generated links can still be used. - RedirectMatch 302 ^/$ /index.php/ - # RedirectTemp cannot be used instead - - diff --git a/web/index.php b/web/index.php deleted file mode 100644 index 0a6b10a..0000000 --- a/web/index.php +++ /dev/null @@ -1,14 +0,0 @@ -http()->run();