Alpine418 Posted November 23, 2024 Share Posted November 23, 2024 (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 November 25, 2024 by Alpine418 Link to comment Share on other sites More sharing options...
Alpine418 Posted November 25, 2024 Author Share Posted November 25, 2024 (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 November 25, 2024 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