2010-11-10 9 views
6

मेरे पास कुछ PHP कोड है जो डेटाबेस पर एक क्वेरी चलाता है, परिणाम को एक सीएसवी फ़ाइल में सहेजता है, और फिर उपयोगकर्ता को फ़ाइल डाउनलोड करने की अनुमति देता है। समस्या यह है कि, सीएसवी फ़ाइल में वास्तविक सीएसवी सामग्री के आसपास पेज HTML शामिल है।PHP में फ़ाइल डाउनलोड को मजबूर करना - जूमला ढांचे के अंदर

मैंने पहले से ही सभी संबंधित प्रश्न पढ़े हैं, जिनमें this one भी शामिल है। दुर्भाग्यवश मेरा कोड जूमला के भीतर मौजूद है, इसलिए यदि मैं किसी ऐसे पृष्ठ पर रीडायरेक्ट करने का प्रयास करता हूं जिसमें हेडर के अलावा कुछ भी नहीं है, तो जूमला स्वचालित रूप से अपने स्वयं के नेविगेशन कोड से घिरा हुआ है। यह केवल डाउनलोड के समय होता है; अगर मैं सर्वर पर सहेजी गई सीएसवी फ़ाइल को देखता हूं, तो इसमें HTML नहीं है।

क्या कोई भी वास्तविक सीएसवी फ़ाइल के डाउनलोड को मजबूर करने के तरीके से बाहर निकलने में मदद कर सकता है क्योंकि यह सर्वर पर है, ब्राउजर इसे संपादित कर रहा है? मैं हैडर स्थान का उपयोग कर की कोशिश की है, इस तरह:

header('Location: ' . $filename); 

लेकिन यह नहीं बल्कि संवाद बचाने के लिए मजबूर कर रहा से ब्राउज़र में फ़ाइल को खोलता है,।

//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; 

संपादन पूर्ण URL ऐसा दिखाई देगा:

http://mysite.com/administrator/index.php?option=com_eimcart&task=customers 
वास्तविक डाउनलोड लिंक के साथ

इस तरह लग रही:

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

यहाँ मेरे वर्तमान कोड है MOR ई EDITS यहां पृष्ठ का एक शॉट है जिस पर कोड चालू है; जेनरेट की गई फाइल अभी भी सबमेनू के लिए एचटीएमएल में खींच रही है। चयनित लिंक (सीएसवी के रूप में निर्यात) के लिए कोड अब

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

alt text

अब यहाँ है उत्पन्न, सहेजी गई फ़ाइल का एक स्क्रीनशॉट है:

alt text

यह दौरान सिकुड़ गया यहां अपलोड करें, लेकिन पीले रंग में हाइलाइट किया गया टेक्स्ट सबनाव के लिए एचटीएमएल कोड है (ग्राहकों को सूचीबद्ध करें, नया ग्राहक जोड़ें, सीएसवी के रूप में निर्यात करें)। यहां मेरा पूरा कोड अब जैसा दिखता है; अगर मैं सिर्फ उस अंतिम बिट से छुटकारा पा सकता हूं तो यह सही होगा। ब्योर्न

लिए

$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); 

अद्यतन यहाँ कोड (मुझे लगता है कि) कि मेरे लिए काम किया है। लिंक है कि कार्रवाई कॉल में रॉ परम का उपयोग करें:

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; 
} 

तो जब एक:

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

क्योंकि इस प्रक्रियात्मक था, हमारे लिंक जो इस तरह दिखता है एक फ़ाइल customers.php कहा जाता है, में किया गया था उपयोगकर्ता उपरोक्त लिंक पर क्लिक किया गया, 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'); 


//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); 
+0

आपको शायद इस विशिष्ट मामले के लिए जूमला के यूआरएल रीराइटिंग को बंद करने की आवश्यकता होगी। क्या आप कुछ पूर्ण यूआरएल और अपनी .htaccess फ़ाइल दिखा सकते हैं? अनुरोधित जानकारी शामिल करने के लिए –

+0

संपादन ओपी। – EmmyS

+0

आह ठीक है, यह अलग है: जूमला शायद इंडेक्स फ़ाइल में आउटपुट पर हेडर/फ़ूटर को थप्पड़ मारता है, इसे .htaccess में नियम जोड़कर तय नहीं किया जा सकता है ... –

उत्तर

3

यह नमूना कोड का एक टुकड़ा है जिसे मैंने अभी आपकी मदद करने के लिए पकाया है। इसे अपने नियंत्रक में एक क्रिया विधि के रूप में उपयोग करें।

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); 
    } 

यह अकेला पर्याप्त नहीं होगा, क्योंकि आपके द्वारा डाउनलोड की गई फ़ाइल में अभी भी आसपास के HTML शामिल होंगे। इससे छुटकारा पाने के लिए और केवल सीएसवी फ़ाइल की सामग्री प्राप्त करें, आपको अपने अनुरोध में प्रारूप = कच्चे पैरामीटर को जोड़ने की आवश्यकता है। मेरे मामले में विधि com_csvexample घटक के अंदर है, इसलिए यूआरएल होगा:

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

संपादित

आदेश का उपयोग कर से बचने के लिए एक मध्यवर्ती फ़ाइल

साथ स्थानापन्न

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

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

इस विधि का उपयोग y कहां उस कोड को स्थानांतरित करना है जो आउटपुट में कुछ भी लिखा जाने से पहले हेडर भेजता है। आपको readfile फ़ंक्शन पर कॉल की आवश्यकता नहीं होगी।

+0

मैंने गहराई से थोड़ा सा कोड आपके विश्लेषण का विश्लेषण किया। क्या कोई कारण है कि आप सर्वर पर csv फ़ाइल को संग्रहीत करना चाहते हैं या यह अभी बनाया गया है ताकि आप इसे ब्राउज़र पर बाद में भेज सकें? यदि आपको सर्वर पर रहने के लिए इसकी आवश्यकता नहीं है तो आप सीएसवी को इको के साथ आउटपुट स्ट्रीम पर सीधे आउटपुट कर सकते हैं, स्वयं को बहुत सारी परेशानी बचा सकते हैं ... बस शीर्षकों को पहले भेजना याद रखें :) – silvo

+0

यह कोड मुझे विरासत में मिला है मैं वहां क्या था के साथ काम कर रहा था। फ़ाइल को सर्वर पर रखने का कोई कारण नहीं है। क्या आप इको के माध्यम से भेजने पर विस्तार कर सकते हैं? क्या यह अभी भी एक फाइल बनायेगा जो उपयोगकर्ता अपने कंप्यूटर पर डाउनलोड करेगा? या यह सिर्फ ब्राउज़र में सीएसवी प्रदर्शित करेगा? – EmmyS

+0

कृपया मेरे संशोधित उत्तर पर एक नज़र डालें। सीएसवी को सीधे आउटपुट में प्रिंट करना आपके कोड के मुकाबले कहीं अलग नहीं है। ब्राउज़र का व्यवहार आपके द्वारा भेजे जाने वाले शीर्षकों पर निर्भर करता है। चूंकि आप ब्राउज़र को सूचित करते हुए एक शीर्षलेख भेज रहे हैं कि सामग्री वास्तव में एक अनुलग्नक है, यह फ़ाइल डाउनलोड को ट्रिगर करेगा। – silvo

3

अपने नियंत्रक के लिए इस विधि जोड़ें:

function exportcsv() { 
    $model = & $this->getModel('export'); 
    $model->exportToCSV(); 
} 

फिर एक नया मॉडल export.php कहा जाता है, नीचे दिए गए कोड जोड़ें। आपको कोड को अपनी स्थिति में बदलने या विस्तार करने की आवश्यकता होगी।

<?php 
/** 
* @package TTVideo 
* @author Martin Rose 
* @website www.toughtomato.com 
* @version 2.0 
* @copyright Copyright (C) 2010 Open Source Matters. All rights reserved. 
* @license http://www.gnu.org/copyleft/gpl.html GNU/GPL 
*/ 

//No direct acesss 
defined('_JEXEC') or die(); 
jimport('joomla.application.component.model'); 
jimport('joomla.filesystem.file'); 
jimport('joomla.filesystem.archive'); 
jimport('joomla.environment.response'); 

class TTVideoModelExport extends JModel 
{ 

    function exportToCSV() { 
    $files = array(); 
    $file = $this->__createCSVFile('#__ttvideo'); 
    if ($file != '') $files[] .= $file; 
    $file = $this->__createCSVFile('#__ttvideo_ratings'); 
    if ($file != '') $files[] .= $file; 
    $file = $this->__createCSVFile('#__ttvideo_settings'); 
    if ($file != '') $files[] .= $file; 
    // zip up csv files to be delivered 
    $random = rand(1, 99999); 
    $archive_filename = JPATH_SITE.DS.'tmp'.DS.'ttvideo_'. strval($random) .'_'.date('Y-m-d').'.zip'; 
    $this->__zip($files, $archive_filename); 
    // deliver file 
    $this->__deliverFile($archive_filename); 
    // clean up 
    JFile::delete($archive_filename); 
    foreach($files as $file) JFile::delete(JPATH_SITE.DS.'tmp'.DS.$file); 
    } 

    private function __createCSVFile($table_name) { 
    $db = $this->getDBO(); 
    $csv_output = ''; 

    // get table column names 
    $db->setQuery("SHOW COLUMNS FROM `$table_name`"); 
    $columns = $db->loadObjectList(); 

    foreach ($columns as $column) { 
     $csv_output .= $column->Field.'; '; 
    } 
    $csv_output .= "\n"; 

    // get table data 
    $db->setQuery("SELECT * FROM `$table_name`"); 
    $rows = $db->loadObjectList(); 
    $num_rows = count($rows); 
    if ($num_rows > 0) { 
     foreach($rows as $row) { 
     foreach($row as $col_name => $value) { 
      $csv_output .= $value.'; '; 
     } 
     $csv_output .= "\n"; 
     } 
    } 
    $filename = substr($table_name, 3).'.csv'; 
    $file = JPATH_SITE.DS.'tmp'.DS.$filename; 
    // write file to temp directory 
    if (JFile::write($file, $csv_output)) return $filename; 
    else return ''; 
    } 

    private function __deliverFile($archive_filename) { 
    $filesize = filesize($archive_filename); 
    JResponse::setHeader('Content-Type', 'application/zip'); 
    JResponse::setHeader('Content-Transfer-Encoding', 'Binary'); 
    JResponse::setHeader('Content-Disposition', 'attachment; filename=ttvideo_'.date('Y-m-d').'.zip'); 
    JResponse::setHeader('Content-Length', $filesize); 
    echo JFile::read($archive_filename); 
    } 

    /* creates a compressed zip file */ 
    private function __zip($files, $destination = '') { 
    $zip_adapter = & JArchive::getAdapter('zip'); // compression type 
    $filesToZip[] = array(); 
    foreach ($files as $file) { 
     $data = JFile::read(JPATH_SITE.DS.'tmp'.DS.$file); 
     $filesToZip[] = array('name' => $file, 'data' => $data); 
    } 
    if (!$zip_adapter->create($destination, $filesToZip, array())) { 
     global $mainframe; 
     $mainframe->enqueueMessage('Error creating zip file.', 'message'); 
    } 
    } 


} 
?> 

फिर अपने डिफ़ॉल्ट view.php पर जाएं और कस्टम बटम जोड़ें, उदा।

// custom export to set raw format for download 
$bar = & JToolBar::getInstance('toolbar'); 
$bar->appendButton('Link', 'export', 'Export CSV', 'index.php?option=com_ttvideo&task=export&format=raw'); 

गुड लक!

+0

धन्यवाद, मार्टिन, लेकिन यह कोड (जिसे मैंने विरासत में मिला) प्रक्रियात्मक रूप से किया जाता है, एमवीसी में नहीं। – EmmyS

0

स्थिर फ़ाइलों में HTTP शीर्षलेख जोड़ने के लिए आप अपाचे के mod_cern_meta का उपयोग कर सकते हैं। Content-Disposition: attachment। आवश्यक .htaccess और .meta फ़ाइलें PHP द्वारा बनाई जा सकती हैं।

0

जूमला एप्लिकेशन में सीएसवी डेटा आउटपुट करने का एक और तरीका HTML प्रारूप के बजाय सीएसवी का उपयोग करके एक दृश्य बनाना है।

घटकों/com_mycomp/विचारों/कुछ/view.csv.php

और निम्नलिखित के लिए सामग्री समान जोड़ें::

<?php 
// No direct access 
defined('_JEXEC') or die; 

jimport('joomla.application.component.view'); 

class MyCompViewSomething extends JViewLegacy // Assuming a recent version of Joomla! 
{   
    function display($tpl = null) 
    { 
     // Set document properties 
     $document = &JFactory::getDocument(); 
     $document->setMimeEncoding('text/csv'); 

     JResponse::setHeader('Content-disposition', 'inline; filename="something.csv"', true); 

     // Output UTF-8 BOM 
     echo "\xEF\xBB\xBF"; 

     // Output some data 
     echo "field1, field2, 'abc 123', foo, bar\r\n"; 
    } 
} 
?> 

तो फिर तुम फ़ाइल बना सकते हैं यही कारण है कि एक फ़ाइल बनाने के रूप में निम्न प्रकार है, डाउनलोड लिंक इस प्रकार है:

/index.php?option=com_mycomp & दृश्य = कुछ & प्रारूप = सीएसवी

अब, आपको सामग्री-स्वभाव में 'इनलाइन' भाग पर सवाल करने का अधिकार होगा। अगर कुछ साल पहले इस कोड को लिखते समय मुझे सही याद आया, तो मुझे 'अनुलग्नक' विकल्प में समस्याएं थीं। यह लिंक जो मैंने अभी गॉगल किया है, अब इसके लिए ड्राइवर के रूप में परिचित लग रहा था: https://dotanything.wordpress.com/2008/05/30/content-disposition-attachment-vs-inline/। मैं तब से 'इनलाइन' का उपयोग कर रहा हूं और अभी भी किसी भी ब्राउज़र से फ़ाइल को उचित रूप से सहेजने के लिए कहा गया है।मैंने हाल ही में 'अटैचमेंट' का उपयोग करने की कोशिश नहीं की है, इसलिए यह अभी ठीक काम कर सकता है (लिंक अब 7 साल का है!)