파일 업로드 관련으로 Javascript 와 jQuery 를 검색하고 필요한 것을 추가/수정해서 작성했다.

파일 중복 체크를 안하려고 파일명을 rename 처리했다.

$rename = md5(uniqid($tmpname)) .round(microtime(true)).'.'.$fileExt;


파일 테스트 환경 : Windows10 AutoSet9, Linux CentOS 6.5


테스트에 사용한 첨부파일

fileupload-01.zip



=== fileform.php ===

<!DOCTYPE html>
<html>
<head>
<title>Multiple File Upload with PHP</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="css/pure-min.css">
<link rel="stylesheet" type="text/css" href="css/fileupload.css">
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<!-- javascript dependencies -->
<script type="text/javascript" src="js/jquery.form.min.js"></script>
<!-- main script -->
<script type="text/javascript" src="js/fileupload.js"></script>
<script type="text/javascript">
    function viewFileList() {
        var input = document.getElementById("files");
        var ul = document.getElementById("fileList");
        while (ul.hasChildNodes()) {
            ul.removeChild(ul.firstChild);
        }
        for (var i = 0; i < input.files.length; i++) {
            var li = document.createElement("li");
            li.innerHTML = input.files[i].name;
            ul.appendChild(li);
        }
        if(!ul.hasChildNodes()) {
            var li = document.createElement("li");
            li.innerHTML = 'No Files Selected';
            ul.appendChild(li);
        }
    }
</script>
</head>
<body>
<div class="container">
    <div class="status"></div>
    <form id="form" action="fileupload.php" method="post" enctype="multipart/form-data" >
        <input type="file" id="files" name="files[]" multiple="multiple" onChange="viewFileList();" />
        <input type="submit" value="Upload" class="pure-button" />
    </form>
    <ul id="fileList"><li>No Files Selected</li></ul>
    <div class="progress">
        <div class="bar"></div>
        <div class="percent">0%</div>
    </div>

</div><!-- end .container -->

</body>
</html>


=== fileupload.js ===

$(document).ready(function() {
    $('#form').submit(function(){
        var numFiles = $("input:file", this)[0].files.length;
        if(numFiles == 0){
            alert('선택된 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }
    });
});


=== fileupload.php ===

<?php
// Edit upload location here
$valid_formats = array("jpg", "png", "gif", "bmp");
$max_file_size = 1024*100; //100 kb
$upload_path='uploads/';
$count = 0;
if(isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST"){
    foreach ($_FILES['files']['name'] as $i => $name) {
        if ($_FILES['files']['error'][$i] == 4) { // 파일이 전송되지 않았습니다
            continue;
        }
        if ($_FILES['files']['error'][$i] == 0) { // 오류 없이 파일 업로드 성공
            if ($_FILES['files']['size'][$i] > $max_file_size) {
                $message[] = "$name is too large!.";
                continue;
            }elseif( ! in_array(pathinfo($name, PATHINFO_EXTENSION), $valid_formats) ){
                $message[] = "$name 은 허용된 파일 포멧이 아닙니다";
                continue;
            }else{ // 에러가 없으면
                $tmpname = $_FILES['files']['tmp_name'][$i];
                $realname = $_FILES['files']['name'][$i];
                $filesize = $_FILES['files']['size'][$i];
                $fileExt = getExt($realname);
                $rename = md5(uniqid($tmpname)) .round(microtime(true)).'.'.$fileExt;
                $uploadFile = $upload_path . $rename;
                if(move_uploaded_file($tmpname, $uploadFile)){
                    @chmod($readFile,0606);

                    // DB 테이블에 저장하는 루틴은 여기에 추가하면 된다.

                    $count++; // 업로드 성공한 파일 숫자
                }
            }
        }
    }
}

echo $count;
?>

<script type="text/javascript">
var count ='<?php echo $count;?>';
alert('업로드 성공 파일수 : ' + count );
setTimeout(function() {
    window.location.replace("fileform.php");
}, 1000);
</script>

<?php
// 확장자 추출 함수
function getExt($filename){
    $ext = substr(strrchr($filename,"."),1);
    $ext = strtolower($ext);
    return $ext;
}
?>



파일 업로드 / 다운로드 취약점
- 업로드 기능에서 파일 사이즈의 제한을 주지 않을 경우
- 파일 타입의 체크가 없는 경우
- 파일이 업로드 되는 경로가 외부에서 직접적으로 접근 가능하거나 실행 권한을 가지게 되는 경우


파일 업로드할 때 @chmod($readFile,0606); 를 하는 이유를 좀 더 알고자 한다면

http://www.macinstruct.com/node/415 에 나오는 그림을 보면 도움된다.

업로드라 함은 파일을 서버에 쓰는(write)하는 것이다.

그러므로 파일을 read(4) + write(2) 권한만 부여하면 된다. 파일을 실행할 수 있게 하면 보안상에 문제가 될 수도 있다. 그래서 업로드한 파일을 읽기와 쓰기 권한만 부여했다.


보안을 위해서 몇가지 더 권고하는 걸 적어둔다.

- 업로드한 파일을 외부에서 접근할 수 없는 경로에 저장한다.

  즉 Web 서버 URL 밖에다가 저장하도록 하는 것이 좋다.

- 업로드한 파일에 대한 웹서버의 실행권한을 제거하고 저장한다.

- 업로드한 파일의 저장 경로와 파일명을 외부에서 알 수 없도록 한다.

  실제 저장되는 파일명은 난수를 이용해 유추 불가능하도록 생성하여 외부로부터 직접적인 접근이 불가능하게 구현한다.

  업로드한 파일을 위한 전용 디렉토리를 생성하여 실행권한을 제거한다.


참고

파일 업로드에 대한 개념 설명이 잘된 URL

http://blog.habonyphp.com/entry/php-POST-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C#.WHWm81z3TFA


728x90
블로그 이미지

Link2Me

,

jQuery 팝업창에서 부모창으로 값을 전달해야 할 때 사용하는 방법이다.


=== 부모창 ===

<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script language='javascript'>
$(document).ready(function() {
    $('#pay').submit(function() {
        window.open('', 'payviewer', 'width=400,height=400,resizeable,scrollbars');
        this.action = 'popup.php';
        this.method = 'POST';
        this.target = 'payviewer';
    });
});
</script>

<form id="pay" >
    <input type="hidden" name="var" value="POST DATA SENT">
    <input type="text" name="name" id="name" value="홍길동">
    <input type="submit" value="결제하기">
</form>


=== 자식창 : popup.php ===

<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script language='javascript'>
$(document).ready(function() {
    $('#payreturn').submit(function() {
        var name = $("input[name='name']").val(); // 현재 폼의 입력값
        $("input[name='name']",opener.document).val(name); // 값 전달 방식 1
        //$(opener.document).find("#name").val(name); // 값 전달 방식 2

        //$("#name",opener.document).val(name); // 값 전달방식 3
        window.self.close(); // 현재 팝업 닫기
    });
});
</script>

<p><?php echo($_POST['var']); ?></p>
<form id="payreturn" >
    <input type="text" name="name" value="<?php echo($_POST['name']); ?>">
    <input type="submit" value="확인">
</form>


위 샘플코드의 파일

popup.zip



$("input[name='name']",opener.document).val(name);는 부모창의 id를 지정하지 않았어도 값을 변경할 수 있다.

$(opener.document).find("#name").val(name); 는 부모창의 id를 직접 찾아서 값을 변경한다.


jQuery 자식 팝업 창에서 부모창 컨트롤
$(opener.document).find("#Form").attr("action","index.do").submit();

// 팝업창에서 부모창 함수 호출

opener.location.href="javascript:fun();"; //일반적인 방법

$(opener.location).attr("href","javascript:부모스크립트함수명();"); //jQuery 이용
$(opener.location).attr("href","javascript:fun();"); //jQuery 이용


// 부모창의 필드값 가져오기

1. 일반적인 방법
var parentValue = opener.document.getElementById("parentId").value;
2. jQuery를 이용한 방법
$("#parentId", opener.document).val();
3. find를 이용한 방법
$(opener.document).find("#parentId").val();


//팝업창에서 부모창 새로고침(새로고침 의사 표현을 묻는 창이 뜸)
window.opener.parent.location.reload();
window.opener.document.location.reload();


// 작은 윈도우 창을 열어서(window.open) 특정 작업을 처리한 후 부모창(opener)을 refresh하는 방법

// window.opener.location.reload(); 에서 window는 생략 가능

<script>
opener.location.reload();
window.close();
</script>


//팝업창 자신 페이지 새로고침
document.location.reload();

//팝업창 닫기
window.self.close();


// 부모창의 URL을 대체시킨다.

opener.location.replace("URL정보");


// 전체 창에서 새 페이지 열기

top.location.href="abc.php";


// 연 창의 URL 이동

opener.location.href="abc.php";


<script type="text/javascript">
  alert("회원가입을 하시겠습니까?")
  location.href= "member.php"
</script>


728x90
블로그 이미지

Link2Me

,

form 데이터를 window 팝업창으로 값을 전달하여 open 해야 할 필요가 있을 때 사용하는 방법이다.


<form action="popup.php" method="post" target="payviewer" onsubmit="window.open('popup.php', 'payviewer', 'width=200, height=200,resizeable,scrollbars');">
    <input type="hidden" name="var" value="POST DATA SENT">
    <input type="submit" value="결제하기" >
</form>


=== popup.php ===

<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Receiver popup</title>
</head>
<body>
<p><?php echo($_POST['var']); ?></p>
</body>
</html>


위와 같은 방법을 jQuery 로 전달하는 방법이다.

<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<script language='javascript'>
$(document).ready(function() {
    $('#pay').submit(function() {
        window.open('', 'payviewer', 'width=200,height=200,resizeable,scrollbars');
        this.target = 'payviewer';
    });
});
</script>

<form id="pay" action="popup.php" method="post" >
    <input type="hidden" name="var" value="POST DATA SENT">
    <input type="submit" value="결제하기">
</form>


이걸 더 수정해보자.

바로 위 코드와 아래 코드가 어떻게 다른지 확인이 될 것이다.

정보를 어떻게 전달하는지를 알 수 있다.


<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<script language='javascript'>
$(document).ready(function() {
    $('#pay').submit(function() {
        window.open('', 'payviewer', 'width=200,height=200,resizeable,scrollbars');
        this.action = 'popup.php';
        this.method = 'POST';
        this.target = 'payviewer';
    });
});
</script>

<form id="pay" >
    <input type="hidden" name="var" value="POST DATA SENT">
    <input type="submit" value="결제하기">
</form>




728x90
블로그 이미지

Link2Me

,