/    Sign up×
Community /Pin to ProfileBookmark

Can I use a PHP script to gain browser access to protected directory?

I have a music page, where visitors can listen to short samples of my music for free, and also purchase CDs. I would also like to allow existing paid customers the ability to listen to full versions of the music on that page too. So to start, I’ve set up a protected directory on my hosted space, where the music files reside. Of course if the page tries to access it, a user and password is required.

Well I obviously don’t want to share the single directory password publicly, even with paid customers. And i don’t think I want to try managing multiple passwords in an HTACCESS file. What I’d rather do is let each customer be authorized with their own password and credentials via a PHP script. It seems easy enough to set up a call to a PHP script where I could check a database (or even a flat file) to see if the visitor should have access. If so, the PHP script could access the private directory, and no one would see the actual directory user/ password.

That’s what I’d LIKE to do, but can I? First of all, assuming the PHP script “knows” the directory user and password, how can a PHP script request access to the directory, and offer up the credentials. Second, even if the called script can gain access to the protected directory, will that mean the originating browser page can get to it too? If not, the music player on the visitor page won’t be able to play/access the files.

Maybe I’m overthinking this, again? πŸ™

Suggestions?

to post a comment
PHP

8 Comments(s) ↴

Copy linkTweet thisAlerts:
@ginerjmMar 20.2019 β€”Β Not sure but here goes. For the users to "see" an image or "hear" some music from that folder, I think your script is going to download that file (or play it in some fashion that does not allow them to have a copy) for that moment. The script would never give them access. So - it just got simpler for you I think. Now you just need to make sure that you can find a tool that the client can use that view/plays without giving them access to the file.
Copy linkTweet thisAlerts:
@PeterPan_321authorMar 21.2019 β€”Β @ginerjm#1602011 Hmmm... well if I had to MAKE them play it on their own player that wouldn't work. The idea is to let people who've already bought the music use my page as a kind of player. So on a phone (for example), that means the existing HTML5 audio player (or my pretty overlay for it) has to be able to see the music.

EDIT: I think I've figured out that as I suspected, the first part will be easy. That is, a PHP script on the server is probably NOT going to have any trouble, nor need authorization, to get "in" to a private music directory. Its on the same server so it probably won't need any credentials.

But by the same token I'm pretty sure this won't do anything to help the visiting browser have access. I can handle getting the visitors credentials and screen them against a database of buyers. But then, to make it 'seemless" for the visitor, I'll then have to give that visitor's browser permission to access the folder, as if someone already tried and gave the usual popup window the master user and password. THAT will be the trick.

I know I'm having a hard time explaining this.
Copy linkTweet thisAlerts:
@ginerjmMar 21.2019 β€”Β If you are not worried about the abilities of ordinary client-based "players" or "readers" to retain your files then you will NOT have any problem. Your php script will access to the file and deliver it to the client. Clients have to have files delivered to them - they don't access files directly on the server.

If you back up and re-think this - your concern is that these files are to be protected. If that weren't in the equation, what would your concern be? Having the files stored outside of the web-accessible tree simply enforces your concern in that a browser using HTTP cannot access them. Period.

At least Not That I Know Of.
Copy linkTweet thisAlerts:
@PeterPan_321authorMar 21.2019 β€”Β @ginerjm#1602032 OK, then thanks. That is what I need to know. Since the primary goal is to be able to allow AUTHORIZED users to be able to play the music on the page I provide, I'll have to look for another method. Maybe I could let the PHP code authorize the visitor, and then make a temporary copy of the requested tune in an directory accessible to the player page. The file copy would happen on the server with the server CPU and would likely be nearly instantaneous. I would have to come up with a way of deleting the temporary files afterward.
Copy linkTweet thisAlerts:
@ginerjmMar 21.2019 β€”Β Sorry - had to re-read this topic to catch up so my original answer here was incorrect.....

I don't understand why you think that people are going to WANT to use your choice of player. Isn't that why we have dozens of them in the public realm? As soon as you embed one in your page you are going to get complaints from the users who use a different one.

As for giving them access to your library - won't you simply provide a nicely presented listing of your available music that will come from your behind-the-scenes db entries that will point the user to the correct file which YOUR SCRIPT will then access and send down to their web page for playing, whether with your player choice or theirs.

Yes - you could move files to a public page but then the authorized users will be able to then download them freely (if authorized) but SAVE them for permanent usage. Is that something you are prepared for? It makes you liable for breaking copyright laws!
Copy linkTweet thisAlerts:
@PeterPan_321authorMar 21.2019 β€”Β Well I don't want to get into the weeds here... but just suffice to say that when people visit a music site, they may want to just play the music. If you're on a phone, you likely don't have an ordinary file system anyway. But I just want to give them the choice. And the scheme will be a little more complicated than that. If a song is requested either by my player or a download request, I'll likely move it to a public folder I create with some randomization in the file name, so once the player has finished playing it (or the visitor has downloaded to their HD), the file and the random temp directory will be deleted.

But I have another problem now and I guess I'm back to square one. It seems my assumption that a PHP file could automatically access any protected directory just because it is on the same server seem to be wrong. At least with the simple PHP script I'm trying. When my script tries to do the actual readfile() call, an error is posted in my error_log: "failed to open stream: HTTP request failed! HTTP/1.1 401 Authorization Required". Well that's good I guess because I don't want a script on the site that allows anyone to access anything from anywhere. But I guess I still have to figure out how to let the PHP script get access to the folder. I know I could keep the "user" and "password" in PHP vars, and they would not be visible to anyone. BUt I don't know the mechanics of requesting the authorization via PHP. My script is pretty short here, as I'm just testing the premise of getting a file from the protected directory. I just pass it the rest of the file path as a variable when being called from a button, on an HTML page, so I can get the file/path variable ($localPath) with a GET.

[code=php]
<?php
// file fetch. pass file path. Code will add full URL.
// will also log uses.
$rootPath = 'http://mydomain.org';
$logFile = 'downloads.log';

if(empty($_GET['file'])) { notFound(); }
$localPath = $_GET['file'];
$fullPath = $rootPath . $localPath;

$path_parts = pathinfo($fullPath);
// $ext = strtolower($path_parts["extension"]); // in case I want to send special headers later
$current = file_get_contents($logFile);
$current .= "rn" . $_GET['file'] . " Download Request at " . date(DATE_RFC2822);

// generic headers, so browser won't interpret the file ans music and try to play
// during an ordinary download.

header("Content-type: application/octet-stream");
header("Content-Disposition: filename="" . $path_parts["basename"].""");
$bytesRead = readfile($fullPath);
$current .= " Bytes read = " . $bytesRead;

file_put_contents($logFile, $current); // log the file request
exit;

function notFound() {
global $fileName;
error_log("n ** file unreadable: " . $fileName);
header('Location: http://mydomain.org/404.shtml');
exit;
}

?>
[/code]
Copy linkTweet thisAlerts:
@ginerjmMar 21.2019 β€”Β There is a way to provide the credentials but I am not privy to it. OTOH - you don't need to secure the folder - just place it above or beside your domain root folder so that it is outside the brower-accessible tree and don't use the folder's name in your urls.

As for allowing downloads of files I do think you have to be concerned about copyright laws since you could be providing licensed digital files to users without permission.
Copy linkTweet thisAlerts:
@PeterPan_321authorMar 22.2019 β€”Β @ginerjm Well I've KIND OF gotten it to work. I say KIND OF because sometimes there is nothing worse than getting something to work, when you look at the code and think it should NOT work. First of all on a side note, this is MY music that I wrote it, and I have it copyrighted under ASCAP, and so I can distribute and sell it at will.

Now... the critical thing WRONG with the above PHP code was that I made my $rootPath = 'http://mydomain.org'; . By making the script try to access the files as an HTTP request, I was guaranteeing I'd run into an authorization problem. Things got better when I changed the path to simply "/". Further, I decided to put the whole path to the files into that $rootPath = variable, and just let my HTTP page request the file Itself. So with a test file called 'silence.mp3", the test link on a web page simply says...

<a href="/scripts/fetchAfile2.php?file=silence.mp3">test download</a>

And my "fetchafile2.php" code now looks like this...

[code=php]

$rootPath = "/mp3/private/";
$logFile = 'downloads.log';

$localPath = $_GET['file'];

$fullPath = $rootPath . $localPath;

$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);

$current = file_get_contents($logFile);
$current .= "rn" . $_GET['file'] . " Download Request at " . date(DATE_RFC2822);

header("Content-type: application/octet-stream");
header("Content-Disposition: filename="" . $path_parts["basename"].""");

$bytesRead = readfile($fullPath);
$current .= " Bytes read = " . $bytesRead;

file_put_contents($logFile, $current);
exit;
[/code]


Well it didn't work, but at least i was not getting authorization errors. The weird things is that the error I was getting was showing the file attempted by readfile() was NOT FOUND. It said...

"readfile(/mp3/private/silence.mp3): failed to open stream: No such file or directory"

OK, but this was super confusing @ginerjm#1602078 !! That is exactly where the file is!!! So on a whim I changed the $rootPath variable like this...

$rootPath = "../mp3/private/";

So with the script residing in "/scripts", That rootpath should just point the readfile one directory down, and then back up to where the MP# files are. So when combined with the single variable I'm sending ("silence.mp3", ) that works! No error was reported, no authorization error, and the log file said...

/mp3/private/silence.mp3 Download Request at Thu, 21 Mar 2019 21:10:46 -0600 Bytes read = 2403008

Yes, the file was indeed downloaded to my browser's download directory!

So I'm thrilled this worked. there is an ongoing mystery as to why "/" did not point to the root I THINK is should.. I'm sure the answer is buried deep in the PHP.INI file on the server. But relative paths are fine, and maybe even more portable!

So now that i know this is doable, I'll have to remove this PHP file immediately until I can add my own authorization security, because apparently anyone finding it as it is could download ANYTHING from my server! LOL!
Γ—

Success!

Help @PeterPan_321 spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 β€” BETA 4.27,
whats_new: community page,
up_next: more Davinciβ€’003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinciβ€’003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,

tipper: @Samric24,
tipped: article
amount: 1000 SATS,
)...