PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Thursday, August 18, 2022

[FIXED] How can I have a header('Location: ') in the same page as a csv file creation and output or create this csv file in an html based page?

 August 18, 2022     csv, html, output, php     No comments   

Issue

My app collects data using a series of forms, then this data is sent and processed using external API's. You can think of the structure as form>processingForm.php>form2>processingForm2.php ...

After all the info needed has been collected and the app is located at the last processing/sending page I faced an issue. Since there can't be any data output before a header('Location: ') I found myself trapped forever in that processing, htmless page with the csv being correctly downloaded. So I had my file but at the price of not being able to continue the process.

I thought about storing the values I needed to write onto the csv inside $_SESSION in order to retrieve them at the last page of the project, so it would not interfere with other outputs, but when I tried for the first time I saw that the page's html did not appear. This was of course produced due to php being loaded first, so the csv would be created and the page left completely blank.

How can I solve this issue? I want my csv file as well as any html at least as a last page. I would redirect directly to the start again and forget about that last page, but I also can't. The only thing I know would work is leaving that empty page even without a mere button to go back to the start. I guess there must be some kind of workaround to this.

I've also tried printing the last page using php -> Same thing happened since I was outputing the page as a whole. I have error reporting enabled.

This is that final page I've been talking about but once again it's not necessary, a way to simply redirect after the csv has been downloaded would be fine too.

<?php 
session_start(); 

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

if (!isset($_SESSION['logged']) || empty($_SESSION['logged']) || $_SESSION['logged'] != 1) {
    header('Location: url');
}



$arrayCsv = $_SESSION['arrayCsv'];

$filename = $_SESSION['companyName'];
$filename = strtolower(str_replace(' ', '', $filename)); 
$filename = $filename.'.csv';

header('Content-Type: application/csv'); 
header("Content-Disposition: attachment; filename=$filename"); 


$fp = fopen("php://output", 'w');
$delimiter = ',';
$enclosure = '"';
$escape_char = "\\";


foreach ($arrayCsv as $customerCsv) {
    
    fputcsv($fp, $customerCsv, $delimiter, $enclosure, $escape_char);
}


fclose($fp);
?>


<!DOCTYPE html>
<html lang="es">
<head>
    <title>Fin</title>
    <meta charset="utf-8">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" href="../style/homeStyleSheet.css">
</head>
<body>
    <!--NAVBAR-->
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <a class="navbar-brand" href="../index.php"><img id="ubunetLogo" src="../img/logo-color.svg"></a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>

      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item active">
            <a class="nav-link" href="../index.php">Inicio<span class="sr-only">(current)</span></a>
          </li>
          <li class="nav-item active">
            <a class="nav-link" href="./createContact.php">Crear<span class="sr-only">(current)</span></a>
          </li>
          <li class="nav-item active">
            <a class="nav-link" href="#">Actualizar<span class="sr-only">(current)</span></a>
          </li>
          <li class="nav-item active">
            <a class="nav-link" href="#">Eliminar<span class="sr-only">(current)</span></a>
          </li>
        </ul>
      </div>
    </nav>

    <!--BODY-->
    <div id="finalPageContainer">
        <div class="row">
            <a href="../pages/createContact.php"></a>
            <p  id="finalPageP">Todos los datos se han insertado con éxito. Volver a crear contacto.</p>
        </div>
    </div>


    <footer id="sticky-footer2" class="py-4">
        <div class="container text-center">
          <small>Copyright &copy; Ubunet</small>
        </div>
    </footer>
</body>
</html>

Solution

As @cBroe suggested in the comments, I was trying to obtain two different resources in one request. Those resources being:

  1. The csv file.
  2. The HTML/New page

This is not possible, so in order to trick the app a little bit I created a link in the final page that takes you to the same page with a variable to discern wether to download the csv or just show the view. This way the body now looks like this:

<!--BODY-->
    <button id="finalPageContainer" onclick="location.href='http://10.200.210.61/index.php'" type="button">Todos los datos se han insertado correctamente. ¡Volver a inicio!</button>

    <div id="finalPageContainer2">
        <a id="getCsvLink" href="http://10.200.210.61/views/finalPage.php?getCsv=1">Obtener CSV</a>
    </div>


    <footer id="sticky-footer2" class="py-4">
        <div class="container text-center">
          <small>Copyright &copy; Ubunet</small>
        </div>
    </footer>

This is also possible by adding this code at the beginning:

session_start(); 

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

if (!isset($_SESSION['logged']) || empty($_SESSION['logged']) || $_SESSION['logged'] != 1) {
    header('Location: '.$url);
}


if (isset($_GET['getCsv']) && $_GET['getCsv'] == 1) {
    $arrayCsv = $_SESSION['arrayCsv'];

    $filename = $_SESSION['companyName'];
    $filename = strtolower(str_replace(' ', '', $filename)); 
    $filename = $filename.'.csv';

    header('Content-Type: application/csv'); 
    header("Content-Disposition: attachment; filename=$filename"); 


    $fp = fopen("php://output", 'w');
    $delimiter = ',';
    $enclosure = '"';
    $escape_char = "\\";


    foreach ($arrayCsv as $customerCsv) {
        fputcsv($fp, $customerCsv, $delimiter, $enclosure, $escape_char);
    }


    fclose($fp);

    die();
}

The die() at the end is very important for it prevents the html from leaking to the csv file, so the only thing written onto it are the values I need.



Answered By - Berny
Answer Checked By - David Goodson (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing