I have an export function on my website. It exports from a MySQL result query and lets it save the file as CSV locally on user's computer.
Export functionality is almost working, except for one thing. Inside the exported and saved CSV right after all the exported MySQL data at the end the PHP script also includes the entire form's code.
Not sure why.
Export form. Let's you pick what data to export using <select>. This whole code shows up in CSV file after all data:
<div class="btn-group-vertical btn-group-lg btn-block">
<span class="glyphicon glyphicon-step-backward"></span> Back
</div>
<hr />
<?php
// show potential errors / feedback (from registration object)
if (isset($obj1)) {
if ($obj1->errors) {
foreach ($obj1->errors as $error) {
echo $error;
}
}
if ($obj1->messages) {
foreach ($obj1->messages as $message) {
echo $message;
}
}
}
?>
<form name="exportcsvform" method="post" action="admin_export.php" role="form">
<div class="form-group">
<label for="export_data" class="sr-only">Choose:</label>
<select size="1" name="export_data" id="export_data" class="input-lg">
<option value="" selected="selected" disabled>Choose</option>
<?php $obj1->getData(); ?>
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-default btn-lg" name="export" id="export"><span class="glyphicon glyphicon-save"></span>Export</button>
</div>
<hr />
</form>
The PHP function that generates the CSV. It's inside a class, let's call it Class1:
private function exportData()
{
if(isset($_POST['export_data'])){
$this->db_connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if (!$this->db_connection->set_charset("utf8")) {
$this->errors[] = $this->db_connection->error;
}
if (!$this->db_connection->connect_errno) {
$export_data_id = $_POST['export_data'];
$sql =<<<EOF
SELECT col1, col2, col3
FROM table1
JOIN table2 ON table2.col0=table1.col0
WHERE table1.col0 = $export_data_id;
EOF;
// output headers so that the file is downloaded rather than displayed
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=data.csv');
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
// output the column headings
fputcsv($output, array('col1','col2','col3'));
$query_export_data = $this->db_connection->query($sql);
$rows = array();
while($r = mysqli_fetch_assoc($query_export_data)){
$rows[] = $r;
}
// loop over the rows, outputting them
foreach ($rows as $r) fputcsv($output, $r);
}else{
// show error
}
}
}
Main PHP file that loads headers, content, footer and is also the action for the export form(admin_export.php):
<?php
// include the configs / constants for the database connection
require_once("config/db.php");
// load the login class
require_once("classes/Login.php");
// create a login object. when this object is created, it will do all login/logout stuff automatically
// so this single line handles the entire login process. in consequence, you can simply ...
$login = new Login();
// only administrators can see
if (login stuff) {
// require once classes here
require_once("classes/User.php");
$user = new User();
require_once("classes/Class1.php");
$class1 = new Class1();
include("includes/header.php");
// include views here
// include("views/admin_whatever_view.php");
include("views/admin_export_view.php");
include("includes/footer.php");
}else{
echo "<h1>Access denied</h1>";
include("views/go_back_view.php");
}
?>
Most likely it's because you need to flush the output buffer.
Here's a simple export CSV function based on an array taken from ExchangeCore blog. Looks like the only difference is the ob_* functions
public function outputCsv($fileName, $assocDataArray)
{
ob_clean();
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false);
header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename=' . $fileName);
if(isset($assocDataArray['0'])){
$fp = fopen('php://output', 'w');
fputcsv($fp, array_keys($assocDataArray['0']));
foreach($assocDataArray AS $values){
fputcsv($fp, $values);
}
fclose($fp);
}
ob_flush();
}
Related
I created a button in my TYPO3 backend
<f:link.action class="btn btn-default" action="redirectDownload"
additionalAttributes="{role: 'button'}">
<core:icon identifier="actions-system-extension-download"/>
<f:translate key="redirect_download" />
</f:link.action>
It calls the function in my controller
public function redirectDownloadAction()
{
$this->redirectRepository->getRedirects();
}
and in my repository
public function getRedirects()
{
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connectionPool
->getQueryBuilderForTable('tx_redirects');
$csvData = $queryBuilder
->select("*")
->from('tx_redirects')
->execute()
->fetchAll();
return $csvData;
}
I get the correct data and after executing the info
The technical reason is: No template was found. View could not be resolved for action "redirectDownload" in class "\Controller\RedirectController".
My question is how can I download the SQL-result in a CSV file by clicking the button? and dont get the warning.
The warning says you have no Template for this action, what is correct because you dont want to output any website.
First you should put your query results into an array, than put the array in an memory csv and sent it to the user, something like this:
$fiveMBs = 5 * 1024 * 1024;
$outputBuffer = fopen('php://temp/maxmemory:' . $fiveMBs, 'w');
foreach ($rows as $row) {
fputcsv($outputBuffer, $row, ';', '"');
}
rewind($outputBuffer);
$content = utf8_decode(stream_get_contents($outputBuffer));
header('Content-Type: text/csv');
header('Content-Length: ' . strlen($content));
header('Content-Disposition: attachment;filename="' . $filename . '.csv"');
die($content);
I am having trouble debugging a php script that I use for downloading .pdf files.
The script works fine for one user but doesn't work for another giving blank page.
What I am pretty sure is:
the part responsible for downloading works fine for both users
The query works fine and gets correct data from the serwer
All of the files are in the same directory (and as I already wrote it works perfectly for the first user)
Please give me a hint on where the bug might be or how to find it.
Thanks so much in advance.
Here's my code:
.htacces :
<Directory /faktury/>
Order deny,allow
Deny from all
</Directory>
html :
<form action="downloadfv.php" method="post">
<input type="text" name="fv" id="fv" value="$rowvariable" hidden />
<button type="submit"">Download</button>
</form>
downloadfv.php :
<?php
session_start();
if(!isset($_SESSION['zalogowany']))
{
header('Location: logowanie.php');
exit();
}
require_once "connect.php";
mysqli_report(MYSQLI_REPORT_STRICT);
$polaczenie = new mysqli($host, $db_user, $db_password, $db_name);
mysqli_query($polaczenie, "SET CHARSET utf8");
mysqli_query($polaczenie, "SET NAMES `utf8` COLLATE `utf8_polish_ci`");
if (mysqli_connect_errno())
{
echo "Could not connect to server" . mysqli_connect_error();
}
$idogloszenia = htmlspecialchars($_POST['fv'], ENT_QUOTES,'UTF-8');
$sql = "SELECT * FROM faktury WHERE user='{$_SESSION['user']}' AND idogloszenia = '$idogloszenia' ORDER BY idogloszenia DESC LIMIT 1";
$result = $polaczenie->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$file = "./faktury/".$row["nazwapdf"].".pdf";
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
}
} else {
echo " <div class='itemsname'>
<span style='padding:10px; font-size:90%'><u>No invoice available.</u></span>
</div>";
}
$polaczenie->close();
?>
The script works fine. The bug was inside my test database. It ocurred that I've had duplicated rows with similar data in them and the query selected wrong rows.
So the script can be used although as #mehdi pointed out it is not secure.
Thank you #chris85 for your hints.
I have recently made a website and have a members table in my sql. I have an admin page that has the ability to download that with column names; however I used to use INTO OUTFILE but that is not allowed on my host. I came up with this code to download the file:
if(file_exists('downloads/members_'.date("m-d-Y").'.csv') == true) {
header("Location: /downloads/members_".date("m-d-Y").".csv");
}
$output = fopen('downloads/members_'.date("m-d-Y").'.csv', 'w+');
fputcsv($output, array('memberID','username', 'password', 'email', 'active', 'resetToken', 'resetComplete', 'support', 'supportToken' ));
$rows = mysql_query("SELECT * FROM members;");
while ($row = mysql_fetch_assoc($rows)) fputcsv($output,$row);
header("Location: /downloads/members_".date("m-d-Y").".csv");
exit;
This just outputs the column names and I have never used fputcsv before and am a tad confused on what I am doing wrong. I get the file to download but not with the table in it.
[EDIT] I just tried it with a valid sql query and it does not work. updated code above. Also There is stuff in the members table.
Try this:
if (isset($_POST['download'])) {
$result = mysql_query("SELECT * FROM members", $connection);
header('Content-Type: text/csv');
header('Content-Disposition: attachment;filename=yourcsv.csv');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
$csvoutput = fopen('php://output', 'w');
$row = getRow($result);
$headers = array_keys($row);//columns from db e.g, memberID','username',...
fputcsv($csvoutput, $headers);
fputcsv($csvoutput, $row);
while ($row = getRow($result)) {
fputcsv($csvoutput, $row);
}
fclose($csvoutput);
exit;
}
Here is your getRow() function:
function getRow($res){
return mysql_fetch_assoc($res);
}
And in your html:
<input type="submit" name="download" value="Download CSV">
Here is realtime demo with sqllite3 database. Uncomment the create database and insert statement in order to see the working demo. I have tested and it is working fine. I hope this will help you.
I'm imagining a user going to page and having a download automatically initiate. The page they visit will have instructions on what to do with the file. Right now, the text of the page is being included in the csv file instead of echoing to the page. Can this even be down in one script? Here is my code...
<?php
function databaseConnection() {
$conn = new PDO("sqlsrv:server=IP ; Database=database",'user','password');
return $conn;
}
function getStudents() {
global $conn;
$studentsql =
"SQL query";
$studentquery = $conn->prepare($studentsql);
$studentquery->execute();
$studentarray = array();
while ($studentrow = $studentquery->fetch(PDO::FETCH_ASSOC)) {
$studentarray[] = $studentrow;
}
return $studentarray;
}
function createFile($fileheader,$filebody) {
$file = fopen('php://memory', 'w');
fputcsv($file, $fileheader);
foreach ($filebody as $key => $students) {
fputcsv($file, $students);
}
rewind($file);
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=data.csv');
fpassthru($file);
fclose($file);
}
$conn = databaseConnection();
$fileheader = array("header1","header2");
createFile($fileheader, getStudents());
$conn = null;
echo "<p>The file has automatically downloaded and was placed in your downloads folder.</p>
<p>Double clicking the file will automatically open it in Excel. You should then go to File | Save As <br>
and choose a different name and save it as an excel file by choosing .xlsx as the file type.";
?>
You have two options:
Display the result on the page and then redirect to the file download.
Use Javascript, load the data through an AJAX request, display it on the page and redirect to a data URI.
I'm new in PHPExcel library and this is my first experience. I'm trying to export MySQL data to Ms Excel by formatting before. I've implemented a procedure that simply formats headings of the table with bold fonts and saves them with all relevants data to the spreadsheet. However, when I run the procedure, it displays the following error:
Fatal error: Call to undefined function getRow() in C:\Xampp\htdocs\test.php on line 182
Here is the PHP code:
require_once 'PHPExcel.php';
require_once 'PHPExcel/IOFactory.php';
require_once 'PHPExcel/Writer/Excel2007.php';
// create mysql query
$query_export = "SELECT * FROM `table1` ORDER BY `date` ASC";
// execute query
$result = mysqli_query($GLOBALS['mysqli'], $query_export) or die ("<b>Couldn't execute SQL query:</b> " . mysqli_error($GLOBALS['mysqli']));
try {
$sheet = new PHPExcel();
// set metadata
$sheet->getProperties()->setCreator('www.example.com')
->setLastModifiedBy('www.example.com')
->setTitle('Report on Table')
->setKeywords('report tables etc.');
// set default settings
$sheet->getDefaultStyle()->getAlignment()->setVertical(
PHPExcel_Style_Alignment::VERTICAL_TOP);
$sheet->getDefaultStyle()->getAlignment()->setHorizontal(
PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$sheet->getDefaultStyle()->getFont()->setName('Calibri');
$sheet->getDefaultStyle()->getFont()->setSize(12);
// get reference to active spreadsheet in workbook
$sheet->setActiveSheetIndex(0);
$activeSheet = $sheet->getActiveSheet();
// populate with data
$row = getRow($result); // line 182
$colHeaders = array_keys($row);
$col = 'A';
$rownum = 1;
// set column headings
foreach ($colHeaders as $header) {
$activeSheet->setCellValue($col . $rownum, $header);
$activeSheet->getStyle($col . $rownum)->getFont()->setBold(true);
$activeSheet->getColumnDimension($col)->setAutoSize(true);
$col++;
}
// populate individual cells with data
do {
$col = 'A';
$rownum++;
foreach ($row as $value) {
$activeSheet->setCellValue($col++ . $rownum, $value);
}
} while ($row = getRow($result));
// setting headers
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename=Export.xlsx');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
$writer = PHPExcel_IOFactory::createWriter($sheet, 'Excel2007');
$writer->save('php://output');
exit();
} catch (Exception $e) {
$error = $e->getMessage();
}
// display error
if (isset($error)) {
echo "<p>" .$error. "</p>";
}
// free resultset
mysqli_free_result($result);
// close db connection
$GLOBALS['mysqli']->close();
exit();
Any help is appreciated.
UPDATE
The following tutorial is used to create above mentioned code:
http://www.youtube.com/watch?v=L6MQQvBi-ks
I believe you need to define getRow or use something like this:
http://php.net/manual/en/mysqli-result.fetch-row.php