Secure File Download from a path outside of website root

I have a website where users can download personal PDF documents. For security reasons the files are stored in a directory outside of the website root.
I use webassist databridge download to accomplish the download. It would be great if I could do this with wappler. Any chance on this?

You can do this with Wappler. You can create dynamic folders and copy files across to them. Example when you register a user on the same Action Create a directory named using the new users UID etc (for example, /usrFilesuplds/h454fGf876KJjh/). You could then use a Copy file to dump a .htaccess in to the new directory to allow for strict domain based access only. Then each user would have a unique directory containing their specific .PDFs…

Directories being created, image uploaded to folder, .htaccess and blank index.php copied to new directories:

2018-12-31_12-50-06

The Create folder path:

I just realised I posted shots of DMX Extensions in Dreamweaver, the method is exactly the same though!

1 Like

Thank you Dave for your help,
first of all I wish you all the best for 2019!
My problem is a little bit different.
The files are from a local management software and I created a webfrontend for it.
Some user specific files are transfered from the local server once a night to a webserver. The filepath is stored in a local MS SQL Database. The database (a part of it) is also exported once a night to the webserver.
For better understanding I give you an example:

Source: Windows Server Path \\server\path\dbpath\

Target: Linux Server Path /usr/home/myuser/private/dbpath/

I transfered the files outside of wwwroot, so noboby can access the files with a direct http download.
With the webassist extension I can create a formbased download from the path outside of wwwroot.
I hope I could clarify my situation :slight_smile:

Dear Wappler Team,

is there a workaround for my problem?

Thanks a lot for your help in advance!

Marcel

If no one else replies I’ll try to come up with an idea for you tomorrow @MH2ag (am currently suffering with a bout of man-flu here and am just off to bed). Sorry I did not see your above reply earlier.

To clarify a little bit more how I do this at the moment with WebAssist tools:

In the header:

<?php
WA_DFP_SetupDownloadStatusStruct("WA_DownloadResult1");
if(isset($_POST["download"]) || isset($_POST["download_x"])){
    WA_DFP_DownloadFile("WA_DownloadResult1", "/usr/home/myuser".($dl->getColumnVal("DateiPfad",false)) ."", "".($dl->getColumnVal("Dateiname",false)) ."", "".($dl->getColumnVal("Dateiname",false)) ."", false, false, false, "", "", "", "");
}
?>

In the body:

<form role="form" id="form1_<?php echo($rsAkt_i_Dok->getColumnVal("DokumentId")); ?>" name="form1_<?php echo($rsAkt_i_Dok->getColumnVal("DokumentId")); ?>" method="post" action="<?php echo(htmlentities($_SERVER["PHP_SELF"], ENT_QUOTES)."?".$_SERVER["QUERY_STRING"]); ?>">
<div class="form-group">
<td><i class="fa fa-file-pdf-o text-danger"></i></td>
<td align="left"><?php echo($rsAkt_i_Dok->getColumnVal("FileName")); ?></td>
<td><input name="hiddenField" type="hidden" id="hiddenField" value="<?php echo($rsAkt_i_Dok->getColumnVal("DokumentId")); ?>" />
<button type="submit" class="pull-right btn btn-sm btn-default-transparent btn-animated" name="download" value="Dokument laden">Dokument laden<i class="fa fa-download"></i></button>
</td>
</div>
</form>

Hi @Dave,

I hope your man-flu is getting better.

Did you have the chance to look at my problem?

Thanks a lot for your help in advance.

Marcel

Well this can be done with simple 2 lines of PHP code as explained in:

Hi @George,

thanks for your help. I need some more explanation on this, as I’m not a programmer. :thinking:

How would I integrate this with Server Connect or App Connect? How would I combine Server Connect Output of the Filename with the correct path (outside wwwroot)?

How would I use the Server Action „if file exists“ with a path outside of wwwroot?

Paths outside site root are not supported in server connect.
That’s not something usually used and we have not integrated such a functionality in Server Connect.

I understand, but is there a workaround with php, like @George mentioned?

Still feeling like utter sh*t my friend unfortunately… Thanks for asking though!

How about storing the name of the file and the full path/url to the file in the database and using something like a scheduled event to keep everything updated and fresh? Timestamp the new files and so anything less than or equal to a specific time period is removed from the table and only files greater than the set time criteria remain?

Maybe a scheduled event is a bit much… Possibly just a view based on less than or greater than will be OK. As long as the full path/url is in the DB it should all be fine?

I‘m not sure if I understand what you mean.

It would be no problem for me to adjust the view with the full path.

I think my main problem will be the adjustment of the php script @George suggested.

Do you have an idea how to adjust this with Server Connect repeat output?

Inside your www directory, create a "image.php" file, with a similar content to:

<?php
  header('Content-Type: image/png');
  readfile("../img/" . $_GET['img']);
?>

And call your images with

<img src="image.php?img=myimage.png" />

Hi. The solution given by @George seems similar to your current setup.
Correct me if I am wrong, in your current setup, clicking on download button redirects to another PHP file (which is in your web root) where the full path of the file outside root is created and file begins downloading.

If the above observation is correct, the stackoverflow solution works in the same way. You create a file in web root, downloadimg.php, with code something like this:

<?php
header('Content-Type: image/png');
readfile("../../usr/home/myuser/private/" . $_GET['dbpath'] . "/" . $_GET['img']);
?>

Then, in your Wappler project, download link can be created like so:

<a href="downloadimg.php?dbpath=something&img=filename">Click to Download</a>

Clicking on download link will redirect to another PHP file (which is in your web root) where the full path of the file outside root is created and file begins downloading.

1 Like

Hi @nshkrsh,

thanks for your help. You are correct with my current setup.

In my current solution I use a form based download with a button. This way the path doesn’t get exposed in the URL. In the hidden value there is the Id of the document.

In a separate query on POST it will get the correct path and filename.

I’m not sure if I can do this with Wappler.

Any concerns about security?

I don’t think you need to change your correct setup in any way.
The existing method of sending POST data can be replicated in Wappler.

And, if you want to use the solution given in stackoverflow, you can change the simple anchor tag with a POST form and fetch these values in second PHP file via $_POST.

I assume you already have some security in place in the page where download button is. As for the second download page, you will have to add the same security measures before the actual file download code executes, and you should be good to go.
I usually am paranoid about security and never satisfied with any solutions. You must await reply of someone else more confident about this.

Hi @George, @Teodor and @patrick,

any chance that this will be integrated in future versions of Wappler?