How to block access to files

The problem here is that you want to apply the protected files to all pages, not a specific page like in the recipe. Therefore, you need something in your file route, that let’s you differentiate between a page and a file. The easiest way to achieve this, is to use a string between the page id and the filename in the file url:

Kirby::plugin('cookbook/files-firewall', [
  'components'   => [
    'file::url' => function ($kirby, $file) {
      return $kirby->url() . '/' . $file->parent()->id() . '/protected/' . $file->filename();
    },
    'file::version' => function ($kirby, $file, array $options = []) {
        return $file;
    },
  ]
]);

protected is just an example, you can change this to something else.

Then we can change our routes like this:

    'routes' => [
        [
            'pattern' => '(:all)',
            'action' => function ($id) {
                if (!kirby()->user()) {
                    return page('login');
                }
                $this->next();
            }
        ],
        [
            'pattern' => '(:all)/protected/(:any)',
            'action' => function ($pageId, $filename) {
                if (
                    kirby()->user() &&
                    ($page = page($pageId)) &&
                    $file = $page->files()->findBy('filename', $filename)
                ) {
                    return $file->read();
                }
                return site()->errorPage();
            }
        ],
        [
            'pattern' => 'logout',
            'action'  => function () {

                if ($user = kirby()->user()) {
                    $user->logout();
                }

                go('login');
            }
        ]
    ]
  • The first route takes care of pages.
  • The second route is for the files. We separate page id and filename by the string we inserted into the url in the file:url component.
  • If we can find a file, we return it with $file->read().

Note that with this approach, we don’t use any thumbs.