Files above web root?

4,690 views
Skip to first unread message

YWFTDG

unread,
Mar 10, 2010, 5:29:41 AM3/10/10
to jPlayer: the CSS styleable jQuery audio player plugin
I am trying to load my mp3 files for the player, that are in a more
secure area on the server, above the httpdocs folder. The player
doesn't want to load them though. I have already made sure the folder
can be oped via the conf file for the domain, but still no go. Any
ideas?

Maboa

unread,
Mar 10, 2010, 5:42:31 AM3/10/10
to jPlayer: the CSS styleable jQuery audio player plugin
I really don't think this is possible as the path to the files must
always be a valid URL.

Mark B

YWFTDG

unread,
Mar 10, 2010, 7:07:32 AM3/10/10
to jPlayer: the CSS styleable jQuery audio player plugin
Could it possibly load a php file instead, which would then return the
mp3 file? Talking out of my arse some here, but trying to think of a
secure way to stream these audio files without them being just sitting
out in httpdocs.

Marcos Ojeda

unread,
Mar 10, 2010, 7:56:08 AM3/10/10
to jpl...@googlegroups.com
There is no secure way unless you basically convert the mp3 somehow and then roll your own swf to decode it. and even that's not secure, it's only sorta secure.

The best and easiest 80% solution would be to try referrer checking on the directory that holds the mp3. You can do this in your apache config or possibly htaccess with some code like this:

<FilesMatch "\.(mp3|ogg|m4a)$">
   <IfModule mod_headers.c>
   Header set Access-Control-Allow-Origin "http://yourdomain.tld"
   </IfModule>
</FilesMatch>
This isn't totally surefire, but it will prevent people from typing in the mp3's url and getting back a file. For most people this is good enough.

You could probably accomplish the same thing with a php script, but it would be resource intensive and a waste of your time to write.
--


--
You received this message because you are subscribed to the Google Groups "jPlayer: the CSS styleable jQuery audio player plugin" group.
To post to this group, send email to jpl...@googlegroups.com.
To unsubscribe from this group, send email to jplayer+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/jplayer?hl=en.


Maboa

unread,
Mar 10, 2010, 7:59:36 AM3/10/10
to jPlayer: the CSS styleable jQuery audio player plugin
This is an interesting issue so happy to discuss it. :)

What's to stop someone calling the PHP file directly and then grabbing
the file that way?

I've been wondering whether you could restrict the calling of certain
server-side code to the same domain or IP, these details could maybe
spoofed but it would stop 99% of people downloading the file.

Mark B

Maboa

unread,
Mar 10, 2010, 8:01:42 AM3/10/10
to jPlayer: the CSS styleable jQuery audio player plugin
Ah I see Marcos posted a similar idea while I was typing :)

YWFTDG

unread,
Mar 10, 2010, 9:00:37 AM3/10/10
to jPlayer: the CSS styleable jQuery audio player plugin
Hmm, the htaccess sounds about on target, but I have very limited
knowledge on working with these files, other than basic redirects,
etc. Will have to dig deeper on this, maybe hit my host or something.

Thanks for the tips..

hb.d...@gmail.com

unread,
Mar 10, 2010, 7:06:51 AM3/10/10
to jpl...@googlegroups.com
Hi,

generally, you're right @Mark B.
I guess, YWFTDG has/wants to deal with the same task, I just had to: Not
to offer (maybe copyright sensitive) mp3/Ogg -Files over an alltime
valid URL, which is vulnerable against deep-linking...

My kind of solution was to install an extra webserver (keywords to
google for: lighttpd with mod.sec_download).

With this, the files are served just for a given time, e.g. 300sec.,
coming from a folder, which is located outside the webroot.
This way, the URLs to the files get invalid after that given time,
making deep-linking senseless...A side-effect: this server is really fast...
But, yes, only possible, if you have the chance to install extra stuff
@YWFTDG

Btw.: @happyworm, @ Mark P in particular:
Many many thanks for this cool piece of work, the jplayer, and for your
endless patience in answering support questions! How do you still find
time for your everyday work? :)

Best Regards,
Holger

YWFTDG

unread,
Mar 16, 2010, 3:19:30 AM3/16/10
to jPlayer: the CSS styleable jQuery audio player plugin
Thanks for the information everyone. I was finally able to get this
going with a simple call to a php file instead for the file. This
works fine in FF, but chrome doesn't seem to use the streaming bar now
in the player, and Safari the player buttons and player loading/
progress bar has no result/activity at all. I am assuming maybe
something with the way the php is outputting the file to the player,
but doesn't anyone have any ideas why this would cause the player to
not function fully?

<?
$sku = $_GET['sku'];
$filename = $_GET['file'];
$file = '/var/www/vhosts/mydomain.com/audio/'.$sku.'/'.$filename.'';
$mime_type = "audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3";

if(file_exists($file)){
header('Content-type: $mime_type');
header('Content-length: ' . filesize($file));
header('Content-Disposition: filename=" ' . $filename . ' " ');
header('X-Pad: avoid browser bug');
header('Cache-Control: no-cache');
readfile($file);
}else{
header("HTTP/1.0 404 Not Found");
}
?>

Remy

unread,
Mar 16, 2010, 8:38:55 PM3/16/10
to jPlayer: the CSS styleable jQuery audio player plugin
Putting the MP3 in a directory that's not directly accessible by an
URL is a nice touch.
But with your system anyone typing the url to the php file with the
correct GET params (which probably appears clearly in your code) would
be allowed to download the MP3, wouldn't they ?

YWFTDG

unread,
Mar 17, 2010, 1:45:16 AM3/17/10
to jPlayer: the CSS styleable jQuery audio player plugin
Well I am not finished, but the idea is you cannot directly access the
php file with variables only the server (the php page calling it) can
talk to it. This isn't 100% full proof (nothing is) but it at least
could cut down on the easy access. But at this point, it still doesn't
work in Safari and I have no idea why. I have tried numerous header
types/settings, nothing works. The player has no issues in firefore,
chrome works but the progress bar on load does nothing, but in safari
the player is basically broken (stop, progress bar, loading bar a no
go) but the audio does play. Even the data window shows no activity
other than "playing" for Safari...no idea what the problem is....

The player works fine when calling the mp3 files directly but when I
changed over to .php file to send the files, this caused it to break
down.

Anyone got any thoughts, ideas? I am pretty much stuck now, spent
about 10 hours debugging yesterday, nothing..

Remy

unread,
Mar 17, 2010, 7:19:58 PM3/17/10
to jPlayer: the CSS styleable jQuery audio player plugin
I don't really see how the access to the php file could be limited,
since the jplayer doesn't send a HTTP_REFERER to the PHP file. That
was my main problem in this thread:
http://www.google.com/url?sa=D&q=http://groups.google.com/group/jplayer/browse_thread/thread/b34a5ebb19f53e74&usg=AFQjCNHQ5en630w-Zz5JUDZXfZwkctOrtg

I finally had time to test the solution I had imagined and it works
like a charm!
Whenever a track is played by the jplayer, I send an ajax request to a
php file, that creates two session vars: one with the id of the played
track, another with the timestamp I started playing it.

Now, the php page that serves the MP3 files first checks if these two
session vars exist, and that the track started playing less than, say,
three seconds ago. Only if this is the case, it redirects to the mp3
using the headers system.

So, it's not an absolutely surefire solution (nothing is, as you
said), but I'm sure it will be enough for a vast majority of the
visitors :)

Regards,

Remy

Remy

unread,
Mar 17, 2010, 7:18:47 PM3/17/10
to jPlayer: the CSS styleable jQuery audio player plugin

YWFTDG

unread,
Mar 18, 2010, 3:55:57 AM3/18/10
to jPlayer: the CSS styleable jQuery audio player plugin
By calling the files from the php file, did it still work in Safari 4?
Like, if your call to play the file is the the .php url with a
variable, will the controls still function in Safari? That was my main
bug right now with the actual player, outside of dealing with mp3
security. If I call a mp3 file directly, then no problems at all, but
calling php urls it jacks in Safari.

Let me know if you can, but I like your idea on the session solution
too, I will have to figure out what you are doing there.

thanks,
-Michael


On Mar 18, 6:18 am, Remy <remydoo...@gmail.com> wrote:
> I don't really see how the access to the php file could be limited,
> since the jplayer doesn't send a HTTP_REFERER to the PHP file. That

> was my main problem in this thread:http://www.google.com/url?sa=D&q=http://groups.google.com/group/jplay...

YWFTDG

unread,
Mar 16, 2010, 3:47:49 AM3/16/10
to jPlayer: the CSS styleable jQuery audio player plugin
btw, the player buttons were working fine until I started loading the
files this way...

YWFTDG

unread,
Mar 16, 2010, 4:30:07 AM3/16/10
to jPlayer: the CSS styleable jQuery audio player plugin
The error in Safari, or at least all I can see right now is:
/Scripts/jplayer/jquery.jplayer.min.js:34
Error: INDEX_SIZE_ERR: DOM Exception 1


On Mar 16, 2:19 pm, YWFTDG <thedesigngrap...@gmail.com> wrote:

Remy

unread,
Mar 18, 2010, 12:32:32 PM3/18/10
to jPlayer: the CSS styleable jQuery audio player plugin
I have no such problem. It works on FF, Safari and IE.
The main difference maybe, is that the MP3 files are in an url-
accessible location (but protected by htaccess). Obviously the error
you get means that jplayer is not able to find the MP3.

Here is the code and headers I use in the page that serves the MP3, if
that's any help :

session_start();
$idmp3 = $_GET["id"];

if ( (isset($_SESSION["title_played"])) &&
(isset($_SESSION["time_played"])) &&
($idmp3 == $_SESSION["title_played"]) && (time()-
$_SESSION["time_played"] < 3) )
{
$path = "mypath/".$idmp3.".mp3";
header('Content-type: audio/mpeg');
header('Content-Length: '.filesize($path)); // provide file size
header("Expires: -1");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
readfile($path);
}

Hope it helps!

YWFTDG

unread,
Mar 21, 2010, 7:42:45 AM3/21/10
to jPlayer: the CSS styleable jQuery audio player plugin
Remy,
Thanks for the tip on that, for some reason though I still have player
issues in Safari. It plays, but the player controls still messed up. I
am going to paste my actuall code for the player to see if anyone can
see where I might have something off in the JS that could be causing
this issue.


<script type="text/javascript">
var $j = jQuery.noConflict();
$j(document).ready(function(){
var playItem = 0;

<?
$path = '/mydomain/full/path/audio/'.$sku.'/'; -- hidden for
security
$allowed_types = array('mp3');

if(file_exists($path)) { ?>
var myPlayList = [
<?
$audioFiles = opendir($path);
$count = 0;
while($file = readdir($audioFiles)){
if(in_array(strtolower(substr($file ,-3)),$allowed_types)) {
$count++;
?>
{name:"<?=substr($file, 0, -4)?>",mp3:"<?=$baseURL?
>playerfile.php?sku=<?=$sku?>&file=<?=$file?>"},
<?
}
}
?>
];
<? } // end if exists ?>

// Local copy of jQuery selectors, for performance.
var jpPlayTime = $j("#jplayer_play_time");
var jpTotalTime = $j("#jplayer_total_time");
var jpStatus = $j("#demo_status"); // For displaying information
about jPlayer's status in the demo page

$j("#jquery_jplayer").jPlayer({
ready: function() {
displayPlayList();
playListInit(false); // Parameter is a boolean for autoplay.
demoInstanceInfo(this.element, $j("#demo_info")); // This
displays information about jPlayer's configuration in the demo page
},
swfPath: "/Scripts/jplayer",
oggSupport: false
})
.jPlayer("onProgressChange", function(loadPercent,
playedPercentRelative, playedPercentAbsolute, playedTime, totalTime) {
jpPlayTime.text($j.jPlayer.convertTime(playedTime));
jpTotalTime.text($j.jPlayer.convertTime(totalTime));

demoStatusInfo(this.element, jpStatus); // This displays
information about jPlayer's status in the demo page
})
.jPlayer("onSoundComplete", function() {
playListNext();
});

$j("#jplayer_previous").click( function() {
playListPrev();
return false;
});

$j("#jplayer_next").click( function() {
playListNext();
return false;
});

function displayPlayList() {
for (i=0; i < myPlayList.length; i++) {
$j("#jplayer_playlist ul").append("<li
id='jplayer_playlist_item_"+i+"'>"+ myPlayList[i].name +"</li>");
$j("#jplayer_playlist_item_"+i).data( "index",
i ).click( function() {
var index = $j(this).data("index");
if (playItem != index) {
playListChange( index );
} else {
$j("#jquery_jplayer").jPlayer("play");
}
});
}
}

function playListInit(autoplay) {
if(autoplay) {
playListChange( playItem );
} else {
playListConfig( playItem );
}
}

function playListConfig( index ) {

$j("#jplayer_playlist_item_"+playItem).removeClass("jplayer_playlist_current");

$j("#jplayer_playlist_item_"+index).addClass("jplayer_playlist_current");
playItem = index;
$j("#jquery_jplayer").jPlayer("setFile",
myPlayList[playItem].mp3);
}

function playListChange( index ) {
playListConfig( index );
$j("#jquery_jplayer").jPlayer("play");
}

function playListNext() {
var index = (playItem+1 < myPlayList.length) ? playItem+1 : 0;
playListChange( index );
}

function playListPrev() {
var index = (playItem-1 >= 0) ? playItem-1 : myPlayList.length-1;
playListChange( index );
}
});
</script>

<div id="jquery_jplayer"></div>

<div class="jp-playlist-player">
<div class="jp-interface">
<ul class="jp-controls">
<li id="jplayer_play" class="jp-play">play</li>
<li id="jplayer_pause" class="jp-pause">pause</li>
<li id="jplayer_stop" class="jp-stop">stop</li>
<li id="jplayer_volume_min" class="jp-volume-min">min volume</
li>
<li id="jplayer_volume_max" class="jp-volume-max">max volume</
li>
<li id="jplayer_previous" class="jp-previous">previous</li>
<li id="jplayer_next" class="jp-next">next</li>
</ul>
<div class="jp-progress">
<div id="jplayer_load_bar" class="jp-load-bar">
<div id="jplayer_play_bar" class="jp-play-bar"></div>
</div>
</div>
<div id="jplayer_volume_bar" class="jp-volume-bar">
<div id="jplayer_volume_bar_value" class="jp-volume-bar-value"></
div>
</div>
<div id="jplayer_play_time" class="jp-play-time"></div>
<div id="jplayer_total_time" class="jp-total-time"></div>
</div>
<div id="demo_status"></div>
<div id="jplayer_playlist" class="jp-playlist">
<ul>
<!-- The function displayPlayList() uses this unordered list -->
</ul>
</div>
</div>

YWFTDG

unread,
Mar 21, 2010, 10:17:43 AM3/21/10
to jPlayer: the CSS styleable jQuery audio player plugin
Actually I finally got it working by setting the player to flash
version only. So for reference, this has some buggy issues when
calling a link instead of direct mp3 file in webkit browsers it seems.

> $j("#jplayer_playlist_item_"+playItem).removeClass("jplayer_playlist_curren t");

rambo

unread,
Jun 18, 2012, 3:21:23 AM6/18/12
to jpl...@googlegroups.com
how to disable save download as in right click option in jplayer 

Johno

unread,
Mar 17, 2014, 5:48:54 AM3/17/14
to jpl...@googlegroups.com
Hi

Just about got my head around this one (thanks for sharing)..

<?
$sku = $_GET['sku'];
$filename = $_GET['file'];
$file = '/var/www/vhosts/mydomain.com/audio/'.$sku.'/'.$filename.'';
$mime_type = "audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3";

if(file_exists($file)){
   header('Content-type: $mime_type');
    header('Content-length: ' . filesize($file));
    header('Content-Disposition: filename=" ' . $filename . ' " ');
    header('X-Pad: avoid browser bug');
    header('Cache-Control: no-cache');
    readfile($file);
}else{
    header("HTTP/1.0 404 Not Found");
}
?>


Im now struggling on how to actually call this php file form my Javascript (does it have to be via AJAX)?
Would it be possible for someone to provide an example on how this call is achieved?

Thanks, J

Mark Panaghiston

unread,
Mar 17, 2014, 8:15:12 AM3/17/14
to jpl...@googlegroups.com
You might want to look at this repo here:
https://github.com/happyworm/smartReadFile

That allows you to put the files above the web root.

Johno

unread,
Mar 17, 2014, 10:56:19 AM3/17/14
to jpl...@googlegroups.com
Thanks for the prompt reply Mark, 

Been trying all morning to get this to work, but without any luck so far
Just want to ask about this line that calls the api.php:

mp3: "..api.php?f=song_title.mp3"

Do I need to 'Include' the api.php anywhere upfront or is that call sufficient enough on its own?

Thanks again for your time on this

J

Mark Panaghiston

unread,
Mar 17, 2014, 12:35:19 PM3/17/14
to jpl...@googlegroups.com
The api.php is simply an example of how you might use the smartReadFile.php function.
If you do not put some form of authentication into your website, that is then checked in what I called the api.php, then there is no point whatsoever using it.
ie., There is no point putting the original MP3 media above the web root if all you are going to do is directly pipe them to the web via a piece of PHP.

Johno

unread,
Mar 17, 2014, 12:54:18 PM3/17/14
to jpl...@googlegroups.com
Thanks again for the reply Mark and sorry for lack of knowledge on this, its all new territory but I am learning fast!
I just wanted to get something up and running 'as is' to start with and then to be able to work it further from there (I do have the player running very well on my site, my next step is now getting the files out of the root)
So I am using the api.php as shown, but at present I don't appear to be entering it with this call: mp3: "..api.php?f=song_title.mp3"  (Ive set up a JS alert at the top of the api.php but this isnt triggering)

Still trying everything to get it to work but very frustrating - its the last bit to crack for me so appreciate any assistance

J

Mark Panaghiston

unread,
Mar 17, 2014, 12:58:22 PM3/17/14
to jpl...@googlegroups.com
A JS alert in the top of api.php.... Erm... You do realize that PHP runs on the server and its response is the audio file?
The JS alert will need to be executed in a browser to do anything.

No all PHP is a webpage.

Johno

unread,
Mar 18, 2014, 5:59:54 AM3/18/14
to jpl...@googlegroups.com
One step forward, 3 back..
Managed to get an audio file playing (via the SmartReadFile method) but only when i click play, it wont auto start..
Also will only play a file in a public folder (as soon as i change the base directory to anything else it wont play) and wont start from a specified start point (as far as i know allow ranges is active)

Everything was working fine when the player was serving from a public folder but trying to get audio served from a hidden one is just being a nightmare, real pity as i was making good progress on this - now well and truly stuck

Mark Panaghiston

unread,
Mar 18, 2014, 6:11:03 AM3/18/14
to jpl...@googlegroups.com
I suggest that you find where your php error log is on your system and see what errors it is generating.

The line you need to change to move the media folder is:
https://github.com/happyworm/smartReadFile/blob/master/api.php#L20

You will have to follow the rules of your local system... My example is based on a Linux system, but I imagine windows would need more of a "C:\some\folder\" type path.

The error log will help you see where you are going wrong.

Remember that when you go above the web root, the paths then relate to your local file system... And to be honest, I'm not sure if you can use the ..\..\.. type thing to go above the root, but I expect that you can.

Johno

unread,
Mar 18, 2014, 9:51:03 AM3/18/14
to jpl...@googlegroups.com
Thanks for the perseverance on this Mark, I think ive finally got it working!

I went back to one of the original Header Requests that was posted at the top of this thread and that got things up and running, so ive rebuilt that php file adding the SmartRead code back in and looks like I am now streaming from a non root folder, from a given start point and auto play is now working again  - so well happy!

Will post back later with results once Ive got my head around it all - thanks again for your support, ive learnt a lot!

J

Johno

unread,
Mar 18, 2014, 10:39:03 AM3/18/14
to jpl...@googlegroups.com
quick update, nearly 100% success..

mp3's are working perfectly, but cannot get .ogg's to work at all. I've set them as a MimeType but still no joy.
Anywhere else I may need to look?

Thanks, J

Mark Panaghiston

unread,
Mar 18, 2014, 4:56:45 PM3/18/14
to jpl...@googlegroups.com
A common one is using the property ogg instead of oga in the setMedia command and supplied option.

Johno

unread,
Mar 18, 2014, 5:15:33 PM3/18/14
to jpl...@googlegroups.com
Hi Mark, whilst building my implementation of the SmartRead I omitted this:

if (isset($_SERVER['HTTP_RANGE']))
{
header('HTTP/1.1 206 Partial Content');
}
else
{
header('HTTP/1.1 200 OK');
}

..added it back in and everything's working fine - so one very happy chappy!

Thanks for taking the time out to reply and assisting along the way, much appreciated 
Reply all
Reply to author
Forward
0 new messages