Streaming an MP3 on stdout to Jplayer using PHP

2020-04-19 05:53发布

I'm initializing jplayer with the following parameters:

$jplayer.jPlayer('setMedia',{
  mp3: data.audioMP3,
  oga: data.audioOGA
});

Assume that data.autdioMP3 (and it's OGA counterpart) are paths to a php script, for example: 'http://myserver.local/playaudio.php?songID=99&format=mp3'

Where I am struggling is with playaudio.php. I would like to read the MP3 file and stream it to jplayer without revealing the path to the audio (this is why I am not initializing jplayer with a path to the audio file).

Something like (taken partially from the example for readfile at php docs):

<?php

$if ($validUser && file_exists($file){
     header('Content-Transfer-Encoding: binary');
     header('Content-Type: audio/mpeg');
     header('Expires: 0');
     header('Cache-Control: must-revalidate');
     header('Content-Length: ' . filesize($file));
     ob_clean();
     flush();
     readfile($file);
     exit;
}
?>

I think this just forces the download of the file though... will this still reveal the path to the file to the user? Is there a better option to stream raw mp3 data to the user without revealing the path to the file that you know of?

Thanks!

3条回答
Lonely孤独者°
2楼-- · 2020-04-19 06:20

Thanks for everyone's answers.

I actually ended up solving the problem without revealing the path to the audio file to the user.

Because this is for an online voice messaging application, it was important to protect the path to the messages in order to protect the user's privacy.

The situation ended up being further complicated by the fact that the messages are stored on a remote server... found this out right after I posted this question.

So all in all the process was:

1) Curl the MP3 file from the remote server

2) Set some headers to force the download of the data, which you then echo to stdout

Because the data is being put on standard out and the headers are set to force a download, the effect for jPlayer is the same as if it had requested a file at /some/dir/message.mp3, except that the request goes to /some/dir/playmessage.php - thus the path is never revealed to the user.

EDIT** - Assume that I have access control, validation running before the snippit below, otherwise exposing the path to the script below is no different than just exposing the path to the mp3. (see comments between me and Lloyd)

Here's the code that ended up getting the job done:

$ch = curl_init($remoteFile);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
$data = curl_exec($ch);
curl_close($ch);
if ($data === false) {
  echo 'CURL Failed';
  exit;
}

//Get file size
if (preg_match('/Content-Length: (\d+)/', $data, $matches)) {
  $contentLength = (int)$matches[1];
}

//force user to download file contents
header('Content-Transfer-Encoding: binary');
header('Content-Type: audio/mpeg');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Content-Length: ' . $contentLength);
ob_clean();
flush();
echo $data;
exit;
?>

Assume that $remoteFile is a path to the mp3 file that I want to play on the server where we are storing messages.

I found this resource on reading a remote file using PHP especially helpful. Here's some more information on modifying http headers.

NOTE I am essentially downloading the file twice, which slows the process down for the user. There is probably a better way to do this. :) If you kept the file locally, what I had initially in my question actually works (using readfile() to output the raw mp3 data).

查看更多
▲ chillily
3楼-- · 2020-04-19 06:29

Since you are using javascript to get the file, others can do the same by reading the headers/file requests from the browser (firebug, Chrome's default tools, etc).

The best way to protect your files from being downloaded is to make a series of checks to get at the data. It's not perfect, but it will deter all but the most determined. For some ideas, check out this page on Grooveshark's API (This is a bit old and some info is missing, so it's the perfect reference), or just visit Grooveshark/Youtube and see how they protect their content.

It is possible to recreate this kind of security with some clever usage of sessions and a good database.

查看更多
一纸荒年 Trace。
4楼-- · 2020-04-19 06:38

i think you'll struggle to prevent users discovering your media content URL, i'd say it was pretty much impossible (a quick look at the 'Network' tab on Chrome would reveal your loaded track, regardless how you coded playaudio.php).

I'd say you were better off sticking to publishing media you don't mind sharing with the world.. Or just publish

  • A n second preview
  • A lesser quality version, e.g. 90bps / Mono

If you really wanted to protect your resources, you could use oAuth or Access Control at the server side.

查看更多
登录 后发表回答