Jump to content

Php Mp3 security


EricBeaudoin

Recommended Posts

Hi, I am looking to create a directory that can not be accessed using .htaccess and neither can files directly.
But I want to make it so when you are signed into joomla you can access the files via a mp3 player on the sight.

 

My mp3 extention is joomline player flplayer.
And I heard that if I cange the name of the file in joomla fomr lovelove.com/audio/love/abc.mp3

to lovelove.com/audio/love/abc.php?name=abc

 

and then that abc.php script (inside the script it checks if you are logged in) will retrieve the file name, and the joomline will play it it will work.

 

is this possible?

Also, if not what can I do for this to work?

 

Right now my script is not working as the joomline looks up all the mp3 files as one big string.

this is the abc.php which on my site its calld psp.php

<?php
 define( '_JEXEC', 1 );
    define( 'JPATH_BASE', realpath(dirname(__FILE__).'/../../' ));  
    require_once ( JPATH_BASE .'/includes/defines.php' );
    require_once ( JPATH_BASE .'/includes/framework.php' );
$mainframe =& JFactory::getApplication('site');

 if( !empty( $_GET['name'] ) )
{
  // check if user is logged    
if(JFactory::getUser()->guest) {
die( "ERROR: invalid song or you don't have permissions to download it." );
}
else { 
    $psp = preg_replace( '#[^-\w]#', '', $_GET['name'] );
    $psp_file = "{$_SERVER['DOCUMENT_ROOT']}/audio/live/{$psp}.mp3";
    if( file_exists( $psp_file ) )
    {
      header( 'Cache-Control: public' );
      header( 'Content-Description: File Transfer' );
      header( "Content-Disposition: attachment; filename={$psp_file}" );
      header( 'Content-Type: application/mp3' );
      header( 'Content-Transfer-Encoding: binary' );
      readfile( $psp_file );
      exit;
    }
  }
}
 ?>

then I have joomline player    jlplayer

<?php
/**
 * JoomLine mp3 player - Joomla mp3 player
 *
 * @version 1.5
 * @package JoomLine mp3 player
 * @author Anton Voynov (anton@joomline.ru), Sergii Gaievskiy (shturman.kh@gmail.com)
 * @copyright (C) 2010 by Anton Voynov(http://www.joomline.ru)
 * @license GNU/GPL: http://www.gnu.org/copyleft/gpl.html
 *
 * If you fork this to create your own project,
 * please make a reference to JoomLine someplace in your code
 * and provide a link to http://www.joomline.ru
 **/

defined('_JEXEC') or die('Restricted access');

function ascii2hex($ascii, $reverse = false) {
	$hex = array();
	for ($i = 0; $i < strlen($ascii); $i++) {
		$byte = strtoupper(dechex(ord($ascii{$i})));
		$byte = str_repeat('0', 2 - strlen($byte)).$byte;
		$hex[] = $byte;
	}
	if ($reverse) $hex = array_reverse($hex);
	return implode(" ",$hex);
}

function read_frame (&$f, &$tagdata, $frame) {
	$pos = strpos($tagdata,$frame);
	if ( $pos !== FALSE) {
		// frame found. read length of this frame
		fseek($f, 10+$pos+4);
		$frame2len = hexdec(ascii2hex(fread($f,4)));
		if (($frame2len-1) > 0) {
			// read frame data
			fseek($f, 10+$pos+4+2+4+1);
			$data = trim(fread($f,$frame2len-1));

			$hexfdata = ascii2hex($data);
				if ( substr($hexfdata,0,5) == 'FF FE' or substr($hexfdata,0,5) == 'FE FF' ) {
					$data = iconv("UCS-2","UTF-8",$data);
				} else {
					if (!preg_match('//u', $data)) {
						$data = iconv("cp1251", "UTF-8",$data);
			}
				}
			return $data;
		} else {
			return false;
		}
	} else {
		return false;
	}
	
}

function readmp3tag($file) {
	$f = fopen($file, 'rb');
	rewind($f);
	fseek($f, -128, SEEK_END);
	$tmp = fread($f,128);
	if ($tmp[125] == Chr(0) and $tmp[126] != Chr(0)) {
		// ID3 v1.1
		$format = 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a28COMMENT/x1/C1TRACK/C1GENRENO';
	} else {
		// ID3 v1
		$format = 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a30COMMENT/C1GENRENO';
	}
	$id3v1tag = unpack($format, $tmp);

	// read tag length
	fseek($f, ;
	$tmp = fread($f,2);
	$tmp = ascii2hex($tmp);
	$taglen= hexdec($tmp);
	$tagdata = "";
	if ($taglen > 0) {
	//read tag data
	fseek($f, 10);
	$tagdata = fread($f,$taglen);
	}
	
	// find song title frame
	$title = read_frame ($f, $tagdata, "TIT2");
	if (!$title) {
		if ($id3v1tag['TAG']== 'TAG' && ascii2hex(substr($id3v1tag['NAME'],0,1)) != '00' ) {
			$title = $id3v1tag['NAME'];
		} else {
		$title = explode(DS,$file);
		$title = $title[count($title)-1];
		$title = explode('.',$title);
		$title=$title[0];
	}
		if (!preg_match('//u', $title)) $title = iconv("cp1251", "UTF-8",$title);
	}
	$artist = read_frame ($f, $tagdata, "TPE1");
	if (!$artist) {
		if ($id3v1tag['TAG']== 'TAG' &&  ascii2hex(substr($id3v1tag['ARTISTS'],0,1)) != '00') {
			$artist = $id3v1tag['ARTISTS'];
		} else {
			$artist = "";
	}
	}
	if (!preg_match('//u', $artist)) $artist = iconv("cp1251", "UTF-8//TRANSLIT",$artist);
	
	$id3tag['NAME']		= $title;
	$id3tag['ARTIST']	= $artist;

	return $id3tag;
}

if (DS == "/") 
	$dir = str_replace("\\",DS,$music_dir);
else 
	$dir = str_replace("/",DS,$music_dir);
$dir = JPATH_ROOT.DS.$dir;


if (!is_dir($dir)) {
	echo "Wrong dir in settings";
} else {
	$files = glob($dir.DS."*.{mp3,MP3}",GLOB_BRACE);
	if (count($files) > 0) {
		sort($files);
		$host = $base_uri;
		foreach ($files as $file) {
			$tags = readmp3tag($file);
			$file = explode (DS, $file);
			if ($server_utf8 == 1) {
				$fname = rawurlencode($file[count($file)-1]);
			} else {
				$fname = rawurlencode($file[count($file)-1]);
			}
$fname = substr($fname, 0, -4);
			
			$file = $host."/".$music_dir."/psp.php?name=".$fname;
echo $file;
			$artist = trim($tags['ARTIST']);
			$artist = $artist == "" ? "" : "{$tags['ARTIST']} - ";
			$playlist[] = '{name:"'.$artist.$tags['NAME'].'",mp3:"'.$file.'"}';
		}
	}
	/*
	 * 	
	//if(!window.jQuery) {
		document.write(unescape('<script type="text/javascript" src="<?=$base_uri?>/modules/mod_jlplayer/js/jq.js">%3C/script%3E'));
		document.write(unescape('<script type="text/javascript">jQuery.noConflict();%3C/script%3E'));
	//}

	 * 
	 */
	?>
	<script type="text/javascript">
	var myPlayList = [
		<?php 
			echo implode(",\n		",$playlist)."\n"; 
		?>
		];
		Array.prototype.find=function(v){
				for (i=0;i<this.length;i++){
						if (this[i]==v) return i;
				}
				return 0;
		}
		var plIndex = [];
		for (i=0;i<myPlayList.length;i++) {
				plIndex[i] = i;
		}
		<?php if ($shfl == 1) : ?>
		//shuffle
		function randOrd(){
			return (Math.round(Math.random())-0.5);
		}
		plIndex.sort(randOrd);
		<?php endif; ?>
		function setCookie (name, value) {
					document.cookie = name + "=" + escape(value) + "; expires=Thu, 01-Jan-2055 00:00:01 GMT; path=/";
		}

		function getCookie(name) {
			var cookie = " " + document.cookie;
			var search = " " + name + "=";
			var setStr = null;
			var offset = 0;
			var end = 0;
			if (cookie.length > 0) {
				offset = cookie.indexOf(search);
				if (offset != -1) {
					offset += search.length;
					end = cookie.indexOf(";", offset)
					if (end == -1) 	{
						end = cookie.length;
					}
					setStr = unescape(cookie.substring(offset, end));
				}
			}
			return(setStr);
		}		
		
		function changeShflStatus(el) {
			nowPlay = plIndex[playItem];
			
			if (el.checked) {
				setCookie("jlp_shfl","shuffle");
				plIndex.sort(randOrd);
			} else {
				setCookie("jlp_shfl","notshuffle");
				plIndex.sort();
			}
			playItem = plIndex.find(nowPlay);
			 
		}
		
	</script>	
	<script type="text/javascript" src="<?=$base_uri?>/modules/mod_jlplayer/js/jq.js"></script>
	<script type="text/javascript">jQuery.noConflict();</script>
	<link href="<?=$base_uri?>/modules/mod_jlplayer/skin/skin.css" rel="stylesheet" type="text/css" />
	<script type="text/javascript" src="<?=$base_uri?>/modules/mod_jlplayer/js/jquery.jplayer.min.js"></script>
	
	<script type="text/javascript">
		var playItem = 0;
	 
		jQuery(function(){
			var jpPlayTime = jQuery("#jplayer_play_time");
			var jpTotalTime = jQuery("#jplayer_total_time");
			var jlp_shfl = getCookie("jlp_shfl");
			if (jlp_shfl == "shuffle") {
				document.getElementById('jlp_shfl').checked = true;
			} else if (jlp_shfl == "notshuffle") {
				document.getElementById('jlp_shfl').checked = false;
			}
			jsuri = baseuri+"/modules/mod_jlplayer/js/";
			jQuery("#jquery_jplayer").jPlayer({
				ready: function() {
					displayPlayList();
					playListInit(enable_autoplay); // Parameter is a boolean for autoplay.
				},
				errorAlerts:true,
				warningAlerts:true,
				swfPath: jsuri
			})
			.jPlayer("onProgressChange", function(loadPercent, playedPercentRelative, playedPercentAbsolute, playedTime, totalTime) {
				jpPlayTime.text(jQuery.jPlayer.convertTime(playedTime));
				jpTotalTime.text(jQuery.jPlayer.convertTime(totalTime));
			})
			.jPlayer("onSoundComplete", function() {
				playListNext();
			});
		 
			
			
			jQuery("#jplayer_previous").click( function() {
				playListPrev();
				return false;
			});
		 
			jQuery("#jplayer_next").click( function() {
				playListNext();
				return false;
			});
			
			
		});	
		
		
		function displayPlayList() {
			for (i=0; i < myPlayList.length; i++) {
				jQuery("#jplayer_playlist").append("<div id='jplayer_playlist_item_"+i+"'>"+ myPlayList[i].name +"</div>");
				jQuery("#jplayer_playlist_item_"+i).data( "index", i ).click( function() {
					var index = jQuery(this).data("index");
					if (plIndex[playItem] != index) {
						_index = plIndex.find(index);
						playListChange( _index, index );
					} else {
						jQuery("#jquery_jplayer").jPlayer("play");
					}
				});
			}
		}
	 
		function playListInit(autoplay) {
			if(autoplay) {
				playListChange(0, plIndex[0] );
			} else {
				playListConfig(0, plIndex[0] );
			}
		}
	 
		function playListConfig(_index, index ) {
			jQuery("#jplayer_playlist_item_"+plIndex[playItem]).removeClass("jplayer_playlist_current");
			jQuery("#jplayer_playlist_item_"+index).addClass("jplayer_playlist_current");
			playItem = _index;
			jQuery("#jquery_jplayer").jPlayer("setFile", myPlayList[plIndex[playItem]].mp3);
		}
	 
		function playListChange(_index, index ) {
			playListConfig(_index, index );
			jQuery("#jquery_jplayer").jPlayer("play");
		}

		function playListNext() {
			var _index = (playItem+1 < myPlayList.length) ? playItem+1 : 0;
			var index = plIndex[_index];
			playListChange(_index, index );
		}
	 
		function playListPrev() {
			var _index = (playItem-1 >= 0) ? playItem-1 : myPlayList.length-1;
			var index = plIndex[_index];
			playListChange(_index, index );
		}	
	
	</script>
	
	<?php include_once(JPATH_ROOT.DS.'modules/mod_jlplayer/skin/tpl.php'); ?> 
	
	
	<?php
}

I was messing around in there with $file
 

	if ($server_utf8 == 1) {
				$fname = rawurlencode($file[count($file)-1]);
			} else {
				$fname = rawurlencode($file[count($file)-1]);
			}
$fname = substr($fname, 0, -4);
			
			$file = $host."/".$music_dir."/psp.php?name=".$fname;
echo $file;

I am unsure how to retreive a file title only, with out the whole path, just the name and not even the file ext.
It comes up with all the files names in the echo.
Also I am not sure how joomline chooses just one file.

 

I am not a php designer and I am quite confused lol

 

Any help would be appreciated! Thank you.

Link to comment
Share on other sites

Hi, I am looking to create a directory that can not be accessed using .htaccess and neither can files directly.

But I want to make it so when you are signed into joomla you can access the files via a mp3 player on the sight.

Not really. For people to play the MP3s they have to be able to access the files, so you can't block access and keep things working.

Serve the files not directly but through a PHP script (one sophisticated enough to handle conditional requests and byte ranges, preferably) which validates access. Not access through the player - you can't tell that for sure - but whether the user has access. The URL can include the session ID if it doesn't get sent by the player automatically, and you can do regular stuff about checking if they're logged in and whatever.

 

[edit] Okay, I focused more on the "cannot be accessed" part and less on the "signed into joomla". You can't deny access and allow access at the same time, but you can deny access unless the user does something (like sign in) and then allow access.

Edited by requinix
  • Like 1
Link to comment
Share on other sites

This absolutely is possible. I have a working script for this, but might take me a while to find it. However, I have no knowledge of Joomla so YOU would need to figure out how to make it work.

 

The key is you would put the MP3 files in a directly that is not publicly accessible. You could use .htacxcess, but I like using a non-public folder. Anyway, all requests for an MP3 files will be through a URL such as mysite.com/playmp3.php?id=123 where the parameters on the URL identify the MP3 to be played. I built this to pass the ID of the database reocrd associated with the MP3 file, but you can tweak that as needed. You can put logic on that page to check if the user is logged in. If no, kick them to another page. If yes, get the file path to the file and read() the file and pass the result to the user. You can even create playlists that use these URLs and they will play in your MP3 player just as if they were on your PC.

Link to comment
Share on other sites

Thanks for all the responses!

@

Psycho

Thank you for your response, I had a script working where you go to, mysite.com/playmp3.php?id=123 if you are logged into joomla and you can download the file. if you are not it says acess restricted. and if you go to the directory its also restricted.

 

My problem is plugging this into the joomline module in joomla, which is php and javascript.
I am having trouble getting the player to play the directed files.

it works when using "$file = $host."/".$music_dir."/".$fname;"

I tried to change to "$file = $host."/".$music_dir."/psp.php?name=".$fname;" (psp is just playmp3.php renamed and id is name instead.)

 

But then the files just dont play in the player.

 

Could any one take a look at joomline and give me a direction to start?

http://joomline.net/downloads/joomlinemp3player/1.5.html

Link to comment
Share on other sites

You can protect from downloading the raw mp3 as a file, but you can't protect against the user recording what is playing through their soundcard as a new mp3/wav/flac/whatever.

Thank you, I am aware of that, but I just want to limit access to less people. I do not mind what those logged in people will do because they will be more trusted then a public access folder.

Link to comment
Share on other sites

No matter what you do, you can not protect from ANY content that is brought to the browser. once it reaches the browser consider it up for grabs.

The best way to protect the url location would be to store them as a BLOB in your database but even then the user can download the blob that you sent them.

IF it were me i would write 2 applications 1 being in silverlight and the other in flash (use silverlight as the fallback for flash, there are some issues with mac user

 

 

You could also get the sound waves from the file and play it back with html5.

Link to comment
Share on other sites

@Richard Grant, he already stated he doesn't care about the users with access copying the audio - only that he wants to limit who can access. A simple password protected access model should work fine.

 

@EricBeaudoin, I don't know squat about Joomla. S, if this is a specific Joomla issue I can't help you. But, it may not be a Joomla issue. there are a couple of things to verify first.

 

 

 

it works when using "$file = $host."/".$music_dir."/".$fname;"

I tried to change to "$file = $host."/".$music_dir."/psp.php?name=".$fname;" (psp is just playmp3.php renamed and id is name instead.)

 

You say that it works with the first value but not the second. Is this with the .htaccess restriction in place? I have to assume not. The $host parameter would seem to indicate the value of $file is the web address from the user's browser to the file rather than the file system location on the server. If that is the case, that may be part of the problem. You are putting the psp.php file in that same directory - which you are trying to limit access to. Put that file in another location that is not restricted.

 

There are a lot of different things going on here with PHP, file locations, JavaScript, etc. You need to take a systematic approach to finding the problem.

 

I "assume" that the original value is the "web" location to the file rather than the file system location from the server (based on the fact that the first parameter is $host). But, one should never assume. So, echo $file to the page to verify exactly what it contains when it is working. You should be able to copy/paste the value into your browser address to directly access the file (once you remove the .htaccess restriction). Once you have verified that is indeed what the value contains, change it to instead point to the psp.php file and echo it to the page. Then, copy/paste that value into your browser to ensure the file is being called correctly (change it to just echo a statement). Once you have verified, that $file is pointing to the correct script and the script is executing, change the script to "load/read" the mp3 files. Test the functionality by directly calling the script. Once that is all working, then call the file through the above code and see if it works. If so, put the .htaccess restriction back on the folder and test again.

Link to comment
Share on other sites

@Richard Grant, he already stated he doesn't care about the users with access copying the audio - only that he wants to limit who can access. A simple password protected access model should work fine.

 

@EricBeaudoin, I don't know squat about Joomla. S, if this is a specific Joomla issue I can't help you. But, it may not be a Joomla issue. there are a couple of things to verify first.

 

 

 

 

You say that it works with the first value but not the second. Is this with the .htaccess restriction in place? I have to assume not. The $host parameter would seem to indicate the value of $file is the web address from the user's browser to the file rather than the file system location on the server. If that is the case, that may be part of the problem. You are putting the psp.php file in that same directory - which you are trying to limit access to. Put that file in another location that is not restricted.

 

There are a lot of different things going on here with PHP, file locations, JavaScript, etc. You need to take a systematic approach to finding the problem.

 

I "assume" that the original value is the "web" location to the file rather than the file system location from the server (based on the fact that the first parameter is $host). But, one should never assume. So, echo $file to the page to verify exactly what it contains when it is working. You should be able to copy/paste the value into your browser address to directly access the file (once you remove the .htaccess restriction). Once you have verified that is indeed what the value contains, change it to instead point to the psp.php file and echo it to the page. Then, copy/paste that value into your browser to ensure the file is being called correctly (change it to just echo a statement). Once you have verified, that $file is pointing to the correct script and the script is executing, change the script to "load/read" the mp3 files. Test the functionality by directly calling the script. Once that is all working, then call the file through the above code and see if it works. If so, put the .htaccess restriction back on the folder and test again.

So I got it working today but I accadently delted the code :(

Going to redo it when I have time. I mkoved the psp.php redirecting file to outside the directory.

Also when I was trying to load the music files tags using .fopen, all those commands inluding seek, rewind and so forth do not work. How to I use this psp file and fopen in the origonal php file so i can load the mp3s.

 

Also I am not sure how I loaded the files but I think that I didn't use a relative path but absolute path blahblah.ca/audo/psp.php pointing to blahbla.ca/audio/blah/blahblah.mp3

 

Any ideas how I can get the tracks/mp3 length, seek rewind name and all that info. All the files at one point were coming up as psp for the names. Not sure gonna restart from the origonal files and try again.

 

any advice?

Link to comment
Share on other sites

  • 4 weeks later...
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.