Use PHP readfile to hide a streams URL - php

I need to hide the url of an audio stream and so I have thought that since I have a download script that uses readfile(); to do this I could do the same but I am not sure how to manipulate this in javascritpt. In fact I have no idea and am not even sure if it is even possible to do it this way.
So far I have a PHP file that is accessed by javascript to get the URL of a track from an ID when the play button is clicked.
$T_ID = mysqli_real_escape_string($con, $_GET['t_id']);
$qry = "SELECT url FROM tracks WHERE T_ID = $T_ID";
$result = mysqli_query($con, $qry);
$row = mysqli_fetch_array($result);
$url = $row['url'];
$path_parts = pathinfo($url); //get path info
$file_name = $path_parts['basename']; //only include mp3 track just incase path added in there
$file_path = 'uploads/' . $file_name; //add path
echo $file_path;
The url from that is just used by javascript to specify the new Audio();. However, anyone that know show to open up the console and view the network tab can just find the URL for the track and download it. Which is not what I want or my users want at all.
My preliminary idea is to replace echo($file_path) with readfile($file_path) but I know that it will somehow need to be manipulated in javascript. If PHP reads the file as binary then can javascript do so too to stream it?

By using readfile(), all you are doing is making the php script into the URL for the download. The javascript Audio() object still fetches that URL (and maybe start playing before it's all loaded) just as it would with a direct url to the file. It's not streaming it. You are just hiding the url to the file.
If you want to offer restricted access, then this is a fine way of doing it, but if anyone can still download using this new URL, then you aren't protecting anything except the actual location of the file.
Also, remember to set headers for the correct mime type, e.g.
header('Content-Type: audio/mpeg');
header('Content-Length: '.filesize($file_path));
readfile($file_path);
You may also want to set cache expiry headers, etc.

Related

HTML - In browser viewing and forced downloads

On the website I am working on I like to offer users two links for every download, "View" and "Download". Most if not all of these downloads will be PDF format. The goal of View is to cause the document to be displayed in the browser with the PDF plugin/extension, whereas the Download link forces a download to local storage.
I have it working this way:
<div class="DownloadLinks">
View
Download</div>
</div>
But now I want to do it this way (using PHP to store and retrieve documents) and it doesn't work any more:
<div class="DownloadLinks">
<div class="DownloadLinks">View
Download</div>
</div>
I think the problem might be that the browser doesn't see a file extension in the link therefore performs a download instead of firing up the PDF plugin. Unfortunately I am just using a Content Management System and I don't have access to the PHP script and I can't change any of that. How can I get this to work as intended?
I would recommend just using javascript because of your CMS. Here's a good function for that.
var downloadURL = function downloadURL(url) {
var hiddenIFrameID = 'hiddenDownloader', iframe = document.getElementById(hiddenIFrameID);
if (iframe === null) {
iframe = document.createElement('iframe');
iframe.id = hiddenIFrameID;
iframe.style.display = 'none';
document.body.appendChild(iframe);
}
iframe.src = url;
};
This would be for the download script. If you wanted to uses php so that you could also track the number of downloads (or something along thos lines), your could just use AJAX for that.
You need to add the following headers to get_document.php when you click the download link (you may need an extra GET parameter to indicate this):
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Content-Length: ' . filesize($file));
Where $file is a path to your file, alternatively you can manually substitute the name and file size, but make sure the name includes the correct extension.
Edit, you say you don't have access to the CMS - how about the HTTP server? Or is it a hosted service?

PHP as image src - Tracking

I am using a PHP script that outputs an image, what I am trying to do is track when the image is opened on an email, The code works to display the image but does not run the database query and update the count.
The PHP code as follows.
$image = $_GET['image'];
require_once('connections/site.php');
mysql_select_db($database_site, $site);
$query_requests = "SELECT count FROM tracker WHERE id = '1'";
$requests = mysql_query($query_requests, $site) or die(mysql_error());
$row_requests = mysql_fetch_assoc($requests);
$count = $row_requests['count'];
$newcount = $count++;
$query_update = "UPDATE count SET count = '$newcount' WHERE id = '1'";
$update = mysql_query($query_update, $site) or die(mysql_error());
header("Content-Type: image/jpeg");
readfile('https://mysite.co.uk/images/'.$image);
Maybe I should be using a different method? I was searching around for a way of tracking a standard image open but I couldn't seem to find a decent method so I thought I would try and cook something up to do this.
The problem is that readfile reads and directly writes to the output buffer, hence if you're going to use that method, you'll need to move the readfile to the end of your script.
However, there are a few other concerns:
Your script is using a deprecated database API functions (mysql_*) - you really need to read How can I prevent SQL injection in PHP?
You're potentially exposing other files as you're not attempting to validate what's being fetched via readfile. For example, if $_GET['image'] contains ../connections/site.php, your script will potentially output raw (i.e.: un-parsed) PHP files containing sensitive database settings, etc.) See the existing Preventing Directory Traversal in PHP but allowing paths question/answer for more information.
You're not outputting Content-Type, or Content-Length headers, etc.
put readfile('https://mysite.co.uk/images/'.$image); at the bottom of your code and add this line just before it:
header("Content-Type: image/jpeg");

PHP: set image as background without revealing path

The following problem I can't really wrap my mind around, so really if you guys can't be bothered to supply the entire code some tips leading in the right direction would be great!
So, I have a script where users can upload images to a server. PHP takes care of validating the file and saving it using a new filename in another folder, neither known by the client. Now, the client should be able to see the uploaded image, in html simply:
style="background-image:url('testimagegif.gif');
But preferably the client should not be able to see the path nor the file name of the image saved on the server. I know about using header('Content-type: ... for forcing the client browser to download files, but I do not see how this, nor any similar solution could be applied to this case. Same goes for readfile. If I use it the browser simply downloads the image, not placing it in the html.
You should probably be moving the files into a publicly readable folder on your webserver if you want to serve them.
Otherwise, you'll need something like readfile()
There are two options for this, you could use the data protocol, which would embed the whole image into the URL of the background ( this isn't recommended if the image is bigger than a few kb. ) or you can use a script to present the image by encoding or recording a unique key for the image, eg bg.php?id=4323-34442-3432-4532 which checks a db for the id to retrieve the file path then echoes the content with the right content type.
Some examples;
based on the Data URI wikipedia page
Data URI Method
Assuming a function like this;
function data_uri($fileID) {
$fRecord = mysql_fetch_array(
mysql_select("SELECT filePath, mimeType from fileTable WHERE fileID = " $fileID . ";")
);
$contents = file_get_contents($fRecord['filePath']);
$base64 = base64_encode($contents);
return "data:$fRecord['mimeType'];base64,$base64";
}
Then in your html/php page you'd have the following snippet
style="background-image:url('<?php echo data_uri($fileID);?>'
PHP Image Dump
Assuming a function like this;
// Given a filename and a mimetype; dump the contents to the screen
function showDocumentContent($fileID){
$fRecord = mysql_fetch_array(
mysql_select("SELECT filePath, mimeType from fileTable WHERE fileID = " $fileID . ";")
);
header( 'Content-Encoding: none', true );
header( 'Content-Type: ' . $fRecord['mimeType'], true );
echo readfile( $fRecord['filePath'] );
}
Then in your html page you'd have this;
style="background-image:url('image.php?fileID=123')
In the first case, images larger than a few KB will result in equally large HTML pages, and may not be supported in browsers consistently. In the second case, you'd effectively have created a php script that is pretending to be an image. In both cases, the real path to the binary files on your server is abstracted away by storing a mapping in a database.
If you store the paths to the files somewhere like a database or a file, you can use readfile() to output the file once you retrieve the path.
Combine that with the content-type header, and set the background-image URL to the PHP script with the correct query string like so:
style="background-image:url('script.php?img=30382');"
You must expose some path to the client, because their browser has to access the file. You can use your webserver config to serve at an indirected location, or serve the image with PHP and have the real path in a call to readfile()

Moving images from doc root for added security

My site uses bookmarklets to gather data from external sites, kinda like Pinterest. I'm concerned about security and want to move the images the bookmarklet gathers from the doc root up one level. My script has some hefty security checks in place, but I want to add this as a last line of defense.
How do I access my images within my script? Obviously using ../userimages/id/image.jpg wont work. I'm using Apache.
Thanks!
Proxy the image
You would use a proxy script to feed the images through like the following example:
// open the file in a binary mode
$name = '../userimages/id/image.jpg';
$fp = fopen($name, 'rb');
// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));
// you may like to set some cache headers here
// dump the picture and stop the script
fpassthru($fp);
exit;
This example is from the PHP manuals fpassthru() page. You would save this script somewhere in your servers document root/httpdocs folder.
"Spoofing" the URL to the image
The easiest way to give the PHP file the appearance of being an image file to a user/browser is to use Apaches mod_rewrite. Usually I use a URL structure something like this:
http://www.example.org/image-id/image.png
Where image-id is the unique identifier for that particular image. This way the file has the correct extensions of an image instead of .php.

Is directly linking to an image okay for images uploaded to the server with a custom PHP script?

For an image file (JPEG) that has been uploaded to the server via a PHP script (to a directory such as http://www.somedomain.com/images, is it a good idea to allow the client to get the image's direct address (such as http://www.somedomain.com/images/someimage.jpg and paste it into a WYWSIWYG text editor (such as TinyMCE)?
I am wondering if there is a preferable method where the direct address is encrypted?
Please, if I should just link directly to the image, just say so.
Thanks!
Note: I have modified this question from my original. Please see revisions if you are curious, but I think I was asking the question incorrectly. My apologies to the people who already answered.
As long as you check correctly WHAT is being uploaded, it shouldn't be a problem. So please at least use getimagesize or a similar function to make sure it's an image that's being uploaded, AND make sure the extension on the file is correct so that it will never be run through the PHP interpreter - to prevent someone from uploading an image with a PHP script attached.
BTW Here's a nice whitepaper on uploads and security : http://www.scanit.be/uploads/php-file-upload.pdf
Depending on the CPU Constraints of your web-hosting service you can write a service to 'serve' the images to your users.
Here is some very BASIC code, it needs spiffing up and cleaning up for XSS/etc...
<?php
$basePath = "/path/to/my/image/store/not/web/accessible/";
$file = NULL;
if (isset($_GET['file']))
$file = $_GET['file'];
if ($file != NULL)
{
$path = $basePath . $file;
// $file needs to be checked for people
// trying to hack you, but for the sake of simplicity
// i've left it out
$mime = mime_content_type($path);
$size = filesize($path);
header("Content-Length: " . $size);
header("Content-Type: " . $mime);
header('Expires: 0');
readfile($path); // Outputs the file to the output buffer
}
?>
Obviously you can put whatever security checks in here you want. But this way your files are below the web dir, and you can apply logic to thier accesibility. This is typically used more for FILE vs. Images, but you can do the same thing here.
Images Accessed like this
http://www.mysite.com/image.php?file=hello.jpg
And you can use mod_rewrite to rewrite urls like this:
`http://www.mysite.com/images/hello.jpg
Into the first url.
I Cannot stress enough the need for further security checking in the above example, it was intended to show you how to serve a file to the user using PHP. Please don't copy & use this verbatim.
Wordpress uses direct links for images. The permalink function simply puts the image on a page along with metadata for comments, but the images' SRC attributes still link directly to the image.
why are you concerned about revealing your image location. Hotlinking?
if so you can prevent hotlinking with htaccess
http://altlab.com/htaccess_tutorial.html
Didn't you get your answer already?
Every site reveals image location to the browser. It's just the way web works.
Got any reason to "encrypt" original location?

Categories