Search code examples
phpcodeigniterpclzip

CodeIgniter force_download not downloading file, but printing garbage characters to the console


I am trying to pull data from my database, write CSV files, zip those CSV files and then download the zip.

I have no trouble getting the files written to the server, and they look fine when I download them manually, but when I call force_download nothing happens and the ajax call has garbage in the response.

ajax response screenshot

Here is my controller code:

    public function ajax_getDataSubset() {
        if (!$this->input->post()){
            echo json_encode(array('status'=>'failed','errors'=>array('Access Mode'=>'Disallowed')));
            exit();
        }
      
        $options = $this->input->post();       
            if (isset($options['state'])) {
                $options['state']=explode(',',$options['state']);
            }
            if (isset($options['TSN'])) {
                $options['TSN']=explode(',',$options['TSN']);
            }
            if (isset($options['progList'])) {
                $options['progList']=explode(',',$options['progList']);
            }
        $programData = $this->extractor_model->get_program_data($options);    
        $plotData = $this->extractor_model->get_plot_data($options);
        $treeData = $this->extractor_model->get_tree_data($options);
      
//      make returned data into CSVs
        $programDataCSV = $this->extractor_model->data_to_csv($programData['data'], true);
        $plotDataCSV = $this->extractor_model->data_to_csv($plotData['data'], true);
        $treeDataCSV = $this->extractor_model->data_to_csv($treeData['data'], true);
        
        
        require_once(APPPATH.'libraries/pclzip/pclzip.lib.php');
        $rand=random_string('alnum',16);
        $created=FALSE;
        while (!$created){
            if(!is_dir($this->config->item('temp_path').$rand)) {
                mkdir($this->config->item('temp_path').$rand,0755);
                $dir=$this->config->item('temp_path').$rand;
                $created=TRUE;
            }
        }
        
        $programPath=$this->config->item('temp_path')."$rand/programs.csv";        
        $plotPath=$this->config->item('temp_path')."$rand/plots.csv";
        $treePath=$this->config->item('temp_path')."$rand/trees.csv";
        $zipPath=$this->config->item('temp_path')."$rand/search_results_data.zip";
        $zip= new PclZip($zipPath);  

        if ($programData['resultCount']>0){
            //open filestream for program data 
            $program_handle=fopen($programPath,'a');
            if (!$program_handle){
                show_error('could not open hand for program data');
            }
            fwrite($program_handle,$programDataCSV);
            fclose($program_handle);
            $zip->add($programPath,PCLZIP_OPT_REMOVE_PATH,$this->config->item('temp_path').$rand);
        }
        
        if ($plotData['resultCount']>0){
            //open filestream for plot data 
            $plot_handle=fopen($plotPath,'a');
            if (!$plot_handle){
                show_error('could not open hand for plot data');
            }
            fwrite($plot_handle,$plotDataCSV);
            fclose($plot_handle);
            $zip->add($plotPath,PCLZIP_OPT_REMOVE_PATH,$this->config->item('temp_path').$rand);
        }
        
        if ($treeData['resultCount']>0){
            //open filestream for tree data 
            $tree_handle=fopen($treePath,'a');
            if (!$tree_handle){
                show_error('could not open hand for tree data');
            }
            //Get each component, write it to a temp file, zip it up and then force download
            fwrite($tree_handle,$treeDataCSV);
            fclose($tree_handle);
            $zip->add($treePath,PCLZIP_OPT_REMOVE_PATH,$this->config->item('temp_path').$rand);
        }
        ob_clean(); 
        $data=file_get_contents($zipPath);
        $this->load->helper('download');
        force_download('search_results_data.zip',$data);
        echo json_encode($plotData);
    }

I also tried force_download($zipPath, NULL) but get the same response.

What am I missing??

Thank you!


Solution

  • Thanks to everyone in the comments who helped me figure it out. I moved away from using an ajax call and instead used a form. Here is the view:

    <form action='<?php echo site_url('data/downloadDataSubset');?>' method='post'><input type='hidden' name='projectIDs' id='projectIDs'>Download Standardized Datasets: <input type='hidden' name='getData' id='getData'><button class="btn btn-secondary" id='downloadDataSubset'>CSV</button></form>
    

    And then I changed the controller method name to downloadDataSubset (and removed the echo at the end), and it worked! Here is the new controller method (in the Data.php controller).

        public function downloadDataSubset() {
            if (!$this->input->post()){
                echo json_encode(array('status'=>'failed','errors'=>array('Access Mode'=>'Disallowed')));
                exit();
            }
          
            $options = $this->input->post();       
                if (isset($options['state'])) {
                    $options['state']=explode(',',$options['state']);
                }
                if (isset($options['TSN'])) {
                    $options['TSN']=explode(',',$options['TSN']);
                }
                if (isset($options['progList'])) {
                    $options['progList']=explode(',',$options['progList']);
                }
            $programData = $this->extractor_model->get_program_data($options);    
            $plotData = $this->extractor_model->get_plot_data($options);
            $treeData = $this->extractor_model->get_tree_data($options);
          
    //      make returned data into CSVs
            $programDataCSV = $this->extractor_model->data_to_csv($programData['data'], true);
            $plotDataCSV = $this->extractor_model->data_to_csv($plotData['data'], true);
            $treeDataCSV = $this->extractor_model->data_to_csv($treeData['data'], true);
            
            
            require_once(APPPATH.'libraries/pclzip/pclzip.lib.php');
            $rand=random_string('alnum',16);
            $created=FALSE;
            while (!$created){
                if(!is_dir($this->config->item('temp_path').$rand)) {
                    mkdir($this->config->item('temp_path').$rand,0755);
                    $dir=$this->config->item('temp_path').$rand;
                    $created=TRUE;
                }
            }
            
            $programPath=$this->config->item('temp_path')."$rand/programs.csv";        
            $plotPath=$this->config->item('temp_path')."$rand/plots.csv";
            $treePath=$this->config->item('temp_path')."$rand/trees.csv";
            $zipPath=$this->config->item('temp_path')."$rand/search_results_data.zip";
            $zip= new PclZip($zipPath);  
    
            if ($programData['resultCount']>0){
                //open filestream for program data 
                $program_handle=fopen($programPath,'a');
                if (!$program_handle){
                    show_error('could not open hand for program data');
                }
                fwrite($program_handle,$programDataCSV);
                fclose($program_handle);
                $zip->add($programPath,PCLZIP_OPT_REMOVE_PATH,$this->config->item('temp_path').$rand);
            }
            
            if ($plotData['resultCount']>0){
                //open filestream for plot data 
                $plot_handle=fopen($plotPath,'a');
                if (!$plot_handle){
                    show_error('could not open hand for plot data');
                }
                fwrite($plot_handle,$plotDataCSV);
                fclose($plot_handle);
                $zip->add($plotPath,PCLZIP_OPT_REMOVE_PATH,$this->config->item('temp_path').$rand);
            }
            
            if ($treeData['resultCount']>0){
                //open filestream for tree data 
                $tree_handle=fopen($treePath,'a');
                if (!$tree_handle){
                    show_error('could not open hand for tree data');
                }
                //Get each component, write it to a temp file, zip it up and then force download
                fwrite($tree_handle,$treeDataCSV);
                fclose($tree_handle);
                $zip->add($treePath,PCLZIP_OPT_REMOVE_PATH,$this->config->item('temp_path').$rand);
            }
                        $data=file_get_contents($zipPath);
                $this->load->helper('download');
                force_download('search_results_data.zip',$data);
            
        }