'2018/06/13'에 해당되는 글 3건

728x90

회원가입폼과 기가입여부를 체크하는 기능이 포함된 Form 예제다.

jQuery, Ajax 를 사용하여 입력 필드 체크와 휴대폰번호 및 비밀번호 유효성 검사, 이미 가입된 ID인지 여부를 체크하는 기능, 회원가입 자료 저장, 로그인 처리 기능이 포함되어 있다.

첨부파일에는 테이블 구조 SQL 까지 포함되어 있으므로 윈도우 기반 Autoset9 에서 직접 테스트해볼 수 있다.


간략하게 사용법 순서를 적어보면....

1. 테이블 구조 SQL 문을 autoset9 에서 테이블 생성한다.

    members 테이블과 member_data 테이블 두개의 테이블로 나누었고 PHP에서 JOIN 으로 데이터를 처리한다.

 CREATE TABLE IF NOT EXISTS `members` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `userID` varchar(50) NOT NULL DEFAULT '',
  `userNM` varchar(20) NOT NULL,
  `passwd` varchar(80) NOT NULL,
  `salt` varchar(10) NOT NULL,
  `admin` tinyint(2) NOT NULL DEFAULT '0',
  `phoneSE` varchar(80) DEFAULT NULL,
  `OStype` tinyint(2) NOT NULL DEFAULT '0',
  `regdate` char(14) NOT NULL DEFAULT '',
  `curdate` char(14) DEFAULT NULL COMMENT '최근접속',
  PRIMARY KEY (`uid`),
  UNIQUE KEY `userID` (`userID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

 CREATE TABLE IF NOT EXISTS `member_data` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `relateduid` int(11) NOT NULL DEFAULT '0',
  `level` int(11) NOT NULL DEFAULT '0',
  `userNM` varchar(60) NOT NULL COMMENT '이름',
  `email` varchar(60) NOT NULL COMMENT '메일',
  `mobileNO` varchar(20) NOT NULL,
  `officeNO` varchar(20) DEFAULT NULL,
  `homeNO` varchar(20) DEFAULT NULL,
  `home_addr1` varchar(100) DEFAULT NULL,
  `home_addr2` varchar(50) DEFAULT NULL,
  `office_addr1` varchar(100) DEFAULT NULL,
  `office_addr2` varchar(50) DEFAULT NULL,
  `sex` tinyint(2) NOT NULL DEFAULT '0',
  `point` int(11) NOT NULL DEFAULT '0',
  `smart` tinyint(2) NOT NULL DEFAULT '0',
  `modifydate` char(14) NOT NULL DEFAULT '',
  PRIMARY KEY (`uid`),
  KEY `relateduid` (`relateduid`),
  KEY `mobileNO` (`mobileNO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


2. 회원가입 폼

    - E-Mail 을 userID 로 사용하고 가입여부를 체크하는 중복체크 jQuery가 포함되어 있다.

    - E-Mail 주소 유효성 체크 기능이 포함되어 있다.

    - 휴대폰 번호 유효성 체크 기능이 포함되어 있다.

    - 비밀번호는 영문, 숫자, 특수문자 등을 혼용하여 가입하도록 했다.



3. 회원가입 처리 로직은 직접 구현해보도록 하여 입력값이 넘어오는지 여부만 체크하는 걸 주석처리했다.

    회원가입 결과를 확인할 수 있도록 내용을 수정 보완했다.

4. LoginForm.php 에서는 로그인 화면을 구현했다.

    로그인 체크 jQuery 와 Ajax 처리하는 걸 추가했다.

5. 회원가입/로그인이 성공하면 index.php 에서 SESSION을 검사하여 main.php 파일로 이동하도록 했다.


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="form.css"  />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
    // 회원가입처리
    $("form").submit(function(){
        var userNM = $("input[name='userNM']");
        if( userNM.val() =='') {
            alert("성명을 입력하세요");
            userNM.focus();
            return false;
        }

        var email = $("input[name='email']");
        if(email.val() == ''){
            alert('이메일을 입력하세요');
            email.focus();
            return false;
        } else {
            var emailRegex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
            if (!emailRegex.test(email.val())) {
                alert('이메일 주소가 유효하지 않습니다. ex)abc@gmail.com');
                email.focus();
                return false;
            }
        }

        var mobileNO = $("input[name='mobileNO']");
        if(mobileNO.val() ==''){
            alert('휴대폰 번호를 입력하세요');
            mobileNO.focus();
            return false;
        } else if(!/^[0-9]{10,11}$/.test(mobileNO.val())){
            alert("휴대폰 번호는 숫자만 10~11자리 입력하세요.");
            return false;
        } else if(!/^(01[016789]{1}|02|0[3-9]{1}[0-9]{1})([0-9]{3,4})([0-9]{4})$/.test(mobileNO.val())){
            alert("유효하지 않은 전화번호 입니다.");
            return false;
        }

        var password = $("input[name='Password']");
        var repassword = $("input[name='rePassword']");
        if(password.val() =='') {
            alert("비밀번호를 입력하세요!");
            password.focus();
            return false;
        }
        if(password.val().search(/\s/) != -1){
            alert("비밀번호는 공백없이 입력해주세요.");
            return false;
        }
        if(!/^[a-zA-Z0-9!@#$%^&*()?_~]{8,20}$/.test(password.val())){
            alert("비밀번호는 숫자, 영문, 특수문자(!@$%^&*?_~ 만 허용) 조합으로 8~20자리를 사용해야 합니다.");
            return false;
        }
        // 영문, 숫자, 특수문자 2종 이상 혼용
        var chk=0;
        if(password.val().search(/[0-9]/g) != -1 ) chk ++;
        if(password.val().search(/[a-z]/ig)  != -1 ) chk ++;
        if(password.val().search(/[!@#$%^&*()?_~]/g) != -1) chk ++;
        if(chk < 2){
            alert("비밀번호는 숫자, 영문, 특수문자를 두가지이상 혼용하여야 합니다.");
            return false;
        }
        // email이 아닌 userID 인 경우에는 체크하면 유용. email은 특수 허용문자에서 걸러진다.
        /*
        if(password.val().search(userID.val())>-1){
            alert("userID가 포함된 비밀번호는 사용할 수 없습니다.");
            return false;
        }
        */
        if(repassword.val() =='') {
            alert("비밀번호를 다시 한번 더 입력하세요!");
            repassword.focus();
            return false;
        }
        if(password.val()!== repassword.val()){
            alert('입력한 두 개의 비밀번호가 일치하지 않습니다');
            return false;
        }

    });

    // userID(e-mail) 가입여부 검사
    $("#checkid").click(function(e){
        e.preventDefault();
        var email = $("input[name='email']");
        if(email.val() == ''){
            alert('이메일을 입력하세요');
            email.focus();
            return false;
        } else {
            var emailRegex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
            if (!emailRegex.test(email.val())) {
                alert('이메일 주소가 유효하지 않습니다. ex)abc@gmail.com');
                email.focus();
                return false;
            }
        }

        $.ajax({
            url: 'a.joinChk.php',
            type: 'POST',
            data: {userID:email.val()},
            dataType: "json",
            success: function (msg) {
                //alert(msg); // 확인하고 싶으면 dataType: "text" 로 변경한 후 확인 가능
                if(msg.result == 1){
                    alert('사용 가능합니다');
                } else if(msg.result == 0){
                     alert('이미 가입된 아이디입니다');
                    email.val('');
                }
            },
            error: function(jqXHR, textStatus, errorThrown){
                alert("arjax error : " + textStatus + "\n" + errorThrown);
            }
        });
    });

});
</script>
</head>
<body>
<div class="container">
<h2>회원가입 Form 예제</h2>
<form method="post" action="a.register.php">
    <table>
        <tr>
            <td style='width:100px'>이름</td>
            <td><input type="text" size=37 name="userNM" value=""></td>
        </tr>
        <tr>
            <td>E-Mail</td>
            <td>
                <input type="text" size=25 name="email" value="">
                <input type="button" id="checkid" value="중복체크">
            </td>
        </tr>
        <tr>
            <td>휴대폰번호</td>
            <td><input type="text" size=37 name="mobileNO" value=""></td>
        </tr>
        <tr>
            <td>비밀번호</td>
            <td><input type="password" size=37 name="Password"></td>
        </tr>
        <tr>
            <td>비밀번호(확인)</td>
            <td><input type="password" size=37 name="rePassword"></td>
        </tr>
        <tr>
            <td colspan='2' align='center'><input type="submit" value="회원가입"></td>
        </tr>
    </table>
</fom>
</div>
</body>
</html>

 body {    
    font-family: 나눔바른고딕, NanumBarunGothic, 맑은고딕, "Malgun Gothic", 돋움, Dotum, "Apple SD Gothic Neo", sans-serif;
    font-size: 12px;
    color: rgb(33, 33, 33);
    letter-spacing: 0.03em;
}

table {
    width: 600px;
}

tr {
    height: 50px;
}

input[type=text], input[type=password] {
    padding: 5px 10px; /* 상하 우좌 */
    margin: 3px 0; /* 상하 우좌 */
    font-family: inherit; /* 폰트 상속 */
    border: 1px solid #ccc; /* 999가 약간 더 진한 색 */
    font-size:14pt;
    box-sizing: border-box;
    border-radius: 3px;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    -webkit-transition: width 0.4s ease-in-out;
    transition: width 0.4s ease-in-out;
}

input[type=text]:focus, input[type=password]:focus {
    border: 2px solid #555;
}

input[type=submit],input[type=button] {
    margin-top: 10px;
    width:100px;
    height:40px;
    line-height: 22px;
    padding: 5px, 10px; /* 상하 우좌 */
    background: #E6E6E6;
    color: #000000;
    font-size: 15px;
    font-weight: normal;
    letter-spacing: 1px;
    border: none;
    cursor: pointer;
    border-radius: 3px;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
}

input[type=submit]:hover {
    background-color: #FFBF00;
}

 <?php
// 파일을 직접 실행하면 동작되지 않도록 하기 위해서
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST); // $_POST['loginID'] 라고 쓰지 않고, $loginID 라고 써도 인식되게 함
    // db 접속파일 include 및 정상 로그인 여부 체크하는 함수 실행후 결과 반환처리 하면 된다.
    include_once 'dbController.php'; // http://link2me.tistory.com/1478 참조
    require_once 'loginClass.php';
    $c = new LoginClass();
    $rs = $c->isUserExisted($userID);
    if($rs == '0'){
        echo '{"result":"1"}';
    } else {
        echo '{"result":"0"}'; // echo json_encode(array('result' => '0')); 과 동일
    }
}
?>

<?php
// 파일을 직접 실행하면 동작되지 않도록 하기 위해서
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST); // $_POST['loginID'] 라고 쓰지 않고, $loginID 라고 써도 인식되게 함
    echo '<pre>';print_r($_POST);echo '</pre>';
}
?>


LoginClass 함수 만든 예제다.

<?php
class LoginClass extends DBController {
    // 회원 가입 여부 체크
    public function isUserExisted($u) {
        if(!isset($u) || empty($u)) {
            return '-1';
        } else {
            $sql ="SELECT count(userID) from members WHERE userID='".$u."'";
            $result = mysqli_query($this->db, $sql);
            if($row = mysqli_fetch_array($result)){
                return $row[0]; // 미가입이면 0 반환, 가입이면 1 반환
            } else {
                return -1;
            }
        }
    }

}//end class LoginClass

?> 


직접 테스트해보고 싶은 개발자의 타이핑 노고를 덜어주고자 테스트한 파일을 첨부한다.

Last Update : 2019.04.12 첨부파일 내용 보강(초보자를 위한 배려)


ex02.zip


https://link2me.tistory.com/1481 읽어보고 첨부된 예제를 받아서 분석하고 이해하면 많은 도움이 될 것이다.


도움되신 분은 공감 팍팍 눌러주세요.

블로그 이미지

Link2Me

,
728x90

PHP 에서 내용을 다른 파일로 전달하는 방법으로 가장 기본 예제가 로그인 예제다.

네이버 지식인에 올라오는 공통적인 질의사항에 대한 개념이해를 돕기 위함이다.

HTML5 기반 jQuery 입력 필드 체크, 모바일 환경을 고려했다.

<meta name="viewport" content="width=device-width, initial-scale=1"> 이 부분이 모바일 환경을 고려한 부분이다.

bootstrap 폼 예제는 아니다. 기본 Form 에 대한 이해를 하고 나면 bootstrap Form으로 변경하는 것도 쉽다.

Form 을 작성하려면 <form> 태그를 사용한다.

<form> 태그는 두가지 주요 속성을 가진다.

- action 속성 : 어디에 데이터를 보낼지의 URL을 지정

- method 속성 : 어떻게 데이터를 전송할지의 방법을 지정. method 속성값에는 POST와 GET의 두가지 방법이 있다.


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="form1.css"  />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
    $("form").submit(function(){
        var loginID = $("input[name='loginID']").val();
        var loginPW = $("input[name='loginPW']").val();

        if( loginID =='') {
            alert("아이디를 입력하세요");
            $("input[name='loginID']").focus();
            return false;
        }

        if(loginPW =='') {
            alert("패스워드를 입력하세요!");
            $("input[name='loginPW']").focus();
            return false;
        }
    });
});
</script>
</head>
<body>
<div class="container">
<h2>Form 예제1</h2>
<form method="post" action="form.action.php">
    <table>
        <tr>
            <td>로그인 ID</td>
            <td><input type="text" name="loginID" value=""></td>
        </tr>
        <tr>
            <td>패스워드</td>
            <td><input type="password" name="loginPW"></td>
        </tr>
        <tr>
            <td colspan='2' align='center'><input type="submit" value="전송"></td>
        </tr>
    </table>
</fom>
</div>
</body>
</html>

 body {    
    font-family: 나눔바른고딕, NanumBarunGothic, 맑은고딕, "Malgun Gothic", 돋움, Dotum, "Apple SD Gothic Neo", sans-serif;
    font-size: 12px;
    color: rgb(33, 33, 33);
    letter-spacing: 0.03em;
}

table {
    width: 300px;
}

tr {
    height: 50px;
}

input[type=text], input[type=password] {
    width: 100%;
    padding: 5px 10px; /* 상하 우좌 */
    margin: 3px 0; /* 상하 우좌 */
    font-family: inherit; /* 폰트 상속 */
    border: 1px solid #ccc; /* 999가 약간 더 진한 색 */
    font-size:14pt;
    box-sizing: border-box;
    border-radius: 3px;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    -webkit-transition: width 0.4s ease-in-out;
    transition: width 0.4s ease-in-out;
}

input[type=text]:focus, input[type=password]:focus {
    border: 2px solid #555;
}

input[type=submit] {
    margin-top: 10px;
    width:100px;
    height:40px;
    line-height: 22px;
    padding: 5px, 10px; /* 상하 우좌 */
    background: #E6E6E6;
    color: #000000;
    font-size: 15px;
    font-weight: normal;
    letter-spacing: 1px;
    border: none;
    cursor: pointer;
    border-radius: 3px;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
}

input[type=submit]:hover {
    background-color: #FFBF00;
}

<?php
// 파일을 직접 실행하면 동작되지 않도록 하기 위해서
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST); // $_POST['loginID'] 라고 쓰지 않고, $loginID 라고 써도 인식되게 함
    // POST 배열로 넘어온 값 확인 목적
    echo '<pre>';print_r($_POST);echo '</pre>';
    // db 접속파일 include 및 정상 로그인 여부 체크하는 함수 실행후 결과 반환처리 하면 된다.

    $ref = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:'';
    // 만약 사용자가 이전 페이지의 링크를 거치지 않고 브라우저에 URL을 직접 입력하여 접속한 경우는 ''
} else { // 비정상적인 접속인 경우
    echo 0; // form.action.php 파일을 직접 실행할 경우에는 화면에 0을 찍어준다.
    exit;
}
?>


클라이언트에서 Javascript 로 검증하고 있으면 서버에서 재검증할 필요가 없다고 생각할 수도 있지만 이것은 크게 잘못된 생각이다. 공격자는 모든 요청을 자유롭게 서버에 전송할 수 있으므로, Javascript에서의 검증을 쉽게 빠져나갈 수 있다.


만약 사용자가 이전 페이지의 링크를 거지치 않고 직접 접속한 경우에는 브라우저에 URL을 직접 입력하여 접속한 경우에는 참조원 정보뿐만아니라 $_SERVER['HTTP_REFERER'] 도 없다.


테스트한 파일을 첨부한다.

form-01.zip


블로그 이미지

Link2Me

,
728x90

PHP 에서 MySQL 접속 dbController Class 만드는 코드다.

절차지향방식의 생성자, 소멸자 만드는 방법과 class MySQLDbClass extends DBController { } 예시다.


사용법

require_once '../phpclass/dbController.php';

$d = new DBController();


<?php
class DBController {
    private $host = 'localhost';
    private $database = 'survey';
    private $userid = 'root';
    private $password = 'autoset';
    protected $db;

    public function __construct() {
        $this->db = $this->connectDB();
    }

    function __destruct(){
        mysqli_close($this->connectDB());
        //mysqli_close($this->db);
    }

    private function connectDB() {
        $dbconn = mysqli_connect($this->host, $this->userid, $this->password, $this->database);
        mysqli_set_charset($dbconn, "utf8"); // DB설정이 잘못되어 euc-kr 로 되어 있으면 문제가 됨
        if (mysqli_connect_errno()) {
           printf("Connect failed: %s\n", mysqli_connect_error());
           exit();
        } else {
          return $dbconn;
        }
    }

    //DB-UID데이터
    function getUidData($table,$uid){
        return $this->getDbData($table,'uid='.(int)$uid,'*');
    }

    // DB Query Cutom 함수
    function getDbData($table,$where,$column) {
        $result = mysqli_query($this->db,'select '.$column.' from '.$table.($where?' where '.$this->getSqlFilter($where):''));
        $row = mysqli_fetch_array($result);
        return $row;
    }

    // DB Query result 함수
    function getDbresult($table,$where,$column) {
        $result = mysqli_query($this->db,'select '.$column.' from '.$table.($where?' where '.$this->getSqlFilter($where):''));
        return $result;
    }

    //DB데이터 ARRAY -> 테이블에 출력할 데이터 배열
    function getDbArray($table,$where,$flddata,$orderby,$rowsPage,$curPage){
        $sql = 'select '.$flddata.' from '.$table.($where?' where '.$this->getSqlFilter($where):'').($orderby?' order by '.$orderby:'').($rowsPage?' limit '.(($curPage-1)*$rowsPage).', '.$rowsPage:'');
        if($result = mysqli_query($this->db,$sql)){
            return $result;
        }
    }

    //DB데이터 레코드 총 개수
    function getDbRows($table,$where){
        $sql = 'select count(*) from '.$table.($where?' where '.$this->getSqlFilter($where):'');
        if($result = mysqli_query($this->db,$sql)){
            $rows = mysqli_fetch_row($result);
            return $rows[0] ? $rows[0] : 0;
        }
    }

    //DB삽입
    function getDbInsert($table,$key,$val){
        mysqli_query($this->db,"insert into ".$table." (".$key.")values(".$val.")");
    }

    //DB업데이트
    function getDbUpdate($table,$set,$where){
        mysqli_query('set names utf8');
        mysqli_query('set sql_mode=\'\'');
        mysqli_query($this->db,"update ".$table." set ".$set.($where?' where '.$this->getSqlFilter($where):''));
    }

    //DB삭제
    function getDbDelete($table,$where)    {
        mysqli_query($this->db,"delete from ".$table.($where?' where '.$this->getSqlFilter($where):''));
    }

    //SQL필터링
    function getSqlFilter($sql){
        return $sql;
    }

}//end dbClass

?>


만약 2개의 파일로 나누어서 만들었다면 첨부파일처럼 코드를 작성하면 된다.

dbClass.zip


블로그 이미지

Link2Me

,