I would like to ask for your help.
I'm doing a project using CodeIgniter and I need to generate Excel files besides the charts that I'm making. I am using PHPExcel to generate the Excel files.
I added the Classes folder in the third_party folder of the project.
I created a file called Excel.php in the libraries folder of the project with the codes:
<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');
require_once APPPATH."/third_party/Classes/PHPExcel.php";
class Excel extends PHPExcel {
public function __construct() {
parent::__construct();
}
}
In my view file, I used ajax to send the data and process it in the controller which is where I placed the codes for the PHPExcel. Here is my code in the view:
$("#excel").click(function(){
var fromDate = $("#fromDate").val();
var toDate = $("#toDate").val();
var dataString = "fromDate="+fromDate+"&toDate="+toDate;
$.ajax({
//url of the function
url: '<?php echo base_url(); ?>index.php/charts/excel',
//set type post
type: 'POST',
//get the data from the input field
data: dataString,
success:function(data)
{
alert(data);
}
});
});
Here is my code in the controller:
public function excel()
{
$this->load->library('Excel');
//activate worksheet number 1
$this->excel->setActiveSheetIndex(0);
//name the worksheet
$this->excel->getActiveSheet()->setTitle('Users list');
$sDate = $this->input->post('fromDate');//date_create_from_format('Y-m-d', $_POST['fromDate']);
$eDate = $this->input->post('toDate');//date_create_from_format('Y-m-d', $_POST['toDate']);
$data = $this->Charts_model->hello($sDate,$eDate);
// read data to active sheet
//print_r($data);
$row = 1;
foreach($data as $r){
$this->excel->getActiveSheet()->fromArray(array($r->emp_id, $r->emp_stat, $r->isActive, $r->dateStarted), null, 'A'.$row);
$row++;
}
$filename='just_some_random_name.xls'; //save our workbook as this file name
header('Content-Type: application/vnd.ms-excel'); //mime type
header('Content-Disposition: attachment;filename="'.$filename.'"'); //tell browser what's the file name
header('Cache-Control: max-age=0'); //no cache
//save it to Excel5 format (excel 2003 .XLS file), change this to 'Excel2007' (and adjust the filename extension, also the header mime type)
//if you want to save it as .XLSX Excel 2007 format
$objWriter = PHPExcel_IOFactory::createWriter($this->excel, 'Excel5');
//force user to download the Excel file without writing it to server's HD
$objWriter->save('php://output');
}
The controller seems to be working but, it doesnt download any excel file.
So I tried alerting the data returned by the controller and this is how it looks when alerted.
I hope you could help me out with this one. Thanks
UPDATE
The problem is solved. It turns out that it already is downloading the file. As I checked the directory, the file exists.
What I did is I added an anchor tag which is triggered if the export is successful so that it can prompt me that the file is actually downloaded and to be seen below the page.
$("#someid").trigger("click").attr("target", "_blank");
The anchor tag looks like this:
<a href="<?php echo base_url(); ?>/directoryofthefile/somename.xls" style="display: none;">
<input type="button" id="someid" value="Test" class="btn btn-success">
</a>
Extracted from php.net:
If you want the user to be prompted to save the data you are sending, such as a generated PDF file, you can use the » Content-Disposition header to supply a recommended filename and force the browser to display the save dialog.
<?php
// We'll be outputting a PDF
header('Content-Type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('original.pdf');
?>
Extrapolating that to your code, I think you're just missing the readfile()
calling. Try to add it once the file has been created.
Good Luck
Related
I want to achieve:
in a html-form put in some data (e.g. -wahl- and -id- )
after klicking -submit- call the javascript function -machExport-
this function validates the values and passes them (-wahl- and -id-) to the php-File -makeExport.php-
the -php-Funktion gets these values, gets some data from a mysql database, creates output-data,
writes these data into a file -data.txt- and download this file instantly to the users download-folder.
Everything works quite well, but:
after creating the data, this data is stored into the file but there is no downloading.
So, what's wrong.
(If I execute the -php-file directly by passing some values to the php-function, it works quite well,
so only if there ist the javascript function between the html- and the php-function, ist doesn't work )
Part of the code within my -html- document
<form name="form" action="" method="post" onsubmit="return machExport()" onreset="abbruch()">
Javascript-Code:
function machExport(){
var wahl = $("input[name='rd1']:checked").val();
var id = $("#id").val();
// verify these values and give an error message, if necessary
...
// if everything is ok, pass values to the -php- function
var ajxFile = 'makeExport.php';
var param = wahl + "#" + id;
$.ajax({
type: "POST",
url: ajxFile,
data: param
// if I put here a -success: function -statement,
// then the data having been created within my php-function
// is not beeing written into the requested file
// but is displayed in my html-document.
}
});
return false;
}
PHP-File -makeExport.php-
<?php
// get the values for -wahl- and -id-
...
// create data to write into file
$data = ...
// write data to file and download this file instantly
$file = "data.txt";
$fOK = file_put_contents ( $file , $data );
// up to here, it works
// but the next 3 lines are not excecuted
header("Content-Type: text/plain");
header("Content-Disposition: attachment; filename=\"$file\"");
readfile($file);
?>
I've seen a lot of answers of this type of questions but none worked for me. I've a CSV object which has a createCSV function like this :
public function createCSV($url, $delimiter = ","){
$file = fopen($url, 'w');
foreach ($this->content as $line) {
fputcsv($file, $line, $delimiter);
}
fclose($file);
}
And I want to download it directly from the browser so here is what I do :
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename="'.$filename.'"');
$csv_file->createCSV('php://output');
This part of code is execute with an AJAX call and even if the header is set to text/csv the download doesn't work but in the response tab I can see the content of my csv. I've tried with different header but none of them worked. How can I do to download the CSV ?
EDIT
The thing is that I don't have a URL for my CSV and I don't want to store the file somewhere, I just want to build the file and download directly with the browser
Try this code:
$('#exportcsv').click(function(){
var self = this;
$.ajax({
url : '/exportcsv',
method : 'get',
success : function(response)
{
console.log(response);
var csvData = 'data:application/csv;charset=UTF-8,' + encodeURIComponent(response);
$(self).attr({
'download': 'publisher.csv',
'href': csvData,
'target': '_blank'
});
// window.open(uri, 'test.csv');
}
})
})
I am struggling with achieving what I want and am not sure if it is possible. I am using CodeIgniter and PHP for my web application. My home view allows users to query a database and the results are generated and displayed in the table form on the page. The user will then review the table and be provided the option of downloading as an xlsx Excel file. I am using an ajax post to send the table data to my PHP controller that will create the Excel file. I also need this to work in all browsers especially Safari, as the client will access the application from Ipads as well as desktop machines.
My home ajax post: (t is the id of the generated table)
$("#btnExport").click(function() {
$.ajax({
type: "POST",
url: '<?php echo base_url();?>index.php/Home/excel',
datatype: 'html',
data: {
'queryData': $("#t").html()},
success: function (response) {
alert(response);
}
});
});
My controller function:
public function excel()
{
$this->load->library('excel');
$filename = "data";
$table = $this->input->post('queryData');
$objPHPExcel = new PHPExcel();
$tmpfile = time().'.html';
file_put_contents($tmpfile,$table);
$objReader = PHPExcel_IOFactory::createReader('HTML');
$objPHPExcel = $objReader->load($tmpfile);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename='.$filename);
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
unlink($tmpfile);
}
The problem is the handling of the ajax response I've read its impossible to download a file from ajax. Everything I have tried is not working The response is binary encoded data I am assuming is the excel file. Is there a workaround to this problem? I decided on ajax as the table can change dynamically given the current query, and needs to be sent to the server accordingly.Thanks for any assistance.
EDIT
In the linked question it is about submitting forms and not triggering a download. I am not submitting any forms, just passing an html table to the PHP to build the Excel file. I fail to see how that is relevant to my problem. Am I misunderstanding?
Submitting a form is the best you can do to trigger a file download...
It's better to create one even if you don't have a form.
var baseUrl = '<?php echo base_url();?>'
var $form = $(`<form method="post" hidden action="${baseUrl}index.php/Home/excel"><textarea name="queryData">`)
$form.find('textarea').val($("#t").html())
$form.appendTo('body').submit()
There is however one alternative to saving ajax responses and that is by creating a link with a object url from a blob response, setting the download attribute and trigger a click (in IE you need to call navigator.saveOrOpenBlob)
There is a good lib out there that is called FileSaver to abstract out all nasty vendor specifics
The way you would use it is by doing this:
fetch(url, {method: 'post', body: data})
.then(res => {
var cd = res.header.get('Content-Disposition')
var filename = cd.match(/filename="(.+)"/)[1]
return res.blob().then(blob => saveAs(blob, filename))
})
But it's not as good as submitting a form and getting a bit of help from a server that can send a Content-Disposition header cuz not all browser (safari mainly) supports download attribute in links...
there are 2 possibilities that i know
1. store the constructed table in localStorage of your browser
<div id="myTable">
<table>
<tr>
<th>A</th>
<th>B</th>
</tr>
<tr>
<td>Value for column A</td>
<td>Value for column B</td>
</tr>
</table>
</div>
// in jquery
$(document).ready(function(){
alert('nothing');
if (typeof(Storage) !== "undefined") {
// Code for localStorage/sessionStorage.
var table = $('#myTable').html();
localStorage.setItem("storedTable",table);
} else {
console.log('no support');
// Sorry! No Web Storage support..
}
});
// now you can get the table in the next page like this
var table = localStorage.getItem("storedTable");
2. solution, store them in the $_SESSION like this
session_start()
$_SESSION["myTable"] = $yourConstructedTable
redirect to that page where you want to print
get the table like so
session_start();
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$table = $_SESSION["myTable"];
unset($_SESSION["myTable"]); // don't forget to unset the session
// rest of your code
I have this PHP File called print.php:
<?php
require_once("modules/pdf/dompdf_config.inc.php");
$html = $_POST["toRender"];
$number = $_POST["number"];
$dompdf = new DOMPDF();
$dompdf->load_html($html);
$dompdf->render();
$dompdf->stream($number.".pdf");
As you can see, the HTML and a Number are received via POST.
The JavaScript file looks like this:
$("#btnViewPDF").click(function() {
var theHtml = $("#printable").html();
var theNumber = $("#invoiceNumber").val();
$.ajax({
type : "post",
url : "views/print.php",
data : {toRender : theHtml, number : theNumber},
beforeSend: function() {
$(".ajax-loader-bg").fadeIn();
}
}).always(function() {
$(".ajax-loader-bg").fadeOut();
});
return false;
});
Basically it takes all the content inside a DIV called 'printable' but what I want next is the PDF that has been generated in print.php to be displayed, I haven't been able to figure out how can I make this.
I've made it work when I generate test HTML inside print.php and then I type in the url mysite.com/print.php ... it renders the PDF and allows me to download it or see it in another browser tab.
How can I achieve this via AJAX?
You can't download something via AJAX, you could simulate the behavior using an hidden iframe.
Not that you can't download it, but, it will never end up in the filesystem for saving purpose because javascript can't do that for security reasons.
Anyway people always find solutions, you can try this: https://stackoverflow.com/a/23797348/1131176
i did achieve this, by doing just a trick, this example is made in codeigniter, so you can adapt it, first, the ajax method:
$.ajax({
url: base_url+"controladorapr/exportComprobanteIngresos", //method i called
data: $(this).serialize() //i serialized data from a form,
type:"POST",
dataType: 'JSON',
success: function (data) {
//create a link to download the pdf file
var link=document.createElement('a');
//i used the base url to target a file on mi proyect folder
link.href=window.URL = base_url+"exportacion.pdf";
//download the name with a different name given in the php method
link.download=data.nombre_archivo;
link.click();
//this js function hides the loading gif i use
hideLoad();
}
});
Now, let's head to the method on my controller:
function exportComprobanteIngresos(){
//receive your ajax data
$fecha = $this->input->post("fecha_comprobante_ingresos");
$fecha = date_format(DateTime::createFromFormat('d/m/Y', $fecha), "Y-m-d");
//send data to pdf
$data["fecha"] = $fecha;
//do some query here to send data and save it into $data[] array
//pdf size
$tamaño = 'A4';
//create a file name
$nombre_archivo = "Comprobante_ingresos".date_format(DateTime::createFromFormat('Y-m-d', $fecha), "Y_m_d").".pdf";
//load dompdf method, i will show this later, and send the data from db and file name
$pdf = $this->pdf->load_view("pdf/comprobanteIngresos", $data, $tamaño, $nombre_archivo);
//save the pdf content into the file we are downloading
file_put_contents('exportacion.pdf', $pdf);
//send data back to javascript
$data2["nombre_archivo"] = $nombre_archivo;
echo json_encode($data2);
}
now, we will include dompdf, to use dompdf on codeigniter see this answer: Codeigniter with dompdf
Now, this is the code from dompdf i use in the function '$this->pdf->load_view':
$dompdf = new Dompdf();
$html = $this->ci()->load->view($view, $data, TRUE);
$dompdf->loadHtml($html);
// (Optional) Setup the paper size and orientation
$dompdf->setPaper($size, 'portrait');
// Render the HTML as PDF
$dompdf->render();
// Output the generated PDF to variable and return it to save it into the file
$output = $dompdf->output();
return $output;
now with this, i managed to use ajax with dompdf and put a loading gif to it, and it works great, by last, the php file you load on '$this->pdf->load_view' doesn't have a header or else, is pure html and php, hope this helps!
I need to generate a PDF file with some information i get from a database, i'm using PHPExcel in order to do this, but here is the thing, when i click the button `report` so i get all the information and put it into the PDF, i get a lot of "garbage" in my page, this garbage it's like when you try to open a PDF with notepad and it just shows random symbols.
Here is how i do it
I'm using an $.ajax call to get all the information displayed into a form:
$.ajax({
// gets all the information and puts them into the form and several tables
});
Then i add an event handler to the button report so that i send the request id to a php script which will gather the necessary information to fill the report
report.on('click',function(){
$.ajax({
url : '../../php/reports/requestReport.php',
type : 'post',
data : {'idRequest' : id },
dataType : 'json',
success : function(response){
console.log(response);
},
error : function(response){
if(response.responseText != undefined)
$('body').append(response.responseText);
console.warn(response);
}
});
});
And on my php file i have something like this:
<?php
require '../functions.php';
require '../classes/PHPExcel.php';
if(isset($_POST['idRequest']))
$idRequest = $_POST['idRequest'];
else{
$idRequest = false;
echo json_encode(array("ExitCode"=>1,"Message"=>"idRequest Not Received","Location"=>"requestReport.php"));
}
if($idRequest){
try{
// get all the data
// save the request and send it to the report
$excel = new PHPExcel();
//Initializing
$excel->getProperties()->setCreator("TTMS")
->setLastModifiedBy("TTMS")
->setTitle("Request update $idRequest");
$excel->setActiveSheetIndex(0)
->setCellValue('C1', 'Request For Q.A. / Q.C. / Testing');
// Rename worksheet
$excel->getActiveSheet()->setTitle("$idRequest");
// Set active sheet index to the first sheet, so Excel opens this as the first sheet
$excel->setActiveSheetIndex(0);
// Redirect output to a client’s web browser (PDF)
header('Content-Type: application/pdf');
header('Content-Disposition: attachment;filename="Update_Request_'.$idRequest.'.pdf"');
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($excel, 'PDF');
$objWriter->save('php://output');
} catch(PDOException $ex){
echo json_encode(array("ExitCode"=>2,"Message"=>$ex->getMessage(),"Location"=>"requestReport.php PDOException"));
}
So long story short i get garbage on the page where the form is. I think it has something to do with the fact that i'm doing this via ajax but i need to do this so the echo's i have to report the errors in my code.
You're writing the PDF output inside an existing HTML page
$('body').append(response.responseText);
The browser assumes everything displayed in an HTML page is HTML markup, not a stream of binary data.
Direct the output to a new browser window if success.
Write all the output to an HTML file, then use wkhtmltopdf -> http://code.google.com/p/wkhtmltopdf/ to convert it to PDF. It works awesome!
Here is code you would use to create your html file:
if (!$handle = fopen('/path/to/folder/your_file.html', 'w')) {
die("Cannot open file for write");
}
$data_string = "<html><body></body></html>"; //all your html output goes here, formatted correctly, etc
// Write somecontent to our opened file.
if (fwrite($handle, $data_string) === FALSE) {
die("Cannot write to file");
}
Then once that is successful you convert it to PDF, then remove the old html file
// convert to PDF
$output = shell_exec('wkhtmltopdf --page-size Letter /path/to/folder/your_file.html /path/to/folder/your_file.pdf');
if (strpos($output,'Error') == false){
$output = shell_exec('rm /path/to/folder/your_file.html');
}else{
die("error creating pdf, please contact IT administrator.");
}
Now you have the PDF sitting in the location -> /path/to/folder/your_file.pdf which you can make the user download.