Jump to content

Session-based download links


Alpine418
 Share

Recommended Posts

Hi guys,

I want to publish some mp3 files on my website. But I want to prevent users from linking directly to the mp3 file. Instead of using some .htaccess request hacks I want to handle it with proper session based links. Something like https://foo.bar/site/assets /[session id]/[page id]/my-fancy-song.mp3

Once the session expires, the link to the mp3 file won't work. Does ProcessWire already provide such a solution or do I have to create it myself? Does anyone have any experience with this?

Thank you for your support!

Edited by Alpine418
Link to comment
Share on other sites

I solved it myself by the following code.

1. Create a custom RepeaterPage class for my tracks and add a specific method to create a session-based URL for streaming.

<?php namespace ProcessWire;

/**
 * @property Pagefile $audio
 */
class TracksRepeaterPage extends RepeaterPage
{
    /**
     * @param string $streamUrl Default stream URL when audio file does not exist
     *
     * @return string
     */
    public function getStreamUrl(string $streamUrl = ''): string
    {
        // Check whether audio file exists and if it does create a session-based stream URL
        if ($this->audio) {

            // Create the file hash and add it to the session as key for the audio file path
            $audioPath = $this->audio->filename();
            $fileHash = hash('sha1', $audioPath . session_id());
            session()->setFor('stream', $fileHash, $audioPath);

            // Create the stream URL with the file hash
            $streamUrl =  '/stream/' . $fileHash . '.mp3';
        }
        return $streamUrl;
    }
}

2. Create a custom hook to watch for the stream URL in the ready.php:

<?php namespace ProcessWire;

if (!defined("PROCESSWIRE")) {
    die();
}

wire()->addHook('/stream/([\w\d]+).mp3', function ($event) {
    // Get the audio file path by file hash
    $fileHash = $event->arguments(1);
    $audioPath = session()->getFor('stream', $fileHash);

    // Check whether audio file exists and stream it when it does or throw 404
    if (file_exists($audioPath)) {
        wireSendFile($audioPath, [], [
            'content-transfer-encoding' => 'chunked',
            'accept-ranges' => 'bytes',
            'cache-control' => 'no-cache'
        ]);
    }
    throw new Wire404Exception();
});

Ta da! 🙂 When the session expires, the session-based file hashes are destroyed and the stream URL no longer work. So every time the session is renewed with a new session ID, a new unique session-based stream URL is generated for each tracks.

Have I missed anything or are there any security issues?

Edited by Alpine418
  • Like 6
  • Thanks 1
Link to comment
Share on other sites

  • Alpine418 changed the title to Session-based download links

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...