<p>There might be a way to do this with <code>CBaseController::renderFile()</code>, but I'd just use <a href="https://craftcms.com/classreference/services/HttpRequestService#sendFile-detail" rel="nofollow"><code>craft()-&gt;request-&gt;sendFile()</code></a>.</p>

<p>The 3rd parameter is an optional <code>$options</code> array and you can pass a <code>'forceDownload' =&gt; true</code> as one of the key => value pairs to force it to download to the browser.</p>

<p>Instead of hardcoding the the path to your public assets folder, you can do something like:</p>

<pre><code>$path = IOHelper::getFolderName(craft()-&gt;request-&gt;getScriptFile());
</code></pre>

<p>That should get you the path to the folder your public <code>index.php</code> file is executing in and you can tack on your public asset path from there.</p>

CC BY-SA 3.0
2016-05-11T02:23:19.483Z
2016-05-11T02:23:19.483Z
Brad Bell
<p>I have a controller which fetches an asset from an entry (this is the service method that provides the asset):</p>

<pre><code>public function findPoster($entryId) {
    $criteria = craft()-&gt;elements-&gt;getCriteria(ElementType::Entry);
    $criteria-&gt;id = $entryId;

    $entry = $criteria-&gt;first();

    if ($entry) {
        if ($entry-&gt;downloadItem) {
            return $entry-&gt;downloadItem-&gt;first();
        }
    }

    return null;
}
</code></pre>

<p>That works great, however now I need to send the asset to the browser. Having a little poke around in the method listing I see there is a <code>CBaseController::renderFile()</code> which sounds to be what I need, however I can't work out the correct way to build a path to the file. Accessing <code>$url</code> from the asset I've fetched returns a public relative path but obviously I need the path on the filesystem.</p>

<hr>

<p>So far I've got this working:</p>

<pre><code>$name = strtolower($asset-&gt;title) . '.' . $asset-&gt;extension;

header('Content-Type: ' . $asset-&gt;getMimeType());
header('Content-Disposition: attachment; filename=' . $name);

$path = realpath(craft()-&gt;basePath . '/../../public/' . $asset-&gt;url);

die(file_get_contents($path));
</code></pre>

<p>However this is far from ideal because:</p>

<ul>
<li>I have to hardcode the <code>public</code> directory which isn't the case at any other point in Craft, so it feels really dirty.</li>
<li>Manually setting the headers seems like something a controller method would be able to take care of properly.</li>
</ul>

<plugin-development><assets><controller><assetfilemodel>
Send an asset from a plugin controller
# Send an asset from a plugin controller

(Asked by: username_0 on 2016-05-11)

I have a controller which fetches an asset from an entry (this is the service method that provides the asset):
public function findPoster($entryId) {
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->id = $entryId;

    $entry = $criteria->first();

    if ($entry) {
        if ($entry->downloadItem) {
            return $entry->downloadItem->first();
        }
    }

    return null;
}

That works great, however now I need to send the asset to the browser. Having a little poke around in the method listing I see there is a CBaseController::renderFile() which sounds to be what I need, however I can't work out the correct way to build a path to the file. Accessing $url from the asset I've fetched returns a public relative path but obviously I need the path on the filesystem.

So far I've got this working:
$name = strtolower($asset->title) . '.' . $asset->extension;

header('Content-Type: ' . $asset->getMimeType());
header('Content-Disposition: attachment; filename=' . $name);

$path = realpath(craft()->basePath . '/../../public/' . $asset->url);

die(file_get_contents($path));

However this is far from ideal because:

I have to hardcode the public directory which isn't the case at any other point in Craft, so it feels really dirty.
Manually setting the headers seems like something a controller method would be able to take care of properly.

**Tags:** plugin-development, assets, controller, assetfilemodel


---

## 1 answers

### Answer by username_1 on 2016-05-11. Score: 2 | Accepted answer

There might be a way to do this with CBaseController::renderFile(), but I'd just use craft()->request->sendFile().
The 3rd parameter is an optional $options array and you can pass a 'forceDownload' => true as one of the key => value pairs to force it to download to the browser.
Instead of hardcoding the the path to your public assets folder, you can do something like:
$path = IOHelper::getFolderName(craft()->request->getScriptFile());

That should get you the path to the folder your public index.php file is executing in and you can tack on your public asset path from there.


---

