prasathmani / tinyfilemanager

Single-file PHP file manager, browser and manage your files efficiently and easily with tinyfilemanager
https://tinyfilemanager.github.io
GNU General Public License v3.0
4.63k stars 1.63k forks source link

When embedding with HTML tinyfilemanager for a file download contents are wrong. #762

Open londonroadhog opened 2 years ago

londonroadhog commented 2 years ago

I have used the following to embed the file manager

image

When I access the environment within xampp (localhost), and select a simple text file with the contents "Test file for download", then press the download button on that file within tinyfilemanager, the contents of the file then contain an HTML snippet.

image

The above shows the file where I pressed the download icon and the contents of that file.

image

As you can see from the above viewer within tinyfilemanager, the contents of the file are completely different.

However, if I was to run tinyfilemanager.php directly, it works correctly. It only seems when I embed the file manager within HTML within a .php file, that it behaves wrongly. I've tried several things, but really can't get my head around the issue/solution.

mclorch commented 2 years ago

I have the same issue

londonroadhog commented 2 years ago

Pleased to see I am not alone... However, I also noticed under the same conditions, the file copy behaves incorrectly too. But when used standalone the copy is fine.

I have a suspicion is has something to do with these two lines: define('FM_EMBED', true); define('FM_SELF_URL', $_SERVER['PHP_SELF']);

My guess, and it is purely a guess, is that $_SERVER['PHP_SELF'] may not have the desired contents. I need to check this out.

Just checked and it is set to the path and name of the HTML page in use. In my case, its value was: /htmldir/test.php

mclorch commented 2 years ago

I have a unique use case I think, where I execute the script as a separate php process from a wrapper class, and pass on the output to a template. Needed to differentiate between download requests and other requests in my wrapper class, and simply echo the results instead of passing it on to the template in case of download.

londonroadhog commented 2 years ago

I have fixed the upload issue I was having, in that only one upload file was taking place. The cause of this was the define('FM_SELF_URL', $_SERVER['PHP_SELF']) statement. Because I keep the tinyfilemanager in a path different to the location in PHP_SELF, it only was uploading one file. So changing this to define('FM_SELF_URL', 'the path to where tinyfilemanager is held' . DIRECTORY_SEPARATOR . 'tinyfilemanager.php');

Then the multiple uploads started to work. However, the downloading function when embedded still shows the HTML shown on the previous post entry. I've tried several things, even trying to work my way through the PHP of the file manager for downloading. I can't seem to work out why when Embedded it doesn't work, but when used directly it does. There must be another variable that needs defining. I just can't work out what it should be. I can't be the only one with this particular scenario.

Mr Prasathmani, do you have any ideas?

londonroadhog commented 2 years ago

I have a unique use case I think, where I execute the script as a separate php process from a wrapper class, and pass on the output to a template. Needed to differentiate between download requests and other requests in my wrapper class, and simply echo the results instead of passing it on to the template in case of download.

Sounds a little different from what I am attempting. Although, there are similarities. I am using a wrapper PHP file to require the php. Just that simple fact seems to cause the download to misbehave. I've even tried setting the FM_EMBED to false, and that made no difference. I've even gone as far as commenting out both define statements, assuming that it would behave naturally, but no. Still wrong download contents. Makes very little sense to me, unless there's another variable we need to set.

londonroadhog commented 2 years ago

Now I've found another issue with setting the FM_SELF_URL to where the tinyfilemanager.php is kept. When I delete a file from the icons beside the file name, the fm_redirect fires off the tinyfilemanager.php in its own window rather than keeping it embedded. So, I can either have it open embedded with FM_SELF_URL = $_SERVER['PHP_SELF'] and have the upload only working on one file, and the deletes redirecting correctly. Or, give it the parth to the tinyfilemanager.php and have the mass uploads work, but the delete stop keeping things within the embedded php. This is getting rather silly. There has to be a simple solution.

I'd look for an alternative, but really the other filemanagers out there look crap. I can't allow this to be standalone though. It has to be embedded.

mclorch commented 2 years ago

Not sure this is related, but I found a bug in the download function, where the ContentType header is not set correctly: header('Content-Type: $contentType');

Maybe you could experiment with hard-coding the correct value and see if that makes a difference when downloading files? It's line 3063 in tinyfilemanager.php

mclorch commented 2 years ago

for me, I had to ensure that I called exit; after executing the script, though if you are using require, tinyfilemanager.php should take care of that for you. So I'd start with investigating the headers

londonroadhog commented 2 years ago

Not sure this is related, but I found a bug in the download function, where the ContentType header is not set correctly: header('Content-Type: $contentType');

Maybe you could experiment with hard-coding the correct value and see if that makes a difference when downloading files? It's line 3063 in tinyfilemanager.php

OK. So line 3063 states: header('Content-Type: $contentType'); Do you know what it should be?

londonroadhog commented 2 years ago

So for testing things out... I've temporarily added this code to the top of the fm_download_file function. if (!empty($fileName)) { // Check file is exists on given path. if (file_exists($fileLocation)) { header('Content-type: application/octet-stream'); header("Content-Type: " . mime_content_type($fileLocation)); header('Content-Disposition: attachment; filename=' . $fileName); readfile($fileLocation); echo 'File information: fileLocation = ' . $fileLocation . 'fileName = ' . $fileName; exit; } else { echo 'File does not exists on given path'; } } exit;

When I run it embeded, the downloaded file contains the actual download file, but in front of it is a bunch of HTML, which is a copy of the page html that has the tinyfilemanager.php included as a require. That last echo, outputs the contents of the $fileLocation and $fileName fields onto the end of the downloaded file. At least I can see the variable contents, which are correct. But it doesn't explain why the page HTML is also contained in the downloaded file.,

When it isn't embedded, the tinyfilemanager.php works fine for downloads. This is so frustrating!

mclorch commented 2 years ago

I'm not sure that your example code is setting the headers correctly. You can inspect the network request in your browser and see the response headers for better visibility. The code was recently updated to set the correct headers though, so you could give it a try after pulling the latest code and see if it resolves the issue for you.

londonroadhog commented 2 years ago

I'm not sure that your example code is setting the headers correctly. You can inspect the network request in your browser and see the response headers for better visibility. The code was recently updated to set the correct headers though, so you could give it a try after pulling the latest code and see if it resolves the issue for you.

I've downloaded the most recent code, and the headers are the same as the version I have. So no difference there. As for your comment to inspect the network request in the browser, I have no idea what you mean by that.

londonroadhog commented 2 years ago

@mclorch I just double checked, and I see your changes, and they are in the new version I have downloaded. However, when embedded in a webpage the downloads and view files contain the HTML of my webpage AS WELL as the contents of the downloaded/viewed file. It must be something to do with embedding within a webpage.

londonroadhog commented 2 years ago

OK, so a couple more tests, and I still don't understand quite why, but as soon as I surround the PHP with basic HTML in a .PHP file, the tinyfilemanager downloads include the HTML of the webpage.

For example:

image

It doesn't have to be much in the way of code. However, I want to give this tool to some users who will want to upload and download files between them, but within a website. So, I'll have to surround the "require" to "tinyfilemanager" within HTML for the website menu navigation, header, footer, etc. Plus of course, CSS.

If you try using the simple HTML above and try to download a text file with just one line of text in it, you will see the HTML of the page coming through. It is still driving me mad! In my case, I only see two lines of the HTML. If you place a menu and graphics within the HTML, then when just "viewing" the file, you'll see the menu and graphics appear in the viewed file.

When used standalone, the tinyfilemanager works perfectly. It is just when it is surrounded by HTML it misbehaves.