Take the 2-minute tour ×
Craft CMS Stack Exchange is a question and answer site for administrators, end users, developers and designers for Craft CMS. It's 100% free, no registration required.

I have created a plugin that takes a form post, retrieves an asset id and am trying to have the browser start the download process. Is this possible if using a third party source like AmazonS3? If so what may be wrong with this plugin controller method?

public function actionDownloadAsset()
{
    $this->requirePostRequest();
    $id = craft()->request->getRequiredPost("id");

    $attributes = array('id' => $id);
    $element = craft()->elements->getCriteria(ElementType::Asset)->limit(1)->find($attributes);

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename='.basename($element->filename));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . $element->filesize);
    readfile($element->url);
}

Everytime I try the plugin from front end I get a page not found. I have made sure the from is posting to the controller method.

share|improve this question

2 Answers 2

If you're getting a Craft 404, then it sounds like it's not even making it to your controller's action.

Likely, you haven't allowed anonymous access to your controller globally or that action in particular.

share|improve this answer
    
I added "allowed anonymous access" to the controller. If I add a Dump and Exit it gets as far as the element. It doesn't give a Craft 404 just "This webpage is not available". –  aran Aug 11 at 23:01
    
Check either your Apache error logs or craft/storage/runtime/logs/phperrors.log and see if any fatal errors are getting logged. –  Brad Bell Aug 11 at 23:05
    
No errors in either logs. In my code above am I getting the specific asset properly? –  aran Aug 12 at 2:44
    
Yeah, that should work fine. Check the response in your browser's console? –  Brad Bell Aug 12 at 3:25
up vote 2 down vote accepted

I have found a solution.

public function actionDownloadAsset()
{
  $this->requirePostRequest();
  $id = craft()->request->getRequiredPost("id");
  $attributes = array('id' => $id);
  $element = craft()->elements->getCriteria(ElementType::Asset)->first($attributes);


  $file = $entry->url;
  $name = $entry->filename;

  header('Content-Description: File Transfer');
  header('Content-Type: application/octet-stream');
  header('Content-Disposition: attachment; filename='.basename($name));
  header('Content-Transfer-Encoding: binary');
  header('Expires: 0');
  header('Cache-Control: must-revalidate');
  header('Pragma: public');

  readfile($file);
}

To get access to the file url I had to array_shift the $element returned from getCriteria. Then I had to exclude the file size header. This was ultimately causing the "this webpage is not available". Not sure the reason.

header('Content-Length: ' . filesize($entry->size))

share|improve this answer
    
My only concern is, could I run into memory issues for the file being downloaded? –  aran Aug 12 at 3:34
1  
Oh, right. You won't need the array_shift, if you change it to $element = craft()->elements->getCriteria(ElementType::Asset)->first($attributes); Not sure what's going on with the header size. –  Brad Bell Aug 12 at 16:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.