如何在WordPress后端强制下载文件?

时间:2010-10-31 作者:Dave Morris

我想在我的一个WordPress插件中添加一个“点击下载”按钮,但我不确定要使用哪个钩子。到目前为止,将“admin\\u init”挂接到此代码似乎是可行的:

 header("Content-type: application/x-msdownload");
 header("Content-Disposition: attachment; filename=data.csv");
 header("Pragma: no-cache");
 header("Expires: 0");
 echo \'data\';
 exit();
这似乎可行,但我只是想看看是否有最佳实践。

谢谢Dave

3 个回复
最合适的回答,由SO网友:MikeSchinkel 整理而成

如果我没弄错你想a URL something like the following 其对浏览器的响应将是您生成的内容,即.CSV 文件,但没有从WordPress生成内容?

http://example.com/download/data.csv
我想你在找\'template_redirect\' 钩你可以找到\'template_redirect\' 在里面/wp-includes/template-loader.php 这是所有WordPress开发人员都应该熟悉的文件;它短而甜,路由每一个非管理页面加载,所以一定要看看它。

只需在主题中添加以下内容functions.php 文件或在您include 在里面functions.php:

add_action(\'template_redirect\',\'yoursite_template_redirect\');
function yoursite_template_redirect() {
  if ($_SERVER[\'REQUEST_URI\']==\'/downloads/data.csv\') {
    header("Content-type: application/x-msdownload",true,200);
    header("Content-Disposition: attachment; filename=data.csv");
    header("Pragma: no-cache");
    header("Expires: 0");
    echo \'data\';
    exit();
  }
}
注意测试\'/downloads/data.csv\' 通过检查URL$_SERVER[\'REQUEST_URI\']. 另请注意添加的,true,200 到您的header() 在设置的位置调用Content-type; 这是因为WordPress将设置404 “参考资料”;“未找到”状态代码,因为它无法识别URL。不过没问题,因为true 说明header() 更换404 WordPress已设置并使用HTTP200 “参考资料”;“好的”状态代码。

以下是FireFox中的外观(Note 屏幕截图没有/downloads/ 虚拟目录,因为在截图和注释之后,添加一个\'/downloads/\' 虚拟目录):

Screenshot of a download URL for a CSV filemikeschinkel.com)

如果希望从前缀为的URL处理下载,请更新/wp-admin/ 要向用户提供受登录保护的视觉指示,您也可以这样做;下面介绍一种方法。

这次我封装到一个类中,名为DownloadCSV, 并创建一个用户;“能力”已调用\'download_csv\' 对于\'administrator\' 角色(了解角色和功能here)您可以从预定义的\'export\' 角色(如果愿意),如果愿意,只需搜索(&A);代替\'download_csv\' 具有\'export\' 并移除register_activation_hook() 电话和activate() 作用顺便说一下,对激活挂钩的需要是我将其移动到插件而不是保留在主题中的原因之Screenshot of Downloading a file by URL from an option of the WordPress admin\'s Tools menu八 文件*

我还添加了一个;下载CSV“菜单选项关闭;“工具”菜单使用add_submenu_page() 并将其链接到\'download_csv\' 能力。

最后我选择了\'plugins_loaded\' 钩子,因为这是我能用的最早的合适的钩子。你可以使用\'admin_init\' 但是这个钩子运行的时间要晚得多(第1130次钩子调用与第3次钩子调用),那么为什么让WordPress做更多的一次性工作呢(我使用Instrument Hooks plugin 找出要使用的挂钩。)

在钩子中,我检查以确保我的URL以/wp-admin/tools.php 通过检查$pagenow 变量,我验证current_user_can(\'download_csv\') 如果通过了,我会测试$_GET[\'download\'] 查看是否包含data.csv; 如果是,我们运行的代码实际上与以前相同。我还删除了,true,200 从呼叫到header() 在前面的示例中,因为WordPress知道这是一个好的URL,所以还没有设置404状态。下面是您的代码:

<?php
/*
Plugin Name: Download CSV
Author: Mike Schinkel
Author URI: http://mikeschinkel.com
 */
if (!class_exists(\'DownloadCSV\')) {
  class DownloadCSV {
    static function on_load() {
      add_action(\'plugins_loaded\',array(__CLASS__,\'plugins_loaded\'));
      add_action(\'admin_menu\',array(__CLASS__,\'admin_menu\'));
      register_activation_hook(__FILE__,array(__CLASS__,\'activate\'));
    }
    static function activate() {
      $role = get_role(\'administrator\');
      $role->add_cap(\'download_csv\');
    }
    static function admin_menu() {
      add_submenu_page(\'tools.php\',    // Parent Menu
        \'Download CSV\',                // Page Title
        \'Download CSV\',                // Menu Option Label
        \'download_csv\',                // Capability
        \'tools.php?download=data.csv\');// Option URL relative to /wp-admin/
    }
    static function plugins_loaded() {
      global $pagenow;
      if ($pagenow==\'tools.php\' && 
          current_user_can(\'download_csv\') && 
          isset($_GET[\'download\'])  && 
          $_GET[\'download\']==\'data.csv\') {
        header("Content-type: application/x-msdownload");
        header("Content-Disposition: attachment; filename=data.csv");
        header("Pragma: no-cache");
        header("Expires: 0");
        echo \'data\';
        exit();
      }
    }
  }
  DownloadCSV::on_load();
}
下面是激活插件的屏幕截图:Screenshot of Plugin Page showing an activated pluginmikeschinkel.com)

最后,这里是触发下载的屏幕截图:Screenshot of Downloading a file by URL from an option of the WordPress admin\'s Tools menumikeschinkel.com)

SO网友:Developer

另一个用于导出到CSV的有用插件。可能对某些人有用

<?php

class CSVExport
{
    /**
    * Constructor
    */
    public function __construct()
    {
        if(isset($_GET[\'download_report\']))
        {
            $csv = $this->generate_csv();

            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: application/octet-stream");
            header("Content-Disposition: attachment; filename=\\"report.csv\\";" );
            header("Content-Transfer-Encoding: binary");

            echo $csv;
            exit;
        }

        // Add extra menu items for admins
        add_action(\'admin_menu\', array($this, \'admin_menu\'));

        // Create end-points
        add_filter(\'query_vars\', array($this, \'query_vars\'));
        add_action(\'parse_request\', array($this, \'parse_request\'));
    }

    /**
    * Add extra menu items for admins
    */
    public function admin_menu()
    {
        add_menu_page(\'Download Report\', \'Download Report\', \'manage_options\', \'download_report\', array($this, \'download_report\'));
    }

    /**
    * Allow for custom query variables
    */
    public function query_vars($query_vars)
    {
        $query_vars[] = \'download_report\';
        return $query_vars;
    }

    /**
    * Parse the request
    */
    public function parse_request(&$wp)
    {
        if(array_key_exists(\'download_report\', $wp->query_vars))
        {
            $this->download_report();
            exit;
        }
    }

    /**
    * Download report
    */
    public function download_report()
    {
        echo \'<div class="wrap">\';
        echo \'<div id="icon-tools" class="icon32">
        </div>\';
        echo \'<h2>Download Report</h2>\';
        //$url = site_url();

        echo \'<p>Export the Users\';
    }

    /**
    * Converting data to CSV
    */
    public function generate_csv()
    {
    $csv_output = \'\';
    $table = \'users\';

    $result = mysql_query("SHOW COLUMNS FROM ".$table."");

    $i = 0;
    if (mysql_num_rows($result) > 0) {
        while ($row = mysql_fetch_assoc($result)) {
            $csv_output = $csv_output . $row[\'Field\'].",";
            $i++;
        }
    }
    $csv_output .= "\\n";

    $values = mysql_query("SELECT * FROM ".$table."");
    while ($rowr = mysql_fetch_row($values)) {
        for ($j=0;$j<$i;$j++) {
            $csv_output .= $rowr[$j].",";
        }
        $csv_output .= "\\n";
    }

    return $csv_output;
    }
}

// Instantiate a singleton of this plugin
$csvExport = new CSVExport();

SO网友:Joko Wandiro

admin_init 挂钩或load-(page) 钩子似乎起作用了,WordPress还没有设置此状态的标题。我在用load-(page) 钩子,因为它在加载管理菜单页时运行。您可以加载特定页面的脚本。

您可以检查load-(page) Hook on WordPress Codex

如果你正在使用admin_init 挂钩确保verify nonce 使用check_admin_referer 或者其他脚本可能会通过条件将您的下载文件输出。

结束

相关推荐

How do you debug plugins?

我对插件创作还很陌生,调试也很困难。我用了很多echo,它又脏又丑。我确信有更好的方法可以做到这一点,也许是一个带有调试器的IDE,我可以在其中运行整个站点,包括插件?