2010-07-27 42 views
23

Tôi đang cố gắng hoàn thành một nhiệm vụ khá đơn giản cho trang web của mình, nhưng tôi "không chắc chắn chính xác cách thực hiện. Tôi muốn người dùng xem bảng, sau đó nhấp vào , tại thời điểm đó, người dùng có thể lưu nội dung của bảng đó dưới dạng tệp csv. Yêu cầu này đôi khi có thể khá phức tạp, do đó tôi tạo trang tiến độ để cảnh báo người dùng. file csv (tôi sử dụng jQuery và PHP)Tải xuống tệp CSV bằng cách sử dụng "AJAX"

mã jQuery chạy trên nhấp chuột:.

hmis_query_csv_export: function(query_name) { 
    $.uiLock('<p>Query Loading.</p><img src="/images/loading.gif" />') 
    $.get({ 
     url: '/php_scripts/utils/csv_export.php', 
     data: {query_name: query_name}, 
     success: function(data) { 
      $.uiUnlock(); 
     } 
    });} 

PHP liên quan:

header("Content-type: text/x-csv"); 
header("Content-Disposition: attachment; filename=search_results.csv"); 
// 
//Generate csv 
// 
echo $csvOutput 
exit();

Điều này không là gửi văn bản như các file PHP, nhưng nó không tạo ra một tải. Tôi đang làm gì sai?

Trả lời

36

Nếu bạn đang buộc tải xuống, bạn có thể chuyển hướng trang hiện tại đến liên kết tải xuống. Vì liên kết sẽ tạo ra hộp thoại tải xuống, trang hiện tại (và trạng thái của nó) sẽ được giữ nguyên.

cơ bản cách tiếp cận:

$('a#query_name').click(function(){ 
    $('#wait-animation').show(); 
    document.location.href = '/php_scripts/utils/csv_export.php?query_name='+query_name; 
    $('#wait-animation').hide(); 
}); 

phức tạp thêm:

$('a#query_name').click(function(){ 
    MyTimestamp = new Date().getTime(); // Meant to be global var 
    $('#wait-animation').show(); 
    $.get('/php_scripts/utils/csv_export.php','timestamp='+MyTimestamp+'&query_name='query_name,function(){ 
     document.location.href = '/php_scripts/utils/csv_export.php?timestamp='+MyTimestamp+'&query_name='+query_name; 
     $('#wait-animation').hide(); 
    }); 
}); 

Tại PHP kịch bản:

@header("Last-Modified: " . @gmdate("D, d M Y H:i:s",$_GET['timestamp']) . " GMT"); 
@header("Content-type: text/x-csv"); 
// If the file is NOT requested via AJAX, force-download 
if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') { 
    header("Content-Disposition: attachment; filename=search_results.csv"); 
} 
// 
//Generate csv 
// 
echo $csvOutput 
exit(); 

URL cho cả hai yêu cầu phải giống nhau để lừa trình duyệt không bắt đầu tải xuống mới tại document.location.href, nhưng để lưu bản sao vào bộ nhớ cache. Tôi không hoàn toàn chắc chắn về nó, nhưng có vẻ khá hứa hẹn.

+0

Cảm ơn rất nhiều về các mẹo. Tôi có thể làm điều này để làm việc rất dễ dàng, nhưng tôi tự hỏi làm thế nào tôi có thể sử dụng điều này trong khi vẫn thực hiện một khóa màn hình và hình ảnh động tiến bộ. Tôi chỉ lo lắng rằng người dùng có thể bị nhầm lẫn vì tùy thuộc vào truy vấn mà quá trình này có thể mất đến 3 hoặc 4 phút. –

+1

Nếu mất nhiều thời gian để tạo tệp CSV, bạn có thể cần phải thay đổi hướng một chút và thay vào đó sử dụng AJAX để khởi chạy tập lệnh PHP tạo tệp đĩa tạm thời; một khi kịch bản PHP trả về (với tên tập tin) chức năng gọi lại AJAX có thể thực hiện chuyển hướng như Ast Derek hiển thị. – godheadatomic

+0

Vì vậy, chỉnh sửa của bạn có vẻ như nó sẽ hoạt động, nhưng có vẻ như các câu lệnh đang được chạy không đồng bộ. Câu lệnh thứ ba không đợi quá trình tải xuống hoàn tất, do đó màn hình chờ xuất hiện rồi biến mất ngay lập tức. Có cách nào để buộc nó chạy đồng bộ không? –

1

Tôi không nghĩ bạn có thể tải xuống trình duyệt bằng cách sử dụng yêu cầu AJAX/JS. Hãy thử sử dụng iframe ẩn điều hướng đến trang tạo ra CSV

0

Điều quan trọng của việc sử dụng AJAX là tránh tải lại hiển thị của trang. Nếu bạn muốn tải xuống, bạn muốn điều ngược lại, - một yêu cầu hoàn toàn mới từ trình duyệt. Tôi muốn nói, chỉ cần tạo một nút đơn giản trỏ đến trang php của bạn.

+0

Ok, nếu tôi làm như vậy, tôi sẽ tích hợp hoạt ảnh tải và khóa giao diện người dùng vào đó như thế nào? Đó sẽ không phải là một lý do để sử dụng AJAX? Ngoài ra, tôi khá mới với điều này và tôi không chắc chắn cách tốt nhất để làm điều đó trong khi tích hợp các tham số GET vào yêu cầu trang. –

+0

@The_Denominator sử dụng khung nội tuyến –

0

Để phản hồi và mở rộng những gì người khác đã nói, bạn thực sự không thể gửi tệp bằng AJAX. Một trong những lý do cho điều này là (và ai đó sửa tôi nếu tôi sai về điều này, xin vui lòng) rằng trang bạn hiện đang ở đã gửi các tiêu đề nội dung của nó; bạn không thể gửi chúng trở lại cùng một cửa sổ, ngay cả với một yêu cầu AJAX (đó là những gì tập tin PHP của bạn đang cố gắng làm).

Những gì tôi đã thực hiện trước đó trong các dự án là chỉ cần cung cấp liên kết (với target = "_ blank" hoặc chuyển hướng javascript) đến trang PHP tải xuống riêng biệt. Nếu bạn đang sử dụng Apache, hãy kiểm tra mod_xsendfile.

5

EDIT Tôi vừa thử với tệp 10MB và có vẻ như val() quá chậm để chèn dữ liệu. Hurrumph.


Được rồi, vì vậy tôi đã cho người khác đi. Điều này có thể hoặc có thể không hoàn toàn điên rồ!Ý tưởng là tạo một yêu cầu AJAX để tạo dữ liệu, sau đó sử dụng gọi lại để chèn dữ liệu vào một biểu mẫu ẩn trên trang hiện tại có hành động của trang "tải xuống" thứ ba; sau khi chèn, biểu mẫu được tự động gửi, trang tải xuống sẽ gửi tiêu đề và lặp lại POST, và et voila, tải xuống.

Trong khi đó, trên trang gốc bạn có chỉ báo rằng tệp đang được chuẩn bị và khi hoàn thành chỉ báo được cập nhật.

LƯU Ý: mã kiểm tra này không được kiểm tra rộng rãi và không có kiểm tra bảo mật thực (hoặc bất kỳ kiểm tra nào) được đưa ra. Tôi đã thử nghiệm nó với một tập tin CSV 1.5MB tôi đã đặt về và nó đã được hợp lý snappy.

index.html

<a id="downloadlink" href="#">Click Me</a> 
<div id="wait"></div> 
<form id="hiddenform" method="POST" action="download.php"> 
    <input type="hidden" id="filedata" name="data" value=""> 
</form> 

test.js

$(document).ready(function(){ 
    $("#downloadlink").click(function(){  // click the link to download 
     lock();        // start indicator 
     $.get("create.php",function(filedata){ // AJAX call returns with CSV file data 
      $("#filedata").val(filedata);  // insert into the hidden form 
      unlock();       // update indicator 
      $("#hiddenform").submit();   // submit the form data to the download page 
     }); 
    }); 

    function lock(){ 
     $("#wait").text("Creating File..."); 
    } 

    function unlock(){ 
     $("#wait").text("Done"); 
    } 
}); 

create.php

<?php 
//create $data 
print $data; 
?> 

download.php

<?php 
header("Pragma: public"); 
header("Expires: 0"); 
header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); 
header("Content-Type: text/x-csv"); 
header("Content-Disposition: attachment;filename=\"search_results.csv\""); 

if($_POST['data']){ 
    print $_POST['data']; 
} 
?> 
3

Cách tốt nhất để thực hiện điều này là sử dụng một URI dữ liệu như sau:

  1. Hãy gọi AJAX đến máy chủ theo bình thường
  2. Tạo CSV trên phía máy chủ
  3. Trả lại dữ liệu (hoặc nằm ngang hoặc bên trong cấu trúc JSON)
  4. Tạo URI dữ liệu trong Javascript bằng cách sử dụng dữ liệu trả về
  5. Set window.location.href để Data URI

Xem liên kết này để được hướng dẫn (đoạn # 3, cụ thể): http://en.wikipedia.org/wiki/Data_URI_scheme

Bằng cách này, bạn không cần phải lưu bất kỳ tập tin trên máy chủ, và bạn cũng không cần phải sử dụng iframe hoặc các phần tử biểu mẫu ẩn hoặc bất kỳ hacks nào như vậy.

Các vấn đề liên quan