Alpine418 Posted Saturday at 10:04 PM Share Posted Saturday at 10:04 PM (edited) 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 Monday at 07:04 AM by Alpine418 Link to comment Share on other sites More sharing options...
Alpine418 Posted Monday at 06:59 AM Author Share Posted Monday at 06:59 AM (edited) 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 Monday at 07:10 AM by Alpine418 6 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now