연결을 일찍 종료하려면 어떻게합니까?


99

상당히 긴 프로세스를 시작하는 AJAX 호출 (JQuery를 통해)을 시도하고 있습니다. 스크립트가 프로세스가 시작되었음을 나타내는 응답을 단순히 보내길 원하지만 JQuery는 PHP 스크립트가 실행될 때까지 응답을 반환하지 않습니다.

"닫기"헤더 (아래)와 출력 버퍼링으로 시도했습니다. 둘 다 작동하지 않는 것 같습니다. 어떤 추측? 아니면 JQuery에서해야 할 일입니까?

<?php

echo( "We'll email you as soon as this is done." );

header( "Connection: Close" );

// do some stuff that will take a while

mail( 'dude@thatplace.com', "okay I'm done", 'Yup, all done.' );

?>

ob_flush ()로 출력 버퍼를 플러시했지만 작동하지 않았습니까?
Vinko Vrsalovic

답변:


87

다음 PHP 매뉴얼 페이지 (사용자 노트 포함)는 PHP 스크립트를 종료하지 않고 브라우저에 대한 TCP 연결을 닫는 방법에 대한 여러 지침을 제안합니다.

아마도 닫기 헤더를 보내는 것보다 약간 더 많은 것이 필요합니다.


OP는 다음을 확인합니다. 예 , 이것이 트릭을 수행했습니다. 여기에 복사 된 user-note # 71172 (2006 년 11 월)를 가리 킵니다 .

PHP 스크립트를 실행하는 동안 사용자 브라우저 연결을 닫는 것은 [PHP] 4.1 이후로 register_shutdown_function()사용자 연결을 자동으로 닫지 않도록 의 동작 이 수정 된 이후 문제가되었습니다 .

sts at mail dot xubion dot hu 원래 솔루션 게시 :

<?php
header("Connection: close");
ob_start();
phpinfo();
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush();
flush();
sleep(13);
error_log("do something in the background");
?>

어떤 당신이 대체 될 때까지 잘 작동 phpinfo()을 위해 echo('text I want user to see');이 경우 헤더가 전송되지 않습니다!

해결책은 헤더 정보를 보내기 전에 명시 적으로 출력 버퍼링을 끄고 버퍼를 지우는 것입니다. 예:

<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(true); // just to be safe
ob_start();
echo('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
// Do processing here 
sleep(30);
echo('Text user will never see');
?>

이걸 알아 내려고 3 시간을 보냈습니다. 누군가에게 도움이되기를 바랍니다. :)

테스트 :

  • IE 7.5730.11
  • Mozilla Firefox 1.81

2010 년 7 월 후반에 Arctic Fire 관련 답변 에서 후속 조치 인 두 개의 추가 사용자 노트를 위의 항목에 연결했습니다.



1
저자와 @Timbo White, 콘텐츠의 크기를 모르고 연결을 일찍 끊을 수 있습니까? IE, 닫기 전에 콘텐츠를 캡처 할 필요가 없습니다.
skibulk 2014

3
해커와 엉뚱한 웹 브라우저는 여전히 연결 종료 HTTP 헤더를 무시하고 나머지 출력을 얻을 수 있습니다. 다음에 오는 것이 민감하지 않은지 확인하십시오. 아마도 ob_start (); P : supress 모든 것에
hanshenrik

3
fastcgi_finish_request (); 추가 위의 방법이 작동하지 않으면 성공적으로 연결을 끊는다고합니다. 그러나 제 경우에는 스크립트가 계속 실행되지 않으므로주의해서 사용하십시오.
에릭 Dube은

@RichardSmith Connection: close헤더는 스택의 다른 소프트웨어 (예 : CGI의 경우 역방향 프록시)에 의해 덮어 쓰기 될 수 있기 때문 입니다 (nginx에서 해당 동작을 관찰했습니다). 그것에 대해 @hanshenrik의 답변을 참조하십시오. 일반적으로 Connection: close클라이언트 측에서 실행되며이 질문에 대한 답변으로 간주되어서는 안됩니다. 연결은 서버 측 에서 닫아야 합니다 .
7heo.tk

56

다음 2 개의 헤더를 전송해야합니다.

Connection: close
Content-Length: n (n = size of output in bytes )

출력 크기를 알아야하므로 출력을 버퍼링 한 다음 브라우저에 플러시해야합니다.

// buffer all upcoming output
ob_start();
echo "We'll email you as soon as this is done.";

// get the size of the output
$size = ob_get_length();

// send headers to tell the browser to close the connection
header("Content-Length: $size");
header('Connection: close');

// flush all output
ob_end_flush();
ob_flush();
flush();

// if you're using sessions, this prevents subsequent requests
// from hanging while the background process executes
if (session_id()) session_write_close();

/******** background process starts here ********/

또한 웹 서버가 출력에서 ​​자동 gzip 압축을 사용하는 경우 (즉, mod_deflate를 사용하는 Apache) 출력의 실제 크기가 변경되고 Content-Length가 더 이상 정확하지 않기 때문에 작동하지 않습니다. 특정 스크립트에서 gzip 압축을 비활성화합니다.

자세한 내용은 http://www.zulius.com/how-to/close-browser-connection-continue-execution을 참조 하십시오 .


16
서버가 출력을 압축하는 경우 header("Content-Encoding: none\r\n");아파치가 압축하지 않는 방식으로 비활성화 할 수 있습니다 .
GDmac

1
@GDmac 감사합니다! 나는 이것을 잠시 동안 작동시킬 수 없었지만 압축을 비활성화하면 트릭이되었습니다.
Reactgular

ob_flush()필요하지 않으며 실제로 통지됩니다 failed to flush buffer. 나는 그것을 꺼내고 이것은 훌륭하게 작동했습니다.
Levi

2
ob_flush()라인 필요 하다는 것을 알았습니다 .
Deebster 2014 년

21

PHP-FPM과 함께 Fast-CGI를 사용하여 fastcgi_end_request()함수 를 사용할 수 있습니다 . 이러한 방식으로 응답이 이미 클라이언트에 전송 된 동안 일부 처리를 계속할 수 있습니다.

여기 PHP 매뉴얼에서 찾을 수 있습니다 : FastCGI Process Manager (FPM) ; 그러나 그 기능은 설명서에 더 이상 문서화되어 있지 않습니다. 다음은 PHP-FPM 에서 발췌 한 것입니다 . PHP FastCGI Process Manager Wiki :


fastcgi_finish_request ()

범위 : PHP 함수

카테고리 : 최적화

이 기능을 사용하면 일부 PHP 쿼리의 구현 속도를 높일 수 있습니다. 스크립트 실행 과정에서 서버 응답에 영향을주지 않는 동작이있을 때 가속이 가능합니다. 예를 들어 페이지가 형성되고 웹 서버에 전달 된 후에 memcached에 세션을 저장할 수 있습니다.fastcgi_finish_request()응답 출력을 중지하는 PHP 기능입니다. 웹 서버는 즉시 "느리고 슬프게"응답을 클라이언트로 전송하기 시작하며 동시에 PHP는 세션 저장, 다운로드 한 비디오 변환, 모든 종류의 처리와 같은 쿼리 컨텍스트에서 많은 유용한 작업을 수행 할 수 있습니다. 통계 등

fastcgi_finish_request() 종료 기능 실행을 호출 할 수 있습니다.


참고 : fastcgi_finish_request()특질 호출하는 flush, print또는 echo초기 스크립트를 종료됩니다.

이러한 문제를 방지하려면 통화 ignore_user_abort(true)직전 또는 직후에 fastcgi_finish_request전화 할 수 있습니다 .

ignore_user_abort(true);
fastcgi_finish_request();

3
이것은 실제 답입니다!
Kirill Titov 2015

2
php-fpm을 사용하는 경우-이 함수를 사용하십시오-헤더와 다른 모든 것은 잊어 버리십시오. 너무 많은 시간을 절약했습니다!
Ross

17

완전한 버전 :

ignore_user_abort(true);//avoid apache to kill the php running
ob_start();//start buffer output

echo "show something to user";
session_write_close();//close session file on server side to avoid blocking other requests

header("Content-Encoding: none");//send header to avoid the browser side to take content as gzip format
header("Content-Length: ".ob_get_length());//send length header
header("Connection: close");//or redirect to some url: header('Location: http://www.google.com');
ob_end_flush();flush();//really send content, can't change the order:1.ob buffer to normal buffer, 2.normal buffer to output

//continue do something on server side
ob_start();
sleep(5);//the user won't wait for the 5 seconds
echo 'for diyism';//user can't see this
file_put_contents('/tmp/process.log', ob_get_contents());
ob_end_clean();

어떤 의미에서 완전합니까? 수락 된 답변 스크립트를 완료해야하는 문제는 무엇이며 (어떤 것입니까?) 어떤 구성 차이로 인해이를 필요로 했습니까?
hakre

4
이 줄 : header ( "Content-Encoding : none"); -> 매우 중요합니다.
Bobby Tables

2
감사합니다. 이것이이 페이지에서 유일하게 작동하는 솔루션입니다. 이것은 대답으로 승인되어야합니다.

6

더 나은 해결책은 백그라운드 프로세스를 포크하는 것입니다. 유닉스 / 리눅스에서는 매우 간단합니다.

<?php
echo "We'll email you as soon as this is done.";
system("php somestuff.php dude@thatplace.com >/dev/null &");
?>

더 나은 예를 보려면이 질문을 확인해야합니다.

PHP는 백그라운드 프로세스를 실행합니다.


4

Linux 서버와 루트 액세스 권한이 있다고 가정하면 이것을 시도하십시오. 내가 찾은 가장 간단한 해결책입니다.

다음 파일에 대한 새 디렉터리를 만들고 전체 권한을 부여하십시오. (나중에 더 안전하게 만들 수 있습니다.)

mkdir test
chmod -R 777 test
cd test

이 파일을 bgping.

echo starting bgping
ping -c 15 www.google.com > dump.txt &
echo ending bgping

를 참고 &. ping 명령은 현재 프로세스가 echo 명령으로 이동하는 동안 백그라운드에서 실행됩니다. www.google.com을 15 번 핑하며 약 15 초가 걸립니다.

실행 가능하게 만드십시오.

chmod 777 bgping

이 파일을 bgtest.php.

<?php

echo "start bgtest.php\n";
exec('./bgping', $output, $result)."\n";
echo "output:".print_r($output,true)."\n";
echo "result:".print_r($result,true)."\n";
echo "end bgtest.php\n";

?>

브라우저에서 bgtest.php를 요청하면 ping 명령이 완료 될 때까지 약 15 초 동안 기다리지 않고 다음 응답을 빠르게 받아야합니다.

start bgtest.php
output:Array
(
    [0] => starting bgping
    [1] => ending bgping
)

result:0
end bgtest.php

이제 ping 명령이 서버에서 실행 중이어야합니다. ping 명령 대신 PHP 스크립트를 실행할 수 있습니다.

php -n -f largejob.php > dump.txt &

도움이 되었기를 바랍니다!


4

다음은 gzip 압축과 함께 작동하는 Timbo의 코드 수정입니다.

// buffer all upcoming output
if(!ob_start("ob_gzhandler")){
    define('NO_GZ_BUFFER', true);
    ob_start();
}
echo "We'll email you as soon as this is done.";

//Flush here before getting content length if ob_gzhandler was used.
if(!defined('NO_GZ_BUFFER')){
    ob_end_flush();
}

// get the size of the output
$size = ob_get_length();

// send headers to tell the browser to close the connection
header("Content-Length: $size");
header('Connection: close');

// flush all output
ob_end_flush();
ob_flush();
flush();

// if you're using sessions, this prevents subsequent requests
// from hanging while the background process executes
if (session_id()) session_write_close();

/******** background process starts here ********/

당신은 신입니다. 나는 이것을 알아 내기 위해 이틀 동안 일했다. 내 로컬 개발자에서는 작동했지만 호스트에서는 작동하지 않았습니다. 나는 물에 빠졌다. 넌 나를 구했다. 감사합니다!!!!
Chad Caldwell

3

나는 공유 호스트에 있으며 fastcgi_finish_request스크립트를 완전히 종료하도록 설정되어 있습니다. 나는 connection: close해결책도 마음에 들지 않는다 . 이를 사용하면 후속 요청에 대해 별도의 연결이 필요하므로 추가 서버 리소스가 필요합니다. 나는 Transfer-Encoding: cunked Wikipedia 기사를 읽고 0\r\n\r\n응답 이 종료 된다는 것을 배웠습니다 . 나는 이것을 브라우저 버전과 장치에서 철저히 테스트하지는 않았지만 현재 4 개의 브라우저 모두에서 작동합니다.

// Disable automatic compression
// @ini_set('zlib.output_compression', 'Off');
// @ini_set('output_buffering', 'Off');
// @ini_set('output_handler', '');
// @apache_setenv('no-gzip', 1);

// Chunked Transfer-Encoding & Gzip Content-Encoding
function ob_chunked_gzhandler($buffer, $phase) {
    if (!headers_sent()) header('Transfer-Encoding: chunked');
    $buffer = ob_gzhandler($buffer, $phase);
    return dechex(strlen($buffer))."\r\n$buffer\r\n";
}

ob_start('ob_chunked_gzhandler');

// First Chunk
echo "Hello World";
ob_flush();

// Second Chunk
echo ", Grand World";
ob_flush();

ob_end_clean();

// Terminating Chunk
echo "\x30\r\n\r\n";
ob_flush();
flush();

// Post Processing should not be displayed
for($i=0; $i<10; $i++) {
    print("Post-Processing");
    sleep(1);
}

귀하의 좋은 답변 덕분에 connection : close를 사용하는 것이 얼마나 어리 석고 불필요한 지 깨달았습니다. 일부는 서버의 기본 사항에 익숙하지 않은 것 같습니다.
Justin

@Justin 나는 이것을 오래 전에 썼다. 다시 살펴보면 청크를 4KB로 채워야 할 수도 있습니다. 일부 서버는 최소값에 도달 할 때까지 플러시되지 않는다는 것을 기억하는 것 같습니다.
skibulk

2

멀티 스레딩을 시도 할 수 있습니다.

시스템 호출을하는 스크립트를 작성할 수 있습니다. 매개 변수로 작업을 수행하는 스크립트와 함께 php 바이너리를 호출 shell_exec ) 스크립트를 작성할 수 있습니다. 하지만 이것이 가장 안전한 방법이라고 생각하지 않습니다. PHP 프로세스 및 기타 항목을 chrooting하여 항목을 허벅지로 만들 수 있습니다.

또는 http://www.phpclasses.org/browse/package/3953.html 을 수행하는 phpclasses에 클래스가 있습니다. 하지만 구현의 세부 사항을 모릅니다


프로세스가 완료 될 때까지 기다리지 않으려면 &캐릭터를 사용 하여 백그라운드에서 프로세스를 실행하십시오.
Liam

2

TL; DR 답변 :

ignore_user_abort(true); //Safety measure so that the user doesn't stop the script too early.

$content = 'Hello World!'; //The content that will be sent to the browser.

header('Content-Length: ' . strlen($content)); //The browser will close the connection when the size of the content reaches "Content-Length", in this case, immediately.

ob_start(); //Content past this point...

echo $content;

//...will be sent to the browser (the output buffer gets flushed) when this code executes.
ob_end_flush();
ob_flush();
flush();

if(session_id())
{
    session_write_close(); //Closes writing to the output buffer.
}

//Anything past this point will be ran without involving the browser.

기능 답변 :

ignore_user_abort(true);

function sendAndAbort($content)
{
    header('Content-Length: ' . strlen($content));

    ob_start();

    echo $content;

    ob_end_flush();
    ob_flush();
    flush();
}

sendAndAbort('Hello World!');

//Anything past this point will be ran without involving the browser.

1

PHP에서 병렬 프로그래밍을 수행하여 문제를 해결할 수 있습니다. 몇 주 전에 여기에서 질문했습니다. PHP 애플리케이션에서 멀티 스레딩을 어떻게 사용할 수 있습니까?

그리고 훌륭한 답변을 얻었습니다. 나는 특히 하나를 매우 좋아했습니다. 작가는 참조 만든 받는 PHP에서 쉽게 병렬 처리 (; johnlim에 의한 년 9 월 2008) 튜토리얼 나는 며칠 전 등장 유사한 문제를 해결하기 위해 이미 그것을 사용하는 것처럼 실제로 아주 잘 문제를 해결할 수 있습니다.


1

Joeri Sebrechts의 대답 은 비슷하지만 연결을 끊기 전에 버퍼링 될 수있는 기존 콘텐츠를 모두 파괴합니다. ignore_user_abort제대로 호출되지 않아 스크립트가 조기에 종료 될 수 있습니다. diyism의 대답 은 좋지만 일반적으로 적용 할 수 없습니다. 예를 들어, 그 대답이 처리하지 못하는 출력 버퍼가 더 많거나 적을 수 있으므로 상황에서 작동하지 않을 수 있으며 이유를 알 수 없습니다.

이 기능을 사용하면 언제든지 연결을 끊을 수 있으며 (헤더가 아직 전송되지 않은 경우) 지금까지 생성 한 콘텐츠를 유지할 수 있습니다. 추가 처리 시간은 기본적으로 무제한입니다.

function disconnect_continue_processing($time_limit = null) {
    ignore_user_abort(true);
    session_write_close();
    set_time_limit((int) $time_limit);//defaults to no limit
    while (ob_get_level() > 1) {//only keep the last buffer if nested
        ob_end_flush();
    }
    $last_buffer = ob_get_level();
    $length = $last_buffer ? ob_get_length() : 0;
    header("Content-Length: $length");
    header('Connection: close');
    if ($last_buffer) {
        ob_end_flush();
    }
    flush();
}

추가 메모리도 필요하면이 함수를 호출하기 전에 할당하십시오.


1

mod_fcgid 사용자를위한 참고 사항 (사용자의 책임하에 사용하십시오).

빠른 솔루션

Joeri Sebrechts의 대답 은 실제로 기능적입니다. 그러나 mod_fcgid 를 사용 하는 경우이 솔루션이 자체적으로 작동하지 않을 수 있습니다. 즉, flush 함수가 호출 될 때 클라이언트와의 연결이 닫히지 않습니다.

mod_fcgidFcgidOutputBufferSize구성 매개 변수가 원인 일 수 있습니다. 이 팁은 다음에서 찾았습니다.

  1. Travers Carter의이 답변
  2. Seumas Mackinnon의이 블로그 게시물 .

위의 내용을 읽고 나면 빠른 해결책이 줄을 추가하는 것이라는 결론에 도달 할 수 있습니다 (마지막의 "예제 가상 호스트"참조).

FcgidOutputBufferSize 0

Apache 구성 파일 (예 : httpd.conf), FCGI 구성 파일 (예 : fcgid.conf) 또는 가상 호스트 파일 (예 : httpd-vhosts.conf)에 있습니다.

위의 (1)에서 "OutputBufferSize"라는 변수가 언급되었습니다. 이것은 FcgidOutputBufferSize(2)에 언급 된의 이전 이름입니다 ( mod_fcgid에 대한 Apache 웹 페이지업그레이드 노트 참조 ).

세부 사항 및 두 번째 솔루션

위의 솔루션은 전체 서버 또는 특정 가상 호스트에 대해 mod_fcgid가 수행하는 버퍼링을 비활성화합니다 . 이로 인해 웹 사이트의 성능이 저하 될 수 있습니다. 반면에 PHP는 자체적으로 버퍼링을 수행하기 때문에 그렇지 않을 수 있습니다.

mod_fcgid 의 버퍼링 을 비활성화하지 않으 려면 다른 해결책 이 있습니다 . 이 버퍼를 강제로 플러시 할 수 있습니다 .

아래 코드는 Joeri Sebrechts가 제안한 솔루션을 기반으로합니다.

<?php
    ob_end_clean();
    header("Connection: close");
    ignore_user_abort(true); // just to be safe
    ob_start();
    echo('Text the user will see');

    echo(str_repeat(' ', 65537)); // [+] Line added: Fill up mod_fcgi's buffer.

    $size = ob_get_length();
    header("Content-Length: $size");
    ob_end_flush(); // Strange behaviour, will not work
    flush(); // Unless both are called !
    // Do processing here 
    sleep(30);
    echo('Text user will never see');
?>

추가 된 코드 줄이 본질적으로하는 일은 mod_fcgi 의 버퍼를 채우고 강제로 플러시하는 것입니다. 해당 지시문FcgidOutputBufferSize 에 대한 Apache 웹 페이지에 언급 된대로 변수 의 기본값 이 "65536" 이기 때문에 숫자 "65537"이 선택되었습니다 . 따라서 환경에 다른 값이 설정되어있는 경우 그에 따라이 값을 조정해야 할 수 있습니다.

내 환경

  • WampServer 2.5
  • Apache 2.4.9
  • PHP 5.5.19 VC11, x86, 비 스레드 세이프
  • mod_fcgid / 2.3.9
  • Windows 7 Professional x64

가상 호스트 예

<VirtualHost *:80>
    DocumentRoot "d:/wamp/www/example"
    ServerName example.local

    FcgidOutputBufferSize 0

    <Directory "d:/wamp/www/example">
        Require all granted
    </Directory>
</VirtualHost>

나는 많은 해결책을 시도했다. 그리고 이것은 mod_fcgid와 함께 작동하는 유일한 솔루션입니다.
Tsounabe

1

이것은 나를 위해 일했다

//avoid apache to kill the php running
ignore_user_abort(true);
//start buffer output
ob_start();

echo "show something to user1";
//close session file on server side to avoid blocking other requests
session_write_close();

//send length header
header("Content-Length: ".ob_get_length());
header("Connection: close");
//really send content, can't change the order:
//1.ob buffer to normal buffer,
//2.normal buffer to output
ob_end_flush();
flush();
//continue do something on server side
ob_start();
//replace it with the background task
sleep(20);

0

좋아, 기본적으로 jQuery가 XHR 요청을 수행하는 방식은 각 onreadystatechange에서 함수를 실행할 수 없기 때문에 ob_flush 메서드도 작동하지 않습니다. jQuery는 상태를 확인한 다음 수행 할 적절한 작업 (완료, 오류, 성공, 시간 초과)을 선택합니다. 참조를 찾을 수 없었지만 이것이 모든 XHR 구현에서 작동하지 않는다는 소식을 들었습니다. 내가 당신에게 효과가 있다고 생각하는 방법은 ob_flush와 forever-frame 폴링 사이의 교차입니다.

<?php
 function wrap($str)
 {
  return "<script>{$str}</script>";
 };

 ob_start(); // begin buffering output
 echo wrap("console.log('test1');");
 ob_flush(); // push current buffer
 flush(); // this flush actually pushed to the browser
 $t = time();
 while($t > (time() - 3)) {} // wait 3 seconds
 echo wrap("console.log('test2');");
?>

<html>
 <body>
  <iframe src="ob.php"></iframe>
 </body>
</html>

그리고 스크립트가 인라인으로 실행되기 때문에 버퍼가 플러시됨에 따라 실행됩니다. 이 기능을 유용하게 사용하려면 console.log를 기본 스크립트 설정에 정의 된 콜백 메서드로 변경하여 데이터를 받고 작업을 수행하십시오. 도움이 되었기를 바랍니다. 건배, 모건.


0

대체 솔루션은 작업을 대기열에 추가하고 새 작업을 확인하고 실행하는 cron 스크립트를 만드는 것입니다.

공유 호스트에 의해 부과 된 제한을 피하기 위해 최근에 그렇게해야했습니다. exec () 등은 웹 서버에서 실행되는 PHP에 대해 비활성화되었지만 셸 스크립트에서 실행할 수 있습니다.


0

flush()기능이 작동하지 않는 경우 . 다음 과 같이 php.ini 에서 다음 옵션을 설정해야합니다 .

output_buffering = Off  
zlib.output_compression = Off  

0

최신 작업 솔루션

    // client can see outputs if any
    ignore_user_abort(true);
    ob_start();
    echo "success";
    $buffer_size = ob_get_length();
    session_write_close();
    header("Content-Encoding: none");
    header("Content-Length: $buffer_size");
    header("Connection: close");
    ob_end_flush();
    ob_flush();
    flush();

    sleep(2);
    ob_start();
    // client cannot see the result of code below

0

이 스레드에서 많은 다른 솔루션을 시도한 후 (아무도 나를 위해 일하지 않은 후) 공식 PHP.net 페이지에서 솔루션을 찾았습니다.

function sendResponse($response) {
    ob_end_clean();
    header("Connection: close\r\n");
    header("Content-Encoding: none\r\n");
    ignore_user_abort(true);
    ob_start();

    echo $response; // Actual response that will be sent to the user

    $size = ob_get_length();
    header("Content-Length: $size");
    ob_end_flush();
    flush();
    if (ob_get_contents()) {
        ob_end_clean();
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.