在PHP中强制文件下载 - Joomla框架内 [英] Forcing file download in PHP - inside Joomla framework

查看:142
本文介绍了在PHP中强制文件下载 - Joomla框架内的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些在数据库上运行查询的PHP代码,将结果保存到csv文件,然后允许用户下载文件。问题是,csv文件包含实际csv内容的页面HTML。



我已经阅读了所有相关问题,其中包括这是一个。不幸的是,我的代码存在于Joomla中,所以即使我尝试重定向到只包含标题的页面,Joomla也会自动围绕它自己的导航代码。这仅在下载时发生;如果我查看保存在服务器上的csv文件,它不包含HTML。



任何人都可以帮助我强制下载实际的csv文件在服务器上,而不是浏览器正在编辑它呢?我尝试使用标题位置,如下所示:

  header('Location:'。$ filename); 

但它会在浏览器中打开文件,而不是强制保存对话框。



这是我现在的代码:

  //设置动态文件名
$ filename =customers.csv;
//打开文件写入csv
$ fp = fopen($ filename,'w');

//获取所有数据
$ query =select
c.firstname,c.lastname,c.email as customer_email,
a.email as address_email, c.phone as client_phone,
a.phone as address_phone,
a.company,a.address1,a.address2,a.city,a.state,a.zip,c.last_signin
从{$ dbpre}客户c
left join {$ dbpre} customers_addresses a on c.id = a.customer_id order by c.last_signin desc;

$ votes = mysql_query($ query)or die(File:。__FILE__。< br /> Line:__LINE__。< p> {$ query} p>mysql_error());
$ counter = 1;
while($ row = mysql_fetch_array($ votes,1)){
// put header row
if($ counter == 1){
$ headerRow = array() ;
foreach($ row as $ key => $ val)
$ headerRow [] = $ key;
fputcsv($ fp,$ headerRow);
}
//放数据行
fputcsv($ fp,$ row);
$ counter ++;
}

//关闭文件
fclose($ fp);

//重定向到文件
header(Content-type:application / octet-stream);
header(Content-Disposition:attachment; filename =。$ filename);
header(Content-Transfer-Encoding:binary);
readfile($ filename);
退出;

EDITS
完整的网址如下所示:

  http://mysite.com/administrator/index.php?option=com_eimcart&task=customers 

与实际的下载链接如下所示:

  http://mysite.com/administrator/index.php?option=com_eimcart&task=customers&subtask=export 

更多编辑
这是代码所在页面的镜头;生成的文件仍然在拉入子菜单的html。所选链接的代码(Export as CSV)现在是

  index.php?option = com_eimcart& task = customers& subask = export& format = raw 



现在这里是生成的保存文件的截图:





它收缩在这里的上传过程中,黄色突出显示的文本是subnav的html代码(列出客户,添加新客户,导出为csv)。这是我现在完整的代码如果我可以摆脱最后一点的HTML,那将是完美的。

  $ fp = fopen(php:/ / output,'w'); 

$ query =select c.firstname,c.lastname,c.email as customer_email,
a.email as address_email,c.phone as customer_phone,
a.phone作为address_phone,a.company,a.address1,
a.address2,a.city,a.state,a.zip,c.last_signin

从{$ dbpre}客户c
left join {$ dbpre} customers_addresses a on c.id = a.customer_id
order by c.last_signin desc;

$ votes = mysql_query($ query)or die(File:。__FILE__。< br /> Line:__LINE__。< p> {$ query} p>mysql_error());
$ counter = 1;

//重定向到文件
header(Content-type:application / octet-stream);
header(Content-Disposition:attachment; filename = customers.csv);
header(Content-Transfer-Encoding:binary);

while($ row = mysql_fetch_array($ votes,1)){

//放置标题行
if($ counter == 1){
$ headerRow = array();
foreach($ row as $ key => $ val)
$ headerRow [] = $ key;

fputcsv($ fp,$ headerRow);
}

//放数据行
fputcsv($ fp,$ row);
$ counter ++;
}

//关闭文件
fclose($ fp);

BJORN更新



这是我工作的代码(我认为)。在调用该操作的链接中使用RAW参数:

  index.php?option = com_eimcart& task = customers& subtask = export& format = raw 

由于这是程序性的,我们的链接位于一个名为customers.php的文件中,看起来像这样:

  switch($ r ['subtask']){
case'add':
case'edit':
//如果表单被提交然后去验证
include(subnav.php);
if($ r ['custFormSubmitted'] ==true)
include(validate.php);
else
include(showForm.php);
break;

case'delete':
include(subnav.php);
include(process.php);
break;

case'resetpass':
include(subnav.php);
include(resetpassword);
break;

case'export':
include(export_csv.php);
break;


默认值:
include(subnav.php);
include(list.php);
break;
}

所以当用户点击上面的链接时,export_csv.php文件是自动包含该文件包含所有实际代码:

 <? 
header(Content-type:application / octet-stream);
header(Content-Disposition:attachment; filename = customers.csv);
header(Content-Transfer-Encoding:binary);
$ fp = fopen(php:// output,'w');


//获取所有数据
$ query =select
c.firstname,c.lastname,c.email as customer_email,
a。电子邮件作为address_email,c.phone as client_phone,
a.phone as address_phone,
a.company,a.address1,a.address2,a.city,a.state,a.zip,c。来自{$ dbpre}客户的$ c

c

left join {$ dbpre} customers_addresses a on c.id = a.customer_id order by c.last_signin desc;


$ votes = mysql_query($ query)or die(File:。__FILE__。< br /> Line:__LINE__。< p> {$ query}< p>。mysql_error());
$ counter = 1;

while($ row = mysql_fetch_array($ votes,1)){

//放置标题行
if($ counter == 1){
$ headerRow = array();
foreach($ row as $ key => $ val)
$ headerRow [] = $ key;

fputcsv($ fp,$ headerRow);
}

//放数据行
fputcsv($ fp,$ row);
$ counter ++;
}

//关闭文件
fclose($ fp);


解决方案

这是一个我刚刚煮熟的示例代码以帮助你。在控制器中使用它作为一个动作方法。

  function get_csv(){
$ file = JPATH_ADMINISTRATOR。 DS。 test.csv;

//测试以确保文件存在。
如果(!file_exists($ file))死(我很抱歉,该文件似乎不存在);

//发送文件头
头(Content-type:text / csv);
header(Content-Disposition:attachment; filename = test.csv);

//发送文件内容。
readfile($ file);
}

这本身还不够,因为您下载的文件仍然包含周围的html。为了摆脱它,只收到csv文件的内容,你需要添加format = raw参数到您的请求。在我的情况下,该方法在com_csvexample组件内,所以URL将是:

  /index.php?option=com_csvexample& task = get_csv& format = raw 

编辑



为避免使用中间文件替换

  //设置动态文件名
$ filename =customers.csv;
//打开文件写入csv
$ fp = fopen($ filename,'w');

  //打开输出流写入
//这将允许在代码中使用fputcsv
$ fp = fopen(php:// output,'w');

使用此方法,您必须移动在任何东西写入输出之前发送标题的代码。您也不需要调用 readfile 函数。


I have some PHP code that runs a query on a database, saves the results to a csv file, and then allows the user to download the file. The problem is, the csv file contains page HTML around the actual csv content.

I've read all the related questions here already, including this one. Unfortunately my code exists within Joomla, so even if I try to redirect to a page that contains nothing but headers, Joomla automatically surrounds it with its own navigation code. This only happens at the time of download; if I look at the csv file that's saved on the server, it does not contain the HTML.

Can anyone help me out with a way to force a download of the actual csv file as it is on the server, rather than as the browser is editing it to be? I've tried using the header location, like this:

header('Location: ' . $filename);

but it opens the file in the browser, rather than forcing the save dialog.

Here's my current code:

//set dynamic filename
$filename = "customers.csv";
//open file to write csv
$fp = fopen($filename, 'w');

//get all data
$query = "select 
   c.firstname,c.lastname,c.email as customer_email, 
   a.email as address_email,c.phone as customer_phone,
   a.phone as address_phone,
   a.company,a.address1,a.address2,a.city,a.state,a.zip, c.last_signin
   from {$dbpre}customers c
   left  join  {$dbpre}customers_addresses a  on c.id = a.customer_id  order by c.last_signin desc";

$votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
$counter = 1;
while ($row = mysql_fetch_array($votes,1)) {
    //put header row
    if ($counter == 1){
       $headerRow = array();
       foreach ($row as $key => $val)
          $headerRow[] = $key;
       fputcsv($fp, $headerRow);
    }
    //put data row
    fputcsv($fp, $row);
    $counter++;
}

//close file
fclose($fp);

//redirect to file
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=".$filename);
header("Content-Transfer-Encoding: binary");
readfile($filename); 
exit;

EDITS Full URL looks like this:

http://mysite.com/administrator/index.php?option=com_eimcart&task=customers

with the actual download link looking like this:

http://mysite.com/administrator/index.php?option=com_eimcart&task=customers&subtask=export

MORE EDITS Here's a shot of the page that the code is on; the generated file still is pulling in the html for the submenu. The code for the selected link (Export as CSV) is now

index.php?option=com_eimcart&task=customers&subtask=export&format=raw

Now here is a screenshot of the generated, saved file:

It shrank during the upload here, but the text highlighted in yellow is the html code for the subnav (list customers, add new customer, export as csv). Here's what my complete code looks like now; if I could just get rid of that last bit of html it would be perfect.

  $fp= fopen("php://output", 'w');

            $query = "select c.firstname,c.lastname,c.email as customer_email, 
                      a.email as address_email,c.phone as customer_phone,
                      a.phone as address_phone,  a.company, a.address1,
                      a.address2,a.city,a.state,a.zip,c.last_signin

                      from {$dbpre}customers c
                      left  join  {$dbpre}customers_addresses a on c.id = a.customer_id  
                      order by c.last_signin desc";

            $votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
            $counter = 1;

            //redirect to file
            header("Content-type: application/octet-stream");
            header("Content-Disposition: attachment; filename=customers.csv");
             header("Content-Transfer-Encoding: binary");

            while ($row = mysql_fetch_array($votes,1)) {

                    //put header row
                    if ($counter == 1){
                            $headerRow = array();
                            foreach ($row as $key => $val)
                                    $headerRow[] = $key;

                            fputcsv($fp, $headerRow);
                    }

                    //put data row
                    fputcsv($fp, $row);
                $counter++;
            }

            //close file
            fclose($fp);

UPDATE FOR BJORN

Here's the code (I think) that worked for me. Use the RAW param in the link that calls the action:

index.php?option=com_eimcart&task=customers&subtask=export&format=raw

Because this was procedural, our link was in a file called customers.php, which looks like this:

switch ($r['subtask']){
    case 'add':
    case 'edit':
        //if the form is submitted then go to validation
                include("subnav.php");
        if ($r['custFormSubmitted'] == "true")
            include("validate.php");
        else
            include("showForm.php");
        break;

    case 'delete':
                include("subnav.php");
        include("process.php");
            break;

    case 'resetpass':
                include("subnav.php");
        include("resetpassword");
            break;

    case 'export':
        include("export_csv.php");
            break;


    default:
                include("subnav.php");
        include("list.php");
        break;
}

So when a user clicked on the link above, the export_csv.php file is automatically included. That file contains all the actual code:

<?
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=customers.csv");
header("Content-Transfer-Encoding: binary");
$fp= fopen("php://output", 'w');


//get all data
$query = "select 
    c.firstname,c.lastname,c.email as customer_email, 
    a.email as address_email,c.phone as customer_phone,
    a.phone as address_phone,
    a.company,a.address1,a.address2,a.city,a.state,a.zip, c.last_signin

    from {$dbpre}customers c

    left  join  {$dbpre}customers_addresses a  on c.id = a.customer_id  order by c.last_signin desc";


$votes = mysql_query($query) or die ("File: " . __FILE__ . "<br />Line: " . __LINE__ . "<p>{$query}<p>" . mysql_error());
$counter = 1;

while ($row = mysql_fetch_array($votes,1)) {

    //put header row
    if ($counter == 1){
        $headerRow = array();
        foreach ($row as $key => $val)
            $headerRow[] = $key;

        fputcsv($fp, $headerRow);
    }

    //put data row
    fputcsv($fp, $row);
    $counter++;
}

//close file
fclose($fp);

解决方案

This is a piece of sample code that I just cooked up to help you out. Use it as an action method in your controller.

function get_csv() {
        $file = JPATH_ADMINISTRATOR . DS . 'test.csv';

        // Test to ensure that the file exists.
        if(!file_exists($file)) die("I'm sorry, the file doesn't seem to exist.");

        // Send file headers
        header("Content-type: text/csv");
        header("Content-Disposition: attachment;filename=test.csv");

        // Send the file contents.
        readfile($file);
    }

This alone will not be enough, because the file you download will still contain the surrounding html. To get rid of it and only receive the csv file's contents you need to add format=raw parameter to your request. In my case the method is inside the com_csvexample component, so the url would be:

/index.php?option=com_csvexample&task=get_csv&format=raw

EDIT

In order to avoid using an intermediate file substitute

//set dynamic filename
$filename = "customers.csv";
//open file to write csv
$fp = fopen($filename, 'w');

with

//open the output stream for writing
//this will allow using fputcsv later in the code
$fp= fopen("php://output", 'w');

Using this method you have to move the code that sends headers before anything is written to the output. You also won't need the call to the readfile function.

这篇关于在PHP中强制文件下载 - Joomla框架内的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆