Search code examples
phpcsvdrupal-7

DRUPAL 7: Trigger Download request from Ajax call


The approach to generating and and triggering download dialog is incorrect. A dialog (download) cannot be initiated from a background process(AJAX call)

I am trying to create/download a CSV file on button click. When i simply try to create the CSV the code works fine as below:

Drupal button :

 $form['Export'] = array(
        '#type' => 'submit',
        '#value' => t('Export'),
        "#ajax" => array(
            "callback" => "export_csv",
            ),

Processing code:

 $out = fopen('filename.csv', 'w');
           //processing to create file csv
            fputcsv($out, $info, ";");
           fclose($out);

the csv file is created and stored in the root directory.

However when i try to add headers the code below fails with ajax error and no debug info

$fichier = 'inscriptions.csv';
    header( "Content-Type: text/csv;charset=utf-8" );
    header( "Content-Disposition: attachment;filename=\"$fichier\"" );
    header("Pragma: no-cache");
    header("Expires: 0");

    $out =  fopen('php://output', 'w');
    //processing to create file csv
            fputcsv($out, $info, ";");
           fclose($out);

Solution

  • As stated in @misorude comments - don't try to trigger download from background request, instead make it drupal way.

    Lest assume you have my_export_module.

    In hook_menu

    //(...)
    //export download csv
    $items['export/download-csv'] = array(
      'page callback' => 'my_export_module_download_csv',
      'delivery callback' => 'my_export_module_deliver_csv',
      'type' => MENU_CALLBACK,
    );
    

    In my_export_module_download_csv function. Assume $input is 2-dimensional array to export.

    //(...)
    //generate csv
    //open tmp stream
    $f = fopen('php://temp', 'w');
    foreach ($input as $input_line) {
      if (is_array($input_line)) {
        fputcsv($f, $input_line, $delimiter);
      }
    }
    fclose($f);
    
    return array(
      'name' => $output_file_name,
    );
    

    And in the end the my_export_module_deliver_csv function

    function my_export_module_deliver_csv($var = NULL) {
      drupal_add_http_header('Content-Encoding', 'UTF-8');
      drupal_add_http_header('Content-Type', 'application/csv;charset=UTF-8');
      if (isset($var['name'])) {
        drupal_add_http_header('Content-Disposition', 'attachment; filename="' . $var['name'] . '";');
      }
    
      if (isset($var['file'])) {
        echo $var['file'];
      }
    }
    

    This way file is not stored on server, but when entering export/download-csv it should trigger download.