0

I know one should not use echo in controllers, but I don't understand what I should use to return an xml in order to download it. Please note, it's not a file on the server, it's just a string:

public function export()
{
    $this->autoRender = false;

    $id = $this->request->getQuery('id');
    $invoice = $this->Invoices->get($id, ['contain' => ['Customers', 'ItemInvoices' => ['ItemProformas' => ['ItemDeliveryNotes' => ['ItemOrders' => ['Orders' => ['Customers']]]]]]]);

    $fpr = new ExportInvoice();
    $fpr->SetInvoice($invoice);

    header('Content-type: text/xml');
    header('Content-Disposition: attachment; filename="' . $fpr->getFilename() . '"');

    $xml = $fpr->asXML();
    echo $xml;
}

it actually works as expected: the browser download a file with the given filename and its content is the $xml value.

But at the end of the file there are warnings about headers:

Warning (512): Unable to emit headers. Headers sent in file=/home/mark/myproject/src/Controller/InvoicesController.php line=130 [CORE/src/Http/ResponseEmitter.php, line 51]
Warning (2): Cannot modify header information - headers already sent by (output started at /home/mark/myproject/src/Controller/InvoicesController.php:130) [CORE/src/Http/ResponseEmitter.php, line 152]
Warning (2): Cannot modify header information - headers already sent by (output started at /home/mark/myproject/src/Controller/InvoicesController.php:130) [CORE/src/Http/ResponseEmitter.php, line 181]
Warning (2): Cannot modify header information - headers already sent by (output started at /home/mark/myproject/src/Controller/InvoicesController.php:130) [CORE/src/Http/ResponseEmitter.php, line 181]

As far as I know this is due to the usage of echo in controller. It may happens there's an output before sending the header, and then the warnings.

What's the correct way to replace the echo function?

tereško
  • 58,060
  • 25
  • 98
  • 150
Mark
  • 4,338
  • 7
  • 58
  • 120

2 Answers2

4

Prior to the docs , you can use the framework for that , checkout how to Sending a String as File

public function export()
{
    $this->autoRender = false;

    $id = $this->request->getQuery('id');
    $invoice = $this->Invoices->get($id, ['contain' => ['Customers', 'ItemInvoices' => ['ItemProformas' => ['ItemDeliveryNotes' => ['ItemOrders' => ['Orders' => ['Customers']]]]]]]);

    $fpr = new ExportInvoice();
    $fpr->SetInvoice($invoice);

    // header('Content-type: text/xml');
    // header('Content-Disposition: attachment; filename="' . $fpr->getFilename() . '"');

    $xml = $fpr->asXML();
    $response = $this->response;
    $response = $response->withStringBody($xml);
    // use $response->body($xml); for versions before 3.4.0
    $response = $response->withType('xml');
    $response = $response->withDownload($fpr->getFilename());
    return $response;
}
hassan
  • 7,812
  • 2
  • 25
  • 36
-1

Just use die() or exit()

public function export()
{
    $this->autoRender = false;

    $id = $this->request->getQuery('id');
    $invoice = $this->Invoices->get($id, ['contain' => ['Customers', 'ItemInvoices' => ['ItemProformas' => ['ItemDeliveryNotes' => ['ItemOrders' => ['Orders' => ['Customers']]]]]]]);

    $fpr = new ExportInvoice();
    $fpr->SetInvoice($invoice);

    if (!headers_sent())
    {
        header('Content-type: text/xml');
        header('Content-Disposition: attachment; filename="' . $fpr->getFilename() . '"');
    }
    else
    {
        //Do something else to let them know they can't expect a file
        die();
    }

    die($fpr->asXML());
}

Update

Regarding the comment

Using return, exit or die is already explained in detail in this question php-exit-or-return-which-is-better, what-are-the-differences-in-die-and-exit-in-php

Community
  • 1
  • 1
Maximilian Fixl
  • 670
  • 6
  • 23
  • There are so many ways to the same thing! Is there any advantages to use one instead of others? – Mark Jan 08 '20 at 08:38
  • 1
    You should never use die() or exit(). It is one of the worst code smells and makes testing this impossible. Use instead resposne object as documented (and as shown below in a different and more correct answer. – mark Jan 08 '20 at 15:02
  • @mark I'm very thankful for your comment. Good to have learned something again! – Maximilian Fixl Jan 08 '20 at 15:16
  • note from moderator: if your answer is wrong, just delete it, don't copy others to make it better. – Jean-François Fabre Jan 11 '20 at 09:28
  • @Jean-FrançoisFabre I just tried to make an accepted answer correct and more useful. Sorry, now I know it for the next time. – Maximilian Fixl Jan 11 '20 at 09:36