본문 바로가기
IT 인터넷

[PHP] 파일 다운로드 구현

by zzom~ 2024. 9. 29.
반응형

  1. 업로드
    ●업로드된 파일은 microtime 함수로 파일이름을 바꾼다 
         참고 : ⓐ 스크립트가 실행될 염려가 없다. 
                ⓑ <img src="0.1234545345"> 같이 확장자가 꼭 gif, jpg가 아니더라도 이미지가 
                   이미지가 보이므로 이미지파일을 꼭 예외로 할필요는 없다. 
      ●is_uploaded_file()과  move_uploaded_file()을 사용한다. 
         참고 : ⓐ php매뉴얼에 사용된 함수들이다. 
                ⓑ move_uploaded_file()은 파일을 이동시키는 명령어이기때문에 파일을 카피하고 
                   임시파일을 지우는 명령보다 비용이 싸다. 
  2. 다운로드
    ●파일이름을 원상복구 시켜서 다운로드 시킨다. (원본파일이름은 디비에 저장되어있다) 
    ●download.php 파일을 만들어 파일을 다운로드 시켜준다. 
         참고 : ⓐ <a href=download.php?file_name=파일이름>파일받기</a> 이런형태로 다운로드 링크가 된다. 
                ⓑ 단 위의 방법에는 한가지 문제점이 있다. 주소창에 [download.php?file_name=../db/config.php] 
                   이런식으로 직접 쓰는경우에 보안에 중요한 파일이 유출될수 있다.               
                ⓒ 이를 해결하기 위해 "파일이름"이 정해준 디렉토리 안의 파일인지 검사하게 한다. 
                   (단순히 파일이름에 ".." 또는 "/"또는 "\"가 들어가지 못하게 하면된다)
  3.  다운로드 링크는...
    <a href="download.php?file_name=진짜파일이름&file_micro=마이크로타임으로변환된이름">다운로드</a> 
    이렇게 해주시면 됩니다. 
     

download.php 소스

<? 
require_once "lib.php"; 

// 접근경로 확인 
if (!eregi($_SERVER['HTTP_HOST'], $_SERVER['HTTP_REFERER'])) Error("외부에서는 다운로드 받으실수 없습니다."); 


// 다운로드 방식을 구한다. 
$ext = array_pop(explode(".", $_GET['file_name'])); 

if ($ext=="avi" || $ext=="asf")         $file_type = "video/x-msvideo"; 
else if ($ext=="mpg" || $ext=="mpeg")   $file_type = "video/mpeg"; 
else if ($ext=="jpg" || $ext=="jpeg")   $file_type = "image/jpeg"; 
else if ($ext=="gif")                   $file_type = "image/gif"; 
else if ($ext=="png")                   $file_type = "image/png"; 
else if ($ext=="txt")                   $file_type = "text/plain"; 
else if ($ext=="zip")                   $file_type = "application/x-zip-compressed"; 

// 실제로 다운로드 받는다. 
$ret = download_file( $_GET['file_name'], $_GET['file_micro'], "여기에 파일이 있는 디렉토리를 쓴다.", $file_type); 

if( $ret == 1 ) Error("지정하신 파일이 없습니다."); 
if( $ret == 2 ) Error("접근불가능 파일입니다. 정상 접근 하시기 바랍니다."); 
?>

 

lib.php 소스

<? 
//========================================================================================= 
//  파일 업로드 함수 
// 
//  파라미터 
//    $upload_dir     : 업로드 드렉토리 
//    $tmp_file       : 서버로 업로드된 임시 파일 
//    $file_name_plus : 관리를 위해 파일앞에 붙여주는 문자열 
// 
//  리턴값 
//    파일저장에 성공햇을겨우 바꾸어진 파일 이름을 넘긴다. 
//    실패할경우 널문자를 넘긴다. 
//========================================================================================= 
function upload_file($upload_dir, $tmp_file, $file_name_plus="" ) 
{ 
        // 파일이름을 시간으로 바꿔서 php등으 스크립트 언어가 실행되지 못하게한다. 
        $new_file_name = microtime(); 


        // 파일이름이 겹친다면 (마이크로 타임으로 바꾸었기 때문에 이럴일은 거의 없다.) 
        // 파일 확장자 전에 '_i' 를  붙인다. (i는 임의의숫자) 
        $old_new_file_name = $new_file_name; 
        for( $i=0; file_exists( $upload_dir.$new_file_name ); $i++ ) 
                $new_file_name = $old_new_file_name."_".$i; 


        // 관리를 쉽게하기위해 file_name_plus를 앞에 달아준다. 
        $new_file_name = $file_name_plus.$new_file_name; 

        //빈칸을 없앤다. 
       $new_file_name = str_replace(" ","_", $new_file_name); 

        // 임시디렉토리에서 지정디렉토리로 파일을 옴긴다. 
        if( is_uploaded_file( $tmp_file ) ) 
                move_uploaded_file( $tmp_file, $upload_dir.$new_file_name ); 
        else return ""; 

        return $new_file_name; 
} 


//========================================================================================= 
//  이름 바꿔 다운로드하기 
// 
//  파라미터 
//    $file_name  : 실제파일이름 
//    $file_dir   : 파일의 위치 
//    $file_micro : 바뀐 파일 이름명 
//    $file_type  : 파일의 다운로드 방식, 비워두면 일반 파일이다. 
//                                    - 동영상  : video/mpeg, video/x-msvideo 
//                                    - 이미지  : image/jpeg, image/gif, image/png 
//                                    - Zip파일 : application/x-zip-compressed 
//                                    - txt파일 : text/plain 
//  리턴값 
//          완료했을 경우 0을 리턴한다. 
//          다운로드 파일이 없으면 요청시 1을 리턴한다. 
//          해킹시도등 잘못된 파일 요청시 2을 리턴한다. 
//========================================================================================= 
function download_file($file_name, $file_micro, $file_dir, $file_type ) 
{ 
        // 읽어올 파일명에 이상이있는지 검사한다. 
        if( !$file_name || !$file_micro || !$file_dir ) return 1; 
        if( eregi( "\\\\|\.\.|/", $file_micro ) ) return 2; 


        if( file_exists($file_dir.$file_micro) ) 
        { 
                $fp = fopen($file_dir.$file_micro,"r"); 

                if( $file_type ) 
                { 
                        header("Content-type: $file_type"); 
                        Header("Content-Length: ".filesize($file_dir.$file_micro));     
                        Header("Content-Disposition: attachment; filename=$file_name");   
                        Header("Content-Transfer-Encoding: binary"); 
                        header("Expires: 0"); 
                } 
                else 
                { 
                        if(eregi("(MSIE 5.0|MSIE 5.1|MSIE 5.5|MSIE 6.0)", $HTTP_USER_AGENT)) 
                        { 
                                Header("Content-type: application/octet-stream"); 
                                Header("Content-Length: ".filesize($file_dir.$file_micro));     
                                Header("Content-Disposition: attachment; filename=$file_name");   
                                Header("Content-Transfer-Encoding: binary");   
                                Header("Expires: 0");   
                        } 
                        else 
                        { 
                                Header("Content-type: file/unknown");     
                                Header("Content-Length: ".filesize($file_dir.$file_micro)); 
                                Header("Content-Disposition: attachment; filename=$file_name"); 
                                Header("Content-Description: PHP3 Generated Data"); 
                                Header("Expires: 0"); 
                        } 
                } 


                fpassthru($fp); 
                fclose($fp); 
        } 
        else return 1; 
} 

//========================================================================================= 
//  파일 삭제하기 
// 
//  파라미터 
//    $file_name  : 실제파일이름 
//    $file_dir   : 파일의 위치 
// 
//  리턴값 
//          완료했을 경우 0을 리턴한다. 
//          삭제할 파일이 없으면 요청시 1을 리턴한다. 
//          해킹시도등 잘못된 파일 요청시 2을 리턴한다. 
//    파일이 존재하지만 지울수 없는겨우 3을 리턴한다. 
//========================================================================================= 
function delete_file($file_name, $file_dir ) 
{ 
        // 읽어올 파일명에 이상이있는지 검사한다. 
        if( !$file_name || !$file_dir ) return 1; 
        if( eregi( "\\\\|\.\.|/", $file_name ) ) return 2; 

        // 파일이 있나 검사. 
        if( !file_exists($file_dir.$file_micro) ) return 1; 

        // 있는데 못지웠을 경우 
        if( !unlink() ) return 3; 

        return 0; 
} 
?>

 

훨씬 더 확장되거나 기능 많은 소스들도 존재하겠지만

위 소스는 기본적인 내용으로 추가/수정하여 사용하면 될듯하다.(특히 구버전 PHP에서 유용)

반응형