Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

url encoding filenames for headers 2

Status
Not open for further replies.

Leozack

MIS
Oct 25, 2002
867
0
0
GB
Hi all - it's 6am and I'm bailing with a cry for help on this one ...
I have a page that lists filenames and the directories they're in. I could set the filenames to be hyperlinks to the files, so they can be clicked or rightclick/save-as'd, but instead I make the whole table cell the filename is in a big mouseover with an onclick event of window.location=path\filename. I found I had to replace ' for %27 in the path/fname strings to avoid ruining the 'quotes'.

However, the problem with that is streamable filetypes eg mp3/wmv open instead of save, which the end user would rather have, but with the cell link method they can't rightclick/save-as.

So I've tried now pointing the table links back at the php page with path and fname GET variables that are read back in and used in a header to force a download, aka open the open/save dialog box.

This works, but the problem is now that the filename it gives you to 'save as' isn't the same as the actual filename, ie it has _ instead of spaces and such. I've tried various encoding and decoding for the link and the variable the header uses but the best I've got has spaces not _ but the ' that was encoded as %27 is shown as _' and I can't get round it. Here's the current code snippets, you can see the old window.location html cmomented out.

This is at the very top of the php page
Code:
if ($_GET['fname']) {
	//$path = urluncode($_GET['path']);
	//$fname = urluncode($_GET['fname']);
	$path = $_GET['path'];
	$fname = $_GET['fname'];
	header('Content-Type: application/octet-stream');
	header('Content-Disposition: attachment; filename='.urlrecode($fname));
	if ($path != "") { header('Content-Length: '.filesize($path.'/'.$fname)); }
	else { header('Content-Length: '.filesize($fname)); }
	//if ($path != "") { readfile($path.'/'.$fname) OR error('Error Reading File'); }
	//else { readfile($fname) OR error('Error Reading File'); }
}
function urlcode($stringname) {
	return str_replace(" ","%20",str_replace("'","%27",$stringname));
}
function urlrecode($stringname) {
	return str_replace(" ","%20",str_replace("_","%20",$stringname));
}

This is in the html tables
Code:
$showname = $filename;
$filename = $subdir.$filename;
echo "
<tr style=\"font:14px Arial\"
	onmouseover=\"bgColor='8181CC'; style.cursor='pointer'; return true\"
	onmouseout=\"bgColor=''; return true\"
	onclick=\"window.location='index.php?path=".urlcode($subdir)."&fname=".urlcode($showname)."'\">
	<!--
	onclick=\"window.location='".urlcode($filename)."'\">
	!-->
	<td style=\"color:blue\">$showname</td>
</tr>

All help appreciated guys! Of course, if there was a javascript way to prompt the save-target-as box or whatever, that'd be perfect, but there isn't afaik. If anyone has a better way than mine to do this too, shout too :p

_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);
 
Have you tried [built-in] urlencode()?



 
Naturally. First thing I did. If you try this you'll find a name such as
"this isn't a great filename" will encode fine here
Code:
onclick=\"window.location='index.php?path=".urlencode($subdir)."&fname=".urlencode($showname)."'\"
and in theory decode fine here though it makes no difference to the end result
Code:
    $fname = urldecode($_GET['fname']);
    $path = urldecode($_GET['path']);
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename='.$fname);
the save dialog still shows "this_isn_'t_a_great_filename"

:(

_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);
 
Single quote in javascript gives me errors on W2k
both IE6 and opera (not tested on moz and ff)
This:
<a href="javascript: window.navigate('%27')" ...
Gives me a javascript error "expected )".
<a href="javascript: window.navigate('\%27')" ...
or
<a href="javascript: window.navigate('\'')" ...
works.

Then there is the thing with spaces, must be on non Windows because I don't have any problem.
PHP Version 5.0.2 (XAMPP 1.4.9)

Got a problem with Mozilla and Firefox when the file contains a space.
A filename like "that's a good name.txt" was saved as
"that's" for both browsers.

Ran into a problem with magic_quotes_gpc that turns get and post values with " into \", ' into \' and \ into \\.
There might be some magic that turns spaces into underscores.

Here is some code that works for IE and opera:
Code:
<?php
		header('Content-Type: application/octet-stream');
		header('Content-Disposition: attachment; filename=' ."that's a great name.txt'");
		header('Content-Length: 2');
		print "OK";
?>


And some code using GET as filename (compare with previous to see if you're spces magically turn into underscores)
Code:
<?php
if ($_GET['fname'] != null) {
	//The PHP function stripslashes() will strip those backslashes from your string. 
	//Most likely the backslashes magically exist because the PHP directive 
	//magic_quotes_gpc is on. 
	//directive note: magic_quotes
	$fileName = stripslashes($_GET['fname']);
	header('Content-Type: application/octet-stream');
	header('Content-Disposition: attachment; filename=\'' . $fileName . "'");
	header('Content-Length: 2');
	print "oi";
} else {
	//On a w2k machine both opera and IE6 gave a javascrpt error on:
	//href="javascript: window.navigate('%27')"
	//href="javascript: window.navigate(''')"
	//the %27 is seen as a quote and gives javascrpt error, only this would work:
	//href="javascript: window.navigate('\'')"
	//So for making the href we could try to replace ' with \'
	//example works with IE6 and opera but mozilla and firefox will trim the filename to
	//that's (first space int the filename is gone) 
?>
		GET the filename <a 
			href="javascript: var win=window.open('file.php?fname=<?php echo urlencode(str_replace("'","\'","that's a great name.txt")) ?>')">
				download file
			</a>
	<?php

}
?>



Greetings, Harm Meijer
 
The fact is if I echo the variable I want to use as a filename instead of doing those headers, in plaintext you get the proper name, eg "this isn't a great filename.txt". But if I, instead of echo'ing that variable, use it in the ehader where it says filename ... well then I get "this_isn't_a_great_filename.txt". And I've spent so many hours on it over the last 2 days yet it's so simple and stupid. And now I'm tired =_= Still haven't manged it. Currently I just addslashes() to the filename I'm passing the page to use, and as I said if I echo it (maybe stripslashes first I forget) the plaintext is fine. But using it in the header is no joy ._.

_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);
 
Could be browser interpretation of the filename (browser adds underscores).

In w2k both firefox and mozilla won't accept spaces in the filename and truncate the name until the first space.
There is a large audience using these browsers on a windows platform so it might be a good idea to replace the spaces with underscores anyway.




Greetings, Harm Meijer
 
i think the problem is very simply avoided.

please change this line
Code:
header('Content-Disposition: attachment; filename='.urlrecode($fname));

to this
Code:
header('Content-Disposition: attachment; filename="'.$fname .'"');

if you surround the filename in double quotes then the relevant RFC allows you to use the extended character set, including the space. you don't need anything funky like urlencode.

note: this does not work if you use single quotes. it must be double.

try this script for example (call it test script.php)
Code:
<?
$fileName = "test script.php";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($fileName) );
readfile($fileName);
?>

hth
Justin
 
I just made a "test script.php" containing that code, called it, and on my xpsp2 ie7 setup, in the open/save box it was named "test_script.php"

:(

_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);
 
Having said this, I just checked in FF instead of IE, and it seems FF correctly accepts the variable with stripslashes() applied for the header filename and shows it as it should be "this isn't a good filename" whereas IE still accepts it with stripslashes() applied but shows it as "this_isn't_a_good_filename".

How obscure considering if I rightclick and savetargetas in IE it has no problems presenting me with a filename with spaces in. What must a guy do >_<

_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);
 
ok so the following code yields a download name of "test script.php" which is exactly how it should be, in both ie and ff.
Code:
<?
$fileName = "test script.php";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($fileName) );
readfile($fileName);
?>
I KNEW I'd managed to turn _ into spaces at 1 point, so I tried replacing " " with "%20" on the variable I'm about to shove into the name, and lo and behold, it works!!

Glad to finally get there. So it seems the moral of the story is, however you pass filenames around in php, make sure you give them to the download headers with spaces turned into %20

_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);
 
Leozack

is not the code you posted identical to that which I posted above?

you later posted that it does not work in IE7 and in my testing i have found the same).

the best i have come up with so far is as follows
Code:
<?
$fileName = "test script.php";
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE):
	$fileName = rawurlencode($fileName);
endif;
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($fileName) );
readfile($fileName);
?>
 
Appologies, what I meant to paste was
Code:
<?
$fileName = "test script.php"; // this is how you receive it
$filename = str_replace(" ","%20",$filename);
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize($fileName) );
readfile($fileName);
?>
The end result is you're turning spaces into %20 before you give it to the header, and that seems to work. Finally ;)

_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);
 
your solution doesn't work for me in firefox (after fixing the variable error). i get a file name of "test%20script.php"

adding the conditionality that i posted seems to fix the issue at least for IE6-7 and FF.
 
I stand corrected - not sure how that one got by me I'm sure it worked in both ie and ff. But the end result is now this
Code:
if ($_GET['fname']) {
	$fpath = stripslashes($_GET['fpath']);
	$fname = stripslashes($_GET['fname']);
	if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) {
		$fpath = rawurlencode($fpath);
		$fname = rawurlencode($fname);
	}
	header('Content-Type: application/octet-stream');
	header('Content-Disposition: attachment; filename="'.$fname.'"');
	if ($fpath != "") { header('Content-Length: '.filesize($fpath.'/'.$fname)); }
	else { header('Content-Length: '.filesize($fname)); }
	if ($fpath != "") { readfile($fpath.'/'.$fname) OR error('Error Reading File'); }
	else { readfile($fname) OR error('Error Reading File'); }
}

_________________________________
Leozack
Code:
MakeUniverse($infinity,1,42);
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top