Getting private files or showing private images in a HTML page - javascript

I wonder how to publishing private user files but in the way only that user can access it. I mean, after logging in, there would be many files that only the user logged in can access. For instance, an image collection or maybe a mp3 file to play in a html5 player or a pdf to download. But the point is the user logged is the owner of the files and he is the only one who can get them.
My problem is that in the HTML code I need to provide a link in the image attribute or a link in the html5 mp3 player or a file link to download it. And this link has to be pointing to a public directory so it can be accessed by everybody.
My question is: how do people implement that kind of security or functionality nowadays?
Another example. In facebook, you have your own private images and even if you give the full link of any private image to a friend, he cannot see it unless you tag that image as "public" or something like that.
Possible solution
I have been researching about the ideas people have given me here. I did try some things; for instance, I went to Facebook and got the link of a private image of mine (by right clicking over and copy image link...) I put that link in other browser and after logging out of Facebook, and I can see the image in the browser so the conclusion is the file has to be public in the moment we access. Other thing is we hide the name file or something like that.
I propose to:
Users file has to be in a folder which has a "unique reference" as name that only can know the own user. So by storing this reference in a database like a password ... you got the idea...
Sometimes, we will need to have "public files" with limited access, I mean, I want to people to play a mp3 in the html5 player or a video, but I don't want to let them to download it. In this cases, we could obfuscate the code making it hard to find the full link.

Alright. Since I'm unformilliar with your code, I'm going to use a bit of general code as an example. All you have to do is adjust it.
First a very basic html that will upload the video / mp3 / image or whatever:
<form name="upload" action="" method="POST" ENCTYPE="multipart/form-data">
Select the file to upload: <input type="file" name="userfile">
<input type="submit" name="upload" value="upload">
</form>
Next you need to prepare your database table:
CREATE TABLE `uploads` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`userid` INT(11) NOT NULL,
`name` VARCHAR(64) NOT NULL,
`original_name` VARCHAR(64) NOT NULL,
`mime_type` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
Now comes the file upload part. At this point I should mention that I'm not very well formilliar with MySQLi. Therefor I'm using PDO in this example. You should however be able to adjust it to MySQLi if you prefer:
<?php
session_start();
# My PDO class. A link to it can be found at the bottom of this answer
require_once 'pdo.class.php';
# Send user back login if not logged
if(!isset($_SESSION['your_login_userid_here'])){
Header("Location: your_login.php");
}
# If file is uploaded
if(isset($_POST['upload'])){
$uploaddir = 'uploads'; # Your upload directory
function tempnam_sfx($path, $suffix){
do {
$file = $path."/".mt_rand().$suffix;
$fp = #fopen($file, 'x');
}
while(!$fp);
fclose($fp);
return $file;
}
# Make a regular expression to check for allowed mime types
$pattern = "#^(image/|video/|audio/)[^\s\n<]+$#i";
if(!preg_match($pattern, $_FILES['userfile']['type']){
die("Only image, video and audio files are allowed!");
}
$uploadfile = tempnam_sfx($uploaddir, ".tmp");
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
# Define db configuration
define("DB_HOST", "localhost");
define("DB_USER", "username");
define("DB_PASS", "password");
define("DB_NAME", "dbname");
$db = new Database;
$db->query("INSERT INTO uploads SET userid=:id, name=:filename, original_name=:oriname, mime_type=:mime");
$db->bind(":userid",$_SESSION['your_login_userid_here']);
$db->bind(":filename",basename($uploadfile));
$db->bind(":oriname",basename($_FILES['userfile']['name']));
$db->bind(":mime",$_FILES['userfile']['type']);
try {
$db->execute();
} catch (PDOException $e) {
unlink($uploadfile);
die("Error saving data to the database. The file was not uploaded");
}
$id = $db->lastInsertId();
echo "File succesfully uploaded.\n";
} else {
echo "File uploading failed.\n";
}
} else {
# No upload received. Send user to upload page
Header("Location: html_upload_form.html");
}
?>
So what is happening? Basicly we are uploading the file to our upload dir where we give it a random filename with the .tmp extension. In our database we're saving this random filename, the original filename, and what type of file it is. Ofcourse we're adding the userid as well so we know to whom to file belongs. The benefits of this approach are as follows:
- No one will ever know the file name on the server.
- No one will ever know the original file name except the owner.
- The Mime Type allows us to setup our HTML5 mediaplayer.
- The owner is able to download the file, but no one else.
Up comes the PHP file that will retrieve the uploaded file for us:
<?php
session_start();
require_once 'pdo.class.php';
# Send user back login if not logged
if(!isset($_SESSION['your_login_session_here'])){
Header("Location: your_login.php");
}
# Define db configuration
define("DB_HOST", "localhost");
define("DB_USER", "username");
define("DB_PASS", "password");
define("DB_NAME", "dbname");
$uploaddir = 'uploads/';
$id = $_GET['id'];
if(!is_numeric($id)) {
die("File id must be numeric");
}
$db = new Database;
$db->query('SELECT userid, name, mime_type FROM uploads WHERE id=:id');
$db->bind(":id", $id);
try {
$file = $db->single();
} catch (PDOException $e) {
die("Error fetching data from the database");
}
# Check if file belongs to user
if($_SESSION['your_login_session_here'] != $file['userid']){
die("This file does not belong to you!");
}
if(is_null($file) || count($file)==0) {
die("File not found");
}
$newfile = $file['original_name']; # The original filename
# Send headers and file back
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename='.basename($newfile));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($uploaddir.$file['name']));
header("Content-Type: " . $file['mime_type']);
readfile($uploaddir.$file['name']);
?>
What is happening? In this file, you're using the file id to retrieve the users file from the database. That way no user needs to know any filename at all! Thanks to our headers, the owner of the file will however be able to download the file with it's original name, without knowing the filename on the server at all.
So next I will give you a short example on how to show the user all his files:
<?php
session_start();
require_once 'pdo.class.php';
# Send user back login if not logged
if(!isset($_SESSION['your_login_session_here'])){
Header("Location: your_login.php");
}
# Define db configuration
define("DB_HOST", "localhost");
define("DB_USER", "username");
define("DB_PASS", "password");
define("DB_NAME", "dbname");
$db = new Database;
# Retrieve all files from the user and build links
$db->query("SELECT id, original_name, mime_type FROM uploads WHERE userid=:id");
$db->bind(":id",$_SESSION['your_login_session_here']);
try {
$files = $db->resultset();
} catch (PDOException $e) {
die("Error fetching data from the database");
}
if($db->rowCount() > 0){
foreach($files as $file){
echo "". $file['original_name'] ."<br />";
}
} else {
echo "No files found!";
}
?>
And finally comes the PHP file that will display the file in some HTML mediaplayer. I will only 2 examples here, you should be able add your own very easily:
<?php
session_start();
# Send user back login if not logged
if(!isset($_SESSION['your_login_session_here'])){
Header("Location: your_login.php");
}
$id = $_GET['id'];
$type = $_GET['type'];
if(strpos($type, 'video/') === 0){ ?>
<video width="480" height="320" controls>
<source src="your_file_retriever.php?id=<?php echo $id; ?>" type="<?php echo $type; ?>">
</video>
<?php } else if(strpos($type, 'audio/') === 0){ ?>
<audio controls>
<source src="your_file_retriever.php?id=<?php echo $id; ?>" type="<?php echo $type; ?>">
</audio>
<?php } ?>
Now to make sure no one is going to just brute force attack your uploads folder, you need to create a .htaccess file inside this folder. The following code will block anyone from accessing that folder except the server itself ofcourse:
order deny,allow
deny from all
allow from 127.0.0.1
My PDO Class.

There are many solutions. The one I am using for a dating site is to have folder names that are the same as the unique reference for the user. All files in there belong to that user. However access is still controlled by php providing the correct links in the html.
That is the simplified answer. because I don't want the number of sub-folders in the image folder to be in the thousands, I hash them into another level of folders.

Related

Upload blob audio file to aws ec2-instance using php

I am creating a web application where user can record audio and then can upload it to the server.
I am able to record the audio and also was able to send the blob data to the server. But i cannot push file into the ec2-instance (aws hosting enviornment). I am attaching the php code.
I am not sure which path should i use.
Here is the Php Code.
<?php
print_r($_FILES);
$uploaddir = '/var/www/html/public/src/audio/';
$uploadfile = $uploaddir . basename($_FILES['audio_data']['name']);
$size=$_FILES['audio_data']['size'];
$input = $_FILES['audio_data']['tmp_name']; //temporary name that PHP gave to the uploaded file
$output = $_FILES['audio_data']['name'].".wav";
if(move_uploaded_file($input, $$uploadfile)){
echo "uploaded";
}
else{
echo $uploadfile;
}?>
Is there a way to push data and create file on hosted aws-ec2 instance? Is there any changes required in the php file?
This is the image of response from server

How to generate a .doc using AJAX and PHP

today i need some help, i know its not that hard and there is a lot of help for doing this in php in this site but i couldn't find nothing with AJAX, the technology im learning now and i want to master some day.
My code is the following.
$(".descarga").click(function(){
var paquete={idArchivo:$(this).val()};
$.post("includes/descargarPublicacion.php",paquete,procesarDatos);
});
So when a buttom from the "descarga" class i make a "packet", which i use it with the post method to send the data to the php file called descargarPublicacion.php
This is how it looks the php file:
<?php
session_start();
$mysqli = new mysqli("localhost", "root", "", "registroflashback");
if (isset($_GET['idArchivo'])) {
header("Content-type: application/vnd.msword");
header("Cache-Control: must-revalidate,post-check=0, pre-check=0");
header("Content-disposition:attachment;filename=yeaboi.doc");
header("Expires: 0");
$idPubliGet=$_GET['idArchivo'];
$resultadoBusqueda=$mysqli->query("SELECT * FROM publicaciones WHERE idPubli='$idPubliGet'");
if ($resultadoBusqueda->num_rows>0) {
//$resultadoBusqueda['titulo'];
echo 'descarga exitosa';
}else{
echo 'descarga no exitosa';
}
}else{
echo 'descarga no exitosa';
}
?>
I made a little research and people told me to use the headers to convert the file and download it, but it dosnt works for me, it dosnt generates any file, however it executes the "echo descarga exitosa" which i use as return value for the following function in the js file.
function procesarDatos(datos_devueltos){
alert(datos_devueltos);
if(datos_devueltos=="descarga exitosa"){
$("#alertaDescarga").show(1000);
}
if(datos_devueltos!="descarga exitosa"){
$("#alertaDescargaError").show(1000);
}
}
How i could generate a .doc file from html using ajax and jquery? I know i have it almost, it should be some detail but i dont know which one is, thats why im asking some experienced help! Thank you !
I do not understand why you want to to serve the .doc file via ajax. In my opinion it's easier to just provide valid .doc over a normal GET Request.
$(".descarga").click(function(){
//onClick transfer id via Get-Param and download file
window.location = "includes/descargarPublicacion.php?idArchivo="+$(this).val();
});
php part (descargarPublicacion.php)
<?php
if (isset($_GET['idArchivo'])) {
header("Content-type: application/vnd.msword");
header("Cache-Control: must-revalidate,post-check=0, pre-check=0");
header("Content-disposition:attachment;filename=yeaboi.doc");
header("Expires: 0");
//ID is available via GET because we send it as Url Param
$idPubliGet=$_GET['idArchivo'];
//#TODO fetch relevant data with given ID
//#TODO generate valid(!) doc File output
//- just echo'ing something will not result in an valid document for Word
echo $coumentContent;
}
?>
To provide/generate a valid Word document is a little bit more complicated. I would recommend you to look into a libary which does all the work for you.
E.g. https://github.com/PHPOffice/PHPWord
If you instead want to serve just some simple .txt File - change your header Content-Type to text/plain and the filename to yeaboi.txt and print/echo out the text-content

PHP script to download text from site, convert and store it locally

How can I store text from a site to a local file?
So basically the script needs to do the following:
go to this site (fake site)
http://website/webtv/secure?url=http://streamserver.net/channel/channel.m3u8**&TIMESTAMP**
where TIMESTAMP can be a timestamp to make it unique.
the site will respond with:
{
"url":"http://streamserver.net/channel/channel.m3u8?st=8frnWMzvuN209i-JaQ1iXA\u0026e=1451001462",
"alternateUrl":"",
"Ip":"IPADRESS"
}
Grab the url and convert the text as follows:
http://streamserver.net/channel/channel.m3u8?st=8frnWMzvuN209i-JaQ1iXA\u0026e=1451001462
must be:
http://streamserver.net/channel/channel.m3u8?st=8frnWMzvuN209i-JaQ1iXA&e=1451001462
so \u0026e is replaced by &
and store this text in a local m3u8 file.
I am looking for a script either php or any other code is welcome which can perform this. Any help is appreciated.
I tried a small script just to show the contents but then I get the error:
Failed to open stream: HTTP request Failed!
It seems that php tries to open it as a stream instead of a website. It should see it as a site because only then the response is sent.
<?php
$url = 'http://website/webtv/secure?url=http://streamserver.net/channel/channel.m3u8&1';
$output = file_get_contents($url);
echo $output;
?>
This is not a tutorial website, so I am not going to provide you more details. You can try the following code:
<?php
$json_url = "http://linktoyour.site"; //change the url to your needs
$data = file_get_contents($json_url); //Get the content from url
$json = json_decode($data, true); //Decodes string to JSON Object
$data_to_save=$json["url"]; //Change url to whatever key you want value of
$file = 'm3u8.txt'; //Change File name to your desire
file_put_contents($file, $data_to_save); //Writes to File
?>
I think there is issue with your PHP configuration.
It like as allow_url_fopen is denied.
See more http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen

check script status in PHP using ajax

I have a file upload page in my application. I need to show "Uploading" while file is uploading then show "Processing" while file is processing. Then after completion of script my page got redirected to some url.
I have tried to use PHP SESSIONS in the script. As in code below:
$_SESSION['uploaded']=0;
if (!empty($_FILES)) {
$tempFile = $_FILES['file']['tmp_name'];
$targetPath = dirname( __FILE__ ) . $ds. $storeFolder . $ds;
$_FILES['file']['name']=date('Ymdhis').$_FILES['file']['name'];
$targetFile = $targetPath. $_FILES['file']['name'];
if(move_uploaded_file($tempFile,$targetFile)){
$_SESSION['uploaded']=1;
//some processing here which takes some 4-5second to complete
}
}
After file upload complete I update session. I am checking session every second by calling following function in javascript:
function countdown(seconds){
console.log(<?php echo $_SESSION['uploaded']; ?>);
if(<?php echo $_SESSION['uploaded']; ?>==0){
setTimeout(function() {
//uploading
seconds--;
countdown(seconds);
}, 1000);
}
else{
//processing
}
}
After searching from google for long time I came to know that in a single script SESSION is locked till script execution completed. Then I used session_write_close(); But it also not works. I am always getting 0 value of SESSION.
Please help me figuring out solution in simplest way. Thanks.
UPDATE
Unable to make it work with Ajax request also. So further tried using the MySQL table.
What I do is create table when upload script is called. Then insert value of status=0 in it using following code:
$session=session_id();
$stmt=$conn->prepare("DROP TABLE IF EXISTS $session");
$stmt->execute();
$stmt=$conn->prepare("CREATE TABLE $session (id INT(11), status INT(11))");
$stmt->execute();
$stmt=$conn->prepare("INSERT INTO $session VALUES(1,0)");
$stmt->execute();
Then after upload completion I update the status to 1 and do the processing on file.
Then after successful completion of script I redirect to result page and drop table using session_id().
But My Ajax script which is checking status every second doesn't respond till the upload.php script ends. I have tried closing connection after every query but in vain. Code on getstatus.php
<?php
session_start();
$session=session_id();
require_once('connect.php');
$stmt=$conn->prepare("SELECT * FROM $session WHERE id=1");
$stmt->execute();
$res=$stmt->fetch(PDO::FETCH_ASSOC);
echo $res['status'];
?>
Unable to find solution for it till now. Help is greatly appreciated. Thanks.
Instead of invoking a PHP process on the server side every second, you could use a static file to check the upload state.
When generating the upload form for the client:
Create a tempnam for a directory that is accessible for the
client.
Write 'uploading' to the temporary file
Store the filename in the session. (Be aware: The user might open multiple upload forms. Store the filenames in an array)
Send the filename to the client as a hidden field.
On the server side after user submitted the form:
Check if filename sent from the client matches a filename stored in the session.
Write 'processing' to the state file
At the end of your upload script write 'finished' to the state file
On the client side after user submits the form, check the upload state by doing ajax requests on the state file.
Remarks
Disable caching for the state file with .htaccess. If this is no option you can achieve the same behavior with a php state script and the upload state saved to a session variable instead of a state file.
To make sure all generated files are deleted register a destroy handler that deletes files generated in the session: http://php.net/manual/en/function.session-set-save-handler.php
<?php echo $_SESSION['uploaded']; ?> is preprocessed by PHP only once, just before this javascript is sent to client. That said, the javascript on client looks like:
function countdown(seconds){
console.log(0);
if(0==0){
setTimeout(function() {
//uploading
seconds--;
countdown(seconds);
}, 1000);
}
else{
//processing
}
}
You should find other way (ajax?) to update information on the client side.
This became too long for a comment.
I'm unsure how you'd respond with progress information with PHP. I tried once and failed.
Socket.io is awesome in Node.js and there is a PHP server emitter. I would potentially give that a go. It should offer near instantaneous communication without waiting for scripts to complete.
Alternatively I would check out Jquery upload, it has a PHP server script. Supports progress bars Jquery Upload. Either implement it directly or check out the source code for how display progress info. I tried having a quick look but couldn't identify how they do it easily.
Why use DATABASE if you can do it on server ?
To save your bandwidth and database traffic you can seperate your process into 2 file
Create upload.php to serve uploading process
$_SESSION['uploaded']=0;
if (!empty($_FILES)) {
$tempFile = $_FILES['file']['tmp_name'];
$targetPath = dirname( __FILE__ ) . $ds. $storeFolder . $ds;
$_FILES['file']['name']=date('Ymdhis').$_FILES['file']['name'];
$targetFile = $targetPath. $_FILES['file']['name'];
if(move_uploaded_file($tempFile,$targetFile)){
// Save path to session var
$_SESSION['uploaded']=$targetFile;
//You can tell client if the uploading process were done and show 'Processing ...'
// Place some code
exit;
}
}
Next, create a file called progress.php
// check
if(!empty($_SESSION['uploaded'])){
// Do your processing code here
// Remove session
unset($_SESSION['uploaded']);
// Then send response to client after your processing were done
echo 'Done';
exit;
}
You can redirect client using jquery as you tagged it. Good luck

PHP capture form data and image upload, save to server

I know that this should not be a difficult thing to accomplish in PHP however it is giving me the hardest time!
I am trying to do this:
1) Capture form string data AND an image upload in a single form
2) Upload both types of data to the server with a single non-ajax/traditional POST to a simple PHP script (process.php in this case)
3) Take the image the user uploaded, save it in as a text file in a directory named dynamically by the first letter of the first name and the entire last name concagnated together so for me the directory structure would be as follows: /home/uploads/nabrams/image.jpg, /home/uploads/nabrams/userdata.txt,
*The text file will contain the text strings from the client side form, the image from the input[type="file"], once again contained in the same form, sent to the server with 1 submission.
I am using a text file in order to provide the simplest case possible.
Here is the code I am working with currently:
<?php
$uploaddir = '/home/nicholasabrams/public_html' + '/newprofiledata/' + $lname + '/' + $_FILES['userfile']['name'];
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
echo "<p>";
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n";
} else {
echo "Upload failed";
}
echo "</p>";
echo '<pre>';
echo 'Here is some more debugging info:';
print_r($_POST);
print_r($_FILES);
print "</pre>";
However when attempting to upload an image of several formats and sizes (multiple attempts), I am stuck at an error-less blank window. To no surprise, the script did not upload or rename the image as desired.
Also - when trying to add the post data directly into the file name like so:
$uploaddir = '/home/nicholasabrams/public_html/' + $_POST['lname'] + '/' + $_FILES['userfile']['name']; $uploadfile = $uploaddir . basename($_FILES['userfile']['name']); if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile))...
I get filenames with 0pictureNameHere.jpg instead of NAbrams.jpg or if using post data to set the directory, I will never get the image or data in this way.
Side note:
I am a Javascript and jQuery ( <- mainly) developer, would it be worth it for me to attempt doing this with express or some other node module? I am not experienced with node although I have been "using it" for the last few months.
Thanks for the help!

Categories

Resources