ฉันจะบังคับให้ดาวน์โหลดไฟล์ในแบ็กเอนด์ WordPress ได้อย่างไร


30

ฉันต้องการเพิ่มปุ่ม "คลิกเพื่อดาวน์โหลด" ลงในหนึ่งในปลั๊กอิน WordPress ของฉันและฉันไม่แน่ใจว่าจะใช้ตะขอตัวไหน จนถึงตอนนี้ดูเหมือนว่า hooking 'admin_init' ของรหัสนี้จะใช้งานได้:

 header("Content-type: application/x-msdownload");
 header("Content-Disposition: attachment; filename=data.csv");
 header("Pragma: no-cache");
 header("Expires: 0");
 echo 'data';
 exit();

ดูเหมือนว่าจะใช้ได้ แต่ฉันแค่ต้องการดูว่ามีวิธีปฏิบัติที่ดีที่สุดหรือไม่

ขอบคุณเดฟ

คำตอบ:


39

ถ้าฉันเข้าใจคุณอย่างถูกต้องคุณต้องการให้URL มีลักษณะดังนี้ต่อไปนี้ซึ่งการตอบสนองต่อเบราว์เซอร์จะเป็นเนื้อหาที่คุณสร้างเช่น.CSVไฟล์ของคุณและไม่มีเนื้อหาที่สร้างจาก WordPress?

http://example.com/download/data.csv

ฉันคิดว่าคุณกำลังมองหา'template_redirect'ตะขอ คุณสามารถค้นหา'template_redirect'ใน/wp-includes/template-loader.phpซึ่งเป็นไฟล์เวิร์ดเพรสนักพัฒนาทุกคนควรทำความคุ้นเคยกับ; มันสั้นและหวานและเส้นทางการโหลดทุกหน้าไม่ใช่ผู้ดูแลเพื่อให้แน่ใจว่าได้ดู

เพียงเพิ่มสิ่งต่อไปนี้ใน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()ให้แทนที่404WordPress ที่ได้ตั้งค่าไว้และใช้รหัสสถานะHTTP 200 "ตกลง"แทน

และนี่คือสิ่งที่ดูเหมือนใน FireFox ( โปรดทราบว่าภาพหน้าจอไม่มี/downloads/ไดเรกทอรีเสมือนเพราะหลังจากถ่ายภาพและใส่คำอธิบายประกอบภาพหน้าจอมันก็ดูเหมือนว่าเป็นความคิดที่ดีที่จะเพิ่ม'/downloads/'ไดเรกทอรีเสมือน):

สกรีนช็อตของ URL ดาวน์โหลดสำหรับไฟล์ CSV
(ที่มา: mikeschinkel.com )

UPDATE

หากคุณต้องการให้จัดการการดาวน์โหลดจาก URL ที่มีคำนำหน้าด้วย/wp-admin/เพื่อให้ผู้ใช้เห็นด้วยภาพว่าได้รับการคุ้มครองโดยการเข้าสู่ระบบคุณสามารถทำได้เช่นกัน คำอธิบายของวิธีหนึ่งต่อไปนี้

ฉันโพสต์ลงในชั้นเรียนเวลานี้เรียกว่าDownloadCSVและเพื่อสร้างผู้ใช้"ความสามารถ"เรียกว่า'download_csv'สำหรับ'administrator'บทบาท(อ่านเกี่ยวกับบทบาทและความสามารถที่นี่ ) คุณก็สามารถวิ่งออกจากที่กำหนดไว้ล่วงหน้า'export'บทบาทหากคุณต้องการและหากดังนั้นเพียงค้นหาและแทนที่'download_csv'ด้วย'export'และลบการregister_activation_hook()โทรและactivate()ฟังก์ชั่น ความจำเป็นในการขอเปิดใช้งานเป็นเหตุผลหนึ่งที่ทำให้ฉันย้ายสิ่งนี้ไปยังปลั๊กอินแทนที่จะเก็บไว้ในfunctions.phpไฟล์ของธีม*

ฉันยังเพิ่มตัวเลือกเมนู"ดาวน์โหลด CSV"ออกจากเมนู"เครื่องมือ"โดยใช้add_submenu_page()และเชื่อมโยงกับ'download_csv'ความสามารถ

สุดท้ายฉันเลือก'plugins_loaded'เบ็ดเพราะเป็นตะขอที่เหมาะสมที่สุดที่ฉันสามารถใช้ได้ คุณสามารถใช้งานได้'admin_init'แต่ตะขอนั้นจะทำงานช้ากว่านั้น (1130th hook call เทียบกับ hook hook ที่ 3) ดังนั้นทำไม WordPress ถึงทำงานได้มากกว่าที่มันต้องการ? (ฉันใช้ปลั๊กอินเครื่องมือตะขอของฉันเพื่อหาว่าจะใช้ตะขอตัวใด)

ในเบ็ดฉันตรวจสอบเพื่อให้แน่ใจว่า 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();
}

และนี่คือภาพหน้าจอของปลั๊กอินที่เปิดใช้งาน: (ที่มา: mikeschinkel.com )สกรีนช็อตของหน้าปลั๊กอินแสดงปลั๊กอินที่เปิดใช้งาน

และสุดท้ายนี่คือภาพหน้าจอของการกระตุ้นการดาวน์โหลด: (ที่มา: mikeschinkel.com )สกรีนช็อตของการดาวน์โหลดไฟล์ตาม URL จากตัวเลือกของเมนูเครื่องมือของผู้ดูแลระบบ WordPress


ไมค์ขอบคุณสำหรับความช่วยเหลือของคุณ สิ่งเดียวที่จับได้จากฟีเจอร์นี้คือฉันต้องการดาวน์โหลดไฟล์จากแบ็กเอนด์ ดูเหมือนว่า template_redirect จะไม่ทำงานกับแบ็กเอนด์และถ้าฉันไม่ควรใช้ admin_init ฉันสงสัยว่าควรใช้อะไรแทน admin_init ดูเหมือนจะทำงานให้ฉันได้แล้วตอนนี้ฉันอาจติดอยู่กับมันในระยะสั้น มันเป็นคุณสมบัติย่อยที่มีเพียงไม่กี่คนเท่านั้นที่จะใช้
เดฟมอร์ริส

@Dave Morris - คุณช่วยนิยามความหมายของ"back end" ได้ไหม? คุณหมายถึงบนเซิร์ฟเวอร์หรือไม่ ถ้าใช่'template_redirect'ส่วนใหญ่ทำงานบนเซิร์ฟเวอร์แน่นอน ถ้าไม่ฉันจะสับสนโดยสิ้นเชิง คุณสามารถชี้แจงข้อกังวลได้อย่างไร ขอบคุณล่วงหน้า.
MikeSchinkel

@Dave: หากคุณหมายถึงพื้นที่ของผู้ดูแลระบบโดย "back end" สิ่งนี้จะยังคงใช้งานได้ ดาวน์โหลด URL ที่เริ่มต้นด้วย/downloads/data.csvซึ่งเป็นไฟล์ที่ไม่ได้มีอยู่ดังนั้น WordPress "ส่วนหน้า" template-redirectจะจัดการกับคำขอนี้และในที่สุดการเข้าถึง คุณเพียงแค่สร้างลิงค์ในส่วนของผู้ดูแลระบบซึ่งชี้ไปยัง URL ที่อยู่ด้านหน้า (ซึ่งก็ต้องบอกว่าวิธีนี้คุณจะไม่ได้รับการคุ้มครองดูแลระบบเข้าสู่ระบบได้ฟรี? - ทุกคนที่ทราบ URL สามารถดาวน์โหลดไฟล์ แต่อาจจะมีวิธีง่ายๆในการแก้ไขปัญหาที่)
ม.ค. Fabry

@Jan Fabry - อ่าฉันเข้าใจแล้ว โดย"back end"เขาหมายถึงจากภายในผู้ดูแลระบบใช่ไหม เขาสามารถใช้ฟังก์ชั่นที่current_user_can()มีรหัสข้างต้นหรือใช้วิธีการอื่น หลังจากความคิดเห็นนี้ฉันจะเพิ่มการอัปเดตในคำตอบของฉัน
MikeSchinkel

ใช่ฉันขอโทษฉันไม่ได้รับอีเมลแจ้งเตือนจากเว็บไซต์นี้เพื่ออธิบายความล่าช้าในการตอบกลับ ฉันหมายถึงพื้นที่ผู้ดูแลระบบของ WordPress เมื่อฉันพูดว่า "แบ็กเอนด์" ขอโทษสำหรับเรื่องนั้น. ฉันจะลองใช้ template_redirect และดูว่าเกิดอะไรขึ้น ขอบคุณ! ~ Dave
Dave Morris

3

อีกหนึ่งปลั๊กอินที่มีประโยชน์สำหรับการส่งออกเป็น 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();

2

admin_init Hook หรือload- (page) Hook ดูเหมือนว่าใช้งานได้ WordPress ไม่ได้ตั้งค่าหัวข้อในสถานะนี้ ฉันใช้load- (page) Hook เพราะจะทำงานเมื่อมีการโหลดหน้าเมนูการดูแลระบบ คุณสามารถโหลดสคริปต์ของคุณสำหรับหน้าเฉพาะ

คุณสามารถตรวจสอบload- (page) Hook บน WordPress Codex

หากคุณใช้admin_init Hook ตรวจสอบให้แน่ใจว่าไม่มีการตรวจสอบโดยใช้check_admin_refererหรือสคริปต์อื่น ๆ อาจผ่านเงื่อนไขจะได้รับผลลัพธ์ไฟล์ดาวน์โหลดของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.