본문 바로가기

카테고리 없음

PHP) 파일 업로드&다운로드 개선하기

기존에 만들었던 파일 업로드 기능은 웹서버의 디렉토리에 직접 저장하는 방식을 택했다.

이 방법은 근본적으로 파일 업로드 취약점이나 다운로드 취약점을 발생시킨다.

이를 방지하기 위해서는 다양한 방법이 있겠지만 DB를 이용한 방법을 선택했다.

참고로 디자인은 바뀐 것이 없다. 다만 그 안의 로직이 변경되었다.

 

또한 DB내에 새로운 테이블을 생성해야한다.

다음과 같이 테이블을 생성한다.

새로운 테이블

-fileUpload.php

<?php
if(!isset($_FILES['file'])) //파일이 선택되지 않았을 경우 
{
    echo '<p>Please select a file</p>';
}
else
{
    try   
    {
        upload();
    }catch(Exception $e)
    {
        echo '<h4>'.$e->getMessage().'</h4>';
    }
}

function upload(){
    if(is_uploaded_file($_FILES['file']['tmp_name']))
    {
    //파일이 업로드되었는지 확인한다. 
        $size = getimagesize($_FILES['file']['tmp_name']);
        $type = $size['mime'];
        $imgfp = fopen($_FILES['file']['tmp_name'], 'rb');
        $size = $size[3];
        $name = $_FILES['file']['name'];
        $maxsize = 99999999; // 최대 파일 사이즈

        if($_FILES['file']['size'] < $maxsize ) //파일 사이즈가 최대 사이즈보다 클 경우
        {
            $dbh = new PDO("mysql:host=127.0.0.1;dbname=post" ,$user, $pass);
            $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $stmt = $dbh->prepare("INSERT INTO testblob (image_type ,image, image_size, image_name) VALUES (? ,?, ?, ?)");

            $stmt->bindParam(1, $type);
            $stmt->bindParam(2, $imgfp, PDO::PARAM_LOB);
            $stmt->bindParam(3, $size);
            $stmt->bindParam(4, $name);
            $stmt->execute();
        }
        else
        {
            throw new Exception("File Size Error");
        }
    }
    else
    {
        throw new Exception("Unsupported Image Format!");
    }
}
?>
<script>
   history.back();
</script>

파일이 업로드되는 로직은 위와 같이 변경되었다.

위와 같이 코드를 작성하면 DB 내에 파일이 저장된다.

 

-FIleDownload.php

<?php
try{
    $id = $_GET['id'];

    $dbh = new PDO("mysql:host=127.0.0.1;dbname=post" ,$user, $pass);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $sql = "SELECT * FROM testblob WHERE image_id=$id";


    $stmt = $dbh->prepare($sql);
    $stmt->execute();

    $stmt->setFetchMode(PDO::FETCH_ASSOC);
    $array = $stmt->fetch();
	

    header("Content-type:".$array['image_type']);
    header("Content-Disposition: attachment; filename=".$array['image_name']."");
    ob_clean();
    flush();
    echo $array['image'];
}
catch(PDOException $e)
{
    echo $e->getMessage();
}
catch(Exception $e)
{
    echo $e->getMessage();
}
?>

파일을 DB내에서 검색하여 불러온다. 다운로드도 사실상 크게 달라진것은 없다.

 

이제 정상적으로 동작하는지 확인해봐야한다.

기본

위와 같은 테스트 페이지에 파일을 업로드하고 다운로드가 가능한지 시험해본다.

업로드
다운로드

파일이 정상적으로 업/다운로드가 되는것을 확인했다.