2013-04-02 3 views
3

PHP 출력 버퍼에 CSV 파일을 작성한 다음 쓰기가 완료된 후 해당 파일을 클라이언트 컴퓨터로 다운로드해야합니다. (필자는 서버에 쓰기 만하고 다운로드하고 싶었지만 프로덕션 서버에 쓰기 권한이없는 것으로 나타났습니다.)PHP 출력 버퍼에 쓰고 버퍼에서 CSV를 다운로드하십시오.

$basic_info = fopen("php://output", 'w'); 
$basic_header = array(HEADER_ITEMS_IN_HERE); 

@fputcsv($basic_info, $basic_header); 

while($user_row = $get_users_stmt->fetch(PDO::FETCH_ASSOC)) { 
    @fputcsv($basic_info, $user_row); 
} 

@fclose($basic_info); 

header('Content-Description: File Transfer'); 
header('Content-Type: application/csv'); 
header('Content-Disposition: attachment; filename=test.csv'); 
header('Expires: 0'); 
header('Cache-Control: must-revalidate'); 
header('Pragma: public'); 
header('Content-Length: ' . filesize("php://output")); 
ob_clean(); 
flush(); 
readfile("php://output"); 

내가 할 모르겠어요 :

나는 다음과 같은 PHP 스크립트가 있습니다. CSV 파일은 다운로드 하나 아무 것도 표시하지 않습니다. 내 ob_clean() 및 flush() 명령의 순서와 관련이 있다고 가정하지만 이러한 것들을 주문하는 가장 좋은 방법은 무엇인지 모르겠습니다.

도움을 주시면 감사하겠습니다.

+0

출력 버퍼에 쓰는 경우 즉시 클라이언트로 보냅니다. 어떤 경우 든 먼저 모든 헤더를 보내야합니다. – datasage

+1

ob_start()를 어딘가에하지 않으면 ob_clean()이 무의미합니다. readfile WRITES를 출력으로 간주하지만, 그 입력으로부터 읽는 중입니다.이 코드보다 먼저 ob_start()를 수행하지 않았다면, fputcsv()는 헤더 코드가 실행되기 전에 브라우저에 출력을 남겼습니다. –

+0

"@"를 사용할 때마다 PHP에서 문자 그대로 하나의 메서드 이름을 지정할 수 있습니다. 그것은 당신의 코드가 아니므로 각 줄에 @를 심는 대신 처음 시작할 때 코드를 올바르게 작성할 수 있습니까? –

답변

6

조금 지나치게하고 있습니다. CSV 출력의 유일한 목적으로 스크립트를 작성하십시오. 화면에 직접 인쇄하십시오. 헤더 나 버퍼 또는 php : // 출력 또는 그와 같은 것에 대해서는 아직 걱정하지 마십시오. 당신은 당신이 적절하게, 단지 시작에이 헤더를 추가하려면 화면 밖으로 데이터를 인쇄하고 있음을 확인하면

:

<?php 
header("Content-disposition: attachment; filename=test.csv"); 
header("Content-Type: text/csv"); 
?> 

... 즉 적절하게 파일을 다운로드 확인합니다. 그런 다음 원하는 경우 다른 헤더를 추가 할 수 있습니다 (위에 포함 된 헤더는이 작업을 수행하기 위해 추가 크 러프 트없이 자신을 사용했습니다. 나머지는 기본적으로 효율성과 캐시 제어를위한 것이며, 일부는 이미 적절히 처리 될 수 있습니다). 귀하의 특정 응용 프로그램에 중요하거나 중요하지 않을 수도 있습니다).

ob_start()ob_get_clean()과 함께 출력 버퍼링을 사용하면 출력 내용을 문자열로 가져와 Content-Length을 작성할 수 있습니다.

+5

내가 잘못하고있는 것에 대해 불평하는 다른 사람들과 달리 실제로 나를 돕는 것에 대해 감사합니다. – jrubins

0

코드에 약간의 조정을했습니다.

  • 출력 전에 이동 된 헤더는 PHP's doc으로 제안됩니다. 실제 출력 가 전송되기 전에

해당 헤더를() 기억이 중 일부 헤더 제거, 또는

  • PHP

    에서 일반 HTML 태그, 파일의 빈 줄에 의해, 호출해야합니다 그것은 많은 변화를 가져 오지 않았습니다.
  • select 열의 이름을 사용하여 csv header를 작성하는 또 다른 옵션을 주석 처리했습니다.
  • 이제 콘텐츠 길이가 작동합니다.
  • $ basic_info는 출력 버퍼에 이미 있으므로 머리말을 통해 파일로 리다이렉트하므로 echo 할 필요가 없습니다.
  • 오버 헤드가 발생할 수 있으므로 @ (PHP 오류 제어 운영자)이 제거되었으므로 지금 표시 할 링크가 없지만 검색하면 찾을 수 있습니다. 오류가 사라지기 전에 두 번 생각해야합니다. 대부분 번 반복됩니다.

    header('Content-Length: '.$streamSize); 
    

    출력이 이전에 작성된 때문에 : 에드 슨의 대답은 내 의견에서 언급 한 바와 같이


header('Content-Type: text/csv'); 
header('Content-Disposition: attachment; filename=test.csv'); 
header('Expires: 0'); 
header('Cache-Control: no-cache'); 

$basic_info = fopen("php://output", 'w'); 
$basic_header = array(HEADER_ITEMS_IN_HERE); 

fputcsv($basic_info, $basic_header); 
$count = 0; // auxiliary variable to write csv header in a different way 

while($user_row = $get_users_stmt->fetch(PDO::FETCH_ASSOC)) { 
    // Write select column's names as CSV header 
    if ($count == 0) { 
     fputcsv($basic_info, array_keys($user_row)); 
    } 

    fputcsv($basic_info, $user_row); 
    $count++; 
} 

// get size of output after last output data sent 
$streamSize = ob_get_length(); 
fclose($basic_info); 

header('Content-Length: '.$streamSize); 
+0

헤더가 이미 헤더 ('Content-Length :'. $ streamSize)로 전송되지 않았습니까? 전에 php : // output에 썼기 때문에? –

+0

@dnFer 네,하지만 글쓰기를 마친 후에 만 ​​파일 크기를 알 수 있습니다.이 방법은 브라우저가 다운로드 팝업에서 파일 크기를 보여줍니다. –

+0

나는 깨닫는다. 그러나 "헤더가 이미 전송되었습니다"라는 경고가 팝업되지 않는 이유가 궁금합니다. –

1

, 나는 "이미 보낸 헤더는"코드의 마지막 줄에 경고 예상 헤더가 전송되지만 그의 예제는 정상적으로 작동합니다.

일부 조사는 다음과 같은 결론에 날 리드 :

당신이, 당신은 HTTP 헤더와 내용에게 방법을 보낼 수 있습니다 (사용자가 하나 또는 기본 PHP 하나 weither) 출력 버퍼를 사용시

너 싶어. 모든 프로토콜은 본문 (따라서 용어 "헤더") 앞에 헤더를 보내야하지만, 출력 버퍼 레이어를 사용하면 PHP 이 처리해줍니다. 헤더 (header(), setcookie(), session_start())를 사용하여 재생되는 모든 PHP 함수는 버퍼를 채우는 내부 sapi_header_op() 함수 을 실제로 사용합니다. 그런 다음 printf()를 사용하여 출력을 작성하면 에 출력 버퍼를 씁니다 (하나라고 가정). 출력 버퍼가 이 될 때, PHP는 먼저 헤더를 보낸 다음 본문을 보낸다. PHP 이 모든 것을 처리해줍니다.이 동작이 마음에 들지 않으면 은 출력 버퍼 계층을 비활성화하는 것 외에 다른 선택의 여지가 없습니다. 대부분의 구성 하에서

PHP는 버퍼의 기본 사이즈 킬로바이트까지의 데이터를 저장할 수있는 버퍼 PHP 수단 4096 바이트 (4킬로바이트)이다. 이 한도를 초과하거나 PHP 코드 실행이 완료되면 버퍼 된 내용 은 PHP가 사용되는 백엔드 (CGI, , mod_php, FastCGI)에 자동으로으로 전송됩니다. 출력 버퍼링은 PHP-CLI에서 항상 Off입니다. 이 버퍼 크기를 초과하지 않는 (마지막 헤더가 전송되기 전에 스크립트가 분명히 종료되지 않음) 때문에 출력 버퍼를 자동으로 플러시하지 않았기 때문에

에드 슨의 코드가 작동합니다.

출력 버퍼의 데이터가 버퍼 크기를 초과하면 경고가 발생합니다. 또는 그의 예에서,

$get_users_stmt->fetch(PDO::FETCH_ASSOC) 

의 데이터가 너무 클 때.

이 문제를 방지하려면 ob_start() 및 ob_end_flush();로 출력 버퍼링을 관리해야합니다. 아래처럼 :

// Turn on output buffering 
ob_start(); 

// Define handle to output stream 
$basic_info = fopen("php://output", 'w'); 

// Define and write header row to csv output 
$basic_header = array('Header1', 'Header2'); 
fputcsv($basic_info, $basic_header); 

$count = 0; // Auxiliary variable to write csv header in a different way 

// Get data for remaining rows and write this rows to csv output 
while($user_row = $get_users_stmt->fetch(PDO::FETCH_ASSOC)) { 
    if ($count == 0) { 
     // Write select column's names as CSV header 
     fputcsv($basic_info, array_keys($user_row)); 
    } else { 
     //Write data row 
     fputcsv($basic_info, $user_row); 
    } 
    $count++; 
} 

// Get size of output after last output data sent 
$streamSize = ob_get_length(); 

//Close the filepointer 
fclose($basic_info); 

// Send the raw HTTP headers 
header('Content-Type: text/csv'); 
header('Content-Disposition: attachment; filename=test.csv'); 
header('Expires: 0'); 
header('Cache-Control: no-cache'); 
header('Content-Length: '. ob_get_length()); 

// Flush (send) the output buffer and turn off output buffering 
ob_end_flush(); 

당신은 여전히 ​​다른 제한에 묶여 있습니다.

관련 문제