diff --git a/README.md b/README.md index 56ac582..6b3daaf 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # static-ldp A simple way to expose static HTTP assets as an LDP server. -By placing this `index.php` file in your server's directory root, -a server of static resources becomes a conforming LDP server. +Clone this repository and setup your Apache to use it as +document root. Then configure the `sourceDirectory` to point +to the root directory of your static resources. Individual files are served as `ldp:NonRDFSource` resources, and directories are served as `ldp:BasicContainer` resources. diff --git a/composer.json b/composer.json index 779be8f..4a70ee6 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "require": { - "silex/silex": "^1.3", + "silex/silex": "^2.0", "symfony/config": "^3.0", "symfony/yaml": "^3.0", "easyrdf/easyrdf": "^0.9.1", diff --git a/src/Controller/ResourceController.php b/src/Controller/ResourceController.php index 17e13d7..82bba22 100644 --- a/src/Controller/ResourceController.php +++ b/src/Controller/ResourceController.php @@ -2,33 +2,45 @@ namespace Trellis\StaticLdp\Controller; - +use Silex\Api\ControllerProviderInterface; use Silex\Application; -use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -class ResourceController implements ControllerProviderInterface { +class ResourceController implements ControllerProviderInterface +{ /** * {@inheritdoc} */ - public function connect(Application $app) { + public function connect(Application $app) + { $controllers = $app['controllers_factory']; // // Define routing referring to controller services // - $controllers->get("/{path}", "staticldp.resourcecontroller:get") - ->assert('path','.+') + // Options + $controllers->options("/{path}", "staticldp.resourcecontroller:options") + ->assert('path', '.+') + ->value('path', '') + ->bind('staticldp.serverOptions'); + + // Generic GET. + $controllers->match("/{path}", "staticldp.resourcecontroller:getOrHead") + ->method('HEAD|GET') + ->assert('path', '.+') ->value('path', '') - ->bind('staticldp.resourceGet'); + ->bind('staticldp.resourceGetOrHead'); + + + return $controllers; } /** - * Perform the GET request + * Perform the GET or HEAD request. * * @param \Silex\Application $app * The Silex application. @@ -38,7 +50,8 @@ public function connect(Application $app) { * The path parameter from the request. * @return \Symfony\Component\HttpFoundation\Response */ - public function get(Application $app, Request $request, $path) { + public function getOrHead(Application $app, Request $request, $path) + { $valid_types = [ "text/turtle" => "turtle", @@ -51,19 +64,6 @@ public function get(Application $app, Request $request, $path) { $format = $request->headers->get('accept'); } - $headers = [ - "Link" => "; rel=\"type\"", - "Content-Type" => $format, - ]; - - $namespaces = new \EasyRdf_Namespace(); - $namespaces->set("ldp", "http://www.w3.org/ns/ldp#"); - - $graph = new \EasyRdf_Graph(); - - $subject = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; - $predicate = "http://www.w3.org/ns/ldp#contains"; - $docroot = $app['config']['sourceDirectory']; if (!empty($path)) { $path = "/{$path}"; @@ -74,12 +74,60 @@ public function get(Application $app, Request $request, $path) { return new Response("Not Found", 404); } - foreach(scandir($requested_path) as $filename) { - if (substr($filename, 0, 1) !== ".") { - $graph->addResource($subject, $predicate, $subject . (substr($subject, -1) != '/' ? '/' : '') . $filename); + // It is a file. + if (is_file($requested_path)) { + $mimeType = mime_content_type($requested_path); + $headers = [ + "Link" => "; rel=\"type\"", + "Content-Type" => $mimeType, + "Content-Length" => filesize($requested_path), + ]; + // Only read if we are going to use it. + if ($request->getMethod() == 'GET') { + // Probably best to stream the data out. + // http://silex.sensiolabs.org/doc/2.0/usage.html#streaming + $content = file_get_contents($requested_path); + } + } else { + // Else we assume it is a directory. + $namespaces = new \EasyRdf_Namespace(); + $namespaces->set("ldp", "http://www.w3.org/ns/ldp#"); + + $graph = new \EasyRdf_Graph(); + + $subject = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; + $predicate = "http://www.w3.org/ns/ldp#contains"; + + $headers = [ + "Link" => "; rel=\"type\"", + "Content-Type" => $format, + ]; + + foreach (scandir($requested_path) as $filename) { + if (substr($filename, 0, 1) !== ".") { + $graph->addResource($subject, $predicate, $subject . (substr($subject, -1) != '/' ? '/' : '') . $filename); + } } + $content = $graph->serialise($valid_types[$format]); + $headers["Content-Length"] = strlen($content); } - return new Response($graph->serialise($valid_types[$format]), 200, $headers); + if ($request->getMethod() == "HEAD") { + $content = ""; + } + return new Response($content, 200, $headers); + } + + /** + * Response to a generic options request. + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function options() + { + $headers = [ + "Allow" => "OPTIONS, GET, HEAD", + ]; + return new Response('', 200, $headers); } } diff --git a/src/Provider/ServiceProvider.php b/src/Provider/ServiceProvider.php index ec9d94a..7d11a35 100644 --- a/src/Provider/ServiceProvider.php +++ b/src/Provider/ServiceProvider.php @@ -2,43 +2,34 @@ namespace Trellis\StaticLdp\Provider; -use Silex\Application; -use Silex\ServiceProviderInterface; +use Pimple\Container; +use Pimple\ServiceProviderInterface; use Symfony\Component\Yaml\Yaml; use Trellis\StaticLdp\Controller\ResourceController; -class ServiceProvider implements ServiceProviderInterface { +class ServiceProvider implements ServiceProviderInterface +{ /** * {@inheritdoc} */ - public function register(Application $app) { + public function register(Container $app) + { # Register the ResourceService - $app['staticldp.resourcecontroller'] = $app->share( - function () use ($app) { - return new ResourceController($app); - } - ); + $app['staticldp.resourcecontroller'] = function ($app) { + return new ResourceController($app); + }; + /** * Ultra simplistic YAML settings loader. */ if (!isset($app['config'])) { - $app['config'] = $app->share( - function () use ($app) { - $configFile = $app['basePath'].'/../config/settings.yml'; - $settings = Yaml::parse(file_get_contents($configFile)); - return $settings; - } - ); + $app['config'] = function ($app) { + $configFile = $app['basePath'] . '/../config/settings.yml'; + $settings = Yaml::parse(file_get_contents($configFile)); + return $settings; + }; } } - - /** - * {@inheritdoc} - */ - public function boot(Application $app) { - // TODO: Implement boot() method. - } - -} \ No newline at end of file +} diff --git a/src/app.php b/src/app.php index 2a87a4c..82938eb 100644 --- a/src/app.php +++ b/src/app.php @@ -7,6 +7,8 @@ use Silex\Application; use Psr\Http\Message\ResponseInterface; use Islandora\Crayfish\Provider\CrayfishProvider; +use Silex\Provider\ServiceControllerServiceProvider; +use Silex\Provider\TwigServiceProvider; use Trellis\StaticLdp\Controller\ResourceController; use Trellis\StaticLdp\Provider\ServiceProvider; @@ -16,8 +18,13 @@ $app['debug'] = false; $app['basePath'] = __DIR__; -$app->register(new \Silex\Provider\ServiceControllerServiceProvider()); +$app->register(new ServiceControllerServiceProvider()); $app->register(new ServiceProvider()); +$app->register(new TwigServiceProvider(), array( + 'twig.path' => array( + __DIR__ . '/templates', + ), +)); $app->mount("/", new ResourceController()); -return $app; \ No newline at end of file +return $app;