AnsweredAssumed Answered

Trying to understand APIs for downloading files

Question asked by Francesca Shiekh on Feb 25, 2015
Latest reply on Mar 2, 2015 by Francesca Shiekh
I am trying to unerstand APIs for downloading files.

The following API should force a download of a zip file that is located in the sugar root (per Alan @ SugarCRM TechSupport)

I am trying to understand why it's not working in on-site implementation.

if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
class downloadAttachmentsApi extends SugarApi
    public function registerApiRest()
        return array(
            'downloadAttachments' => array(
                'reqType' => 'GET',
                'path' => array('downloadAttachments'),
                'pathVars' => array(''),
                'method' => 'downloadAttachments',
                'shortHelp' => 'Testing download file api endpoint',
                'longHelp' => '',
    public function downloadAttachments($api, $args)
        $filepath = '';
            $info = array(
                'content-type' => 'application/octet-stream',
                'content-length' => filesize($filepath),
                'name' => $filepath,
                'path' => $filepath,
                'doc_type' => 'Sugar',
            );              $GLOBALS['log']->fatal(print_r($info,true));
            require_once "include/download_file.php";
            $dl = new DownloadFileApi($api);
                $dl->outputFile(true, $info);
            } catch (Exception $e) {
                throw new SugarApiExceptionNotFound($e->getMessage(), null, null, 0, $e);
        } else {
            throw new SugarApiException('File not found');

As you can see above I log the $info array and this is what the log entry looks like (using fatal just to cut down the clutter):

Wed Feb 25 14:39:14 2015 [23271][cc76f8b9-7d9b-c0fe-f34e-4e43d183458f][FATAL] Array
    [content-type] => application/octet-stream
    [content-length] => 37462
    [name] =>
    [path] =>
    [doc_type] => Sugar

The result though is an empty download. The file is downloaded with the right name and what looks like the right headers, other than for the size which as you can see is zero:

< HTTP/1.1 200 OK
< Date: Wed, 25 Feb 2015 20:34:01 GMT
* Server Apache/2.2.15 (Scientific Linux) is not blacklisted
< Server: Apache/2.2.15 (Scientific Linux)
< X-Powered-By: PHP/5.4.30
< Expires: 
< Cache-Control: max-age=0, private
< Pragma: 
< Content-Disposition: attachment; filename=""
< X-Content-Type-Options: nosniff
< ETag: d41d8cd98f00b204e9800998ecf8427e
< Content-Length: 0
< Connection: close
< Content-Type: application/octet-stream

* Closing connection 0

In the API above $dl->outputFile(true, $info); is a method in the DownloadFileApi class which is one of two classes in: include/download_file.php

the outputFile method in the DownloadFileApi sets some headers and calls  


I can find two such methods, one in ServiceBase and the other in RestService

The construct in DownloadFileApi suggests that it's using the ServiceBase

   public function __construct(ServiceBase $api)
        $this->api = $api;

but in include/api/ServiceBase.php fileResponse just returns False:

    public function fileResponse($filename)
        return false;

So what am I missing?

When/Where is the content of the file read?

I was expecting some kind of readfile($info['path']); somewhere...

Clearly I'm not understanding this.