Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

[solved] force file download


Go to End


10 Posts   6789 Views

Avatar
ekersten

Community Member, 16 Posts

17 February 2011 at 3:52am

I have a controller method that is supposed to force-download an asset uploaded via backend. The method recieves the ID of such asset and uses SS_HTTPRequest.

The problem is that although i can directly access the asset in the template via $File.URL I can't read it via php because file_exists says $File.URL does not exists.

This is the method source

public function download(){

	$assetID = $this->request->param('ID');

	$do = DataObject::get_by_id('File', $assetID);
	
	if($do && file_exists($do->URL)){
	    return SS_HTTPRequest::send_file(file_get_contents($do->URL), $do->Name);
	}else{
	    echo 'error with ' . $do->URL . ' (' . file_exists($do->URL) . ')';
	    return false;
	}

    }

Am I missing something here?
Thanks in advance

Avatar
ekersten

Community Member, 16 Posts

17 February 2011 at 4:04am

Edited: 17/02/2011 4:06am

After an our of trying i solved it with this piece of code

public function download(){

	$assetID = $this->request->param('ID');

	$do = DataObject::get_by_id('File', $assetID);
	
	if($do){
	    return SS_HTTPRequest::send_file(file_get_contents(Director::absoluteBaseURL() . $do->Filename), $do->Name);
	}else{
	    return false;
	}

    }

Seems the combination "Director::absoluteBaseURL() . $do->Filename" did the trick.

Still I would like to know if this was the best approach for the situation

Avatar
zenmonkey

Community Member, 545 Posts

17 February 2011 at 10:28am

Its a decent method. The only other thing I've ever done is manually build the whole response header when pushing a temporary zip file to the browser, which is even messy-er :)

Avatar
pac

Community Member, 25 Posts

30 September 2011 at 1:13am

looks nice but I can't seem to find how to use it in template. can you help ?

Avatar
zenmonkey

Community Member, 545 Posts

30 September 2011 at 2:22am

In a template you use $File.Filename to get the path of File. $File.Title will return the name of the file with the dashes converted to spaces. So my-filename becomes "my filename". and $File.Name will return the system filename with dashes

Avatar
ekersten

Community Member, 16 Posts

30 September 2011 at 2:26am

In the particular case of the project I was developing, the part of the template that used the controller method on the template looked like this

<% control Songs %>
	<li>
	    <span class="title bodoni">{$Pos}. $Title</span>
	    <a href="$Top.Link(download)/$SongFile.ID" title="$Title.XML">Download</a>
	</li>
<% end_control %>

I hope this helps.

Avatar
zenmonkey

Community Member, 545 Posts

30 September 2011 at 2:31am

What does the Dataobject look like? You're calling $Top but you didn't include the parent control. $Top temporarily breaks you out of the $Songs control loop

Avatar
ekersten

Community Member, 16 Posts

30 September 2011 at 2:36am

That's right, it DOES break you out of the $Songs control loop, but that's the whole point since the method I defined is in the controller and not in the model, using $Link inside the $Songs control loop would only give me the link to the current song being listed.

Instead, with $Top, I get the link to the current page and its "download" method, passing also the current $SongFile.ID.

Go to Top