728x90

MySQLi 객체지향 접속방식으로 코드를 작성한 회원가입과 로그인 예제를 만들었다.

모두 꼼꼼하게 테스트하여 잘 동작함을 확인했다.


안전한 비밀번호 작성 규칙

- 영문자, 숫자, 특수문자 중 2가지 종류를 조합할 때에는 10자리 이상 / 3가지 종류를 조합할 때에는 8자리 이상으로 설정

- 비밀번호는 최소 6개월에 한번씩 변경

- 누구나 쉽게 알 수 있는 비밀번호 사용은 자제


<?php
// DB 정보 입력
define("DB_HOST", "localhost");
define("DB_DATABASE", "test");
define("DB_USER", "root");
define("DB_PASSWORD", "autoset");
?>

<?php
class DBController {
    protected $db; // 변수를 선언한 클래스와 상속받은 클래스에서 참조할 수 있다.

    // 생성자
    function __construct() {
        $this->db = $this->connectDB();
        // construct 메소드는 객체가 생성(인스턴스화)될 때 자동으로 실행되는 특수한 메소드다.
    }

    // 소멸자(destructor)
    function __destruct() {
        mysqli_close($this->connectDB());
    }

    private function connectDB() {
        require_once 'config.php';
        // MySQLi 객체지향 DB 연결
        $conn = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE);
        return $conn; // return database handler
    }

}
?>

<?php
class LoginClass extends DBController {
    // class 자식클래스 extends 부모클래스
    // override : 부모 클래스와 자식 클래스가 같은 메소드를 정의했을 경우 자식 클래스가 우선시된다.

    public function hashSSHA($password) {

        $salt = sha1(rand());
        $salt = substr($salt, 0, 10);
        $encrypted = base64_encode(sha1($password . $salt, true) . $salt);
        $hash = array("salt" => $salt, "encrypted" => $encrypted);
        return $hash;
    }

    public function checkhashSSHA($salt, $password) {
        $hash = base64_encode(sha1($password . $salt, true) . $salt);
        return $hash;
    }

    // 회원 정보 신규 입력
    public function storeUser($userID, $userNM, $password, $mobileNO) {
        $hash = $this->hashSSHA($password);
        $encrypted_password = $hash['encrypted']; // encrypted password
        $salt = $hash['salt']; // salt
        $regdate = date("YmdHis");

        $stmt = $this->db->prepare("INSERT INTO members(userID, userNM, passwd, salt, regdate) VALUES(?, ?, ?, ?, ?)");
        $stmt->bind_param("sssss", $userID, $userNM, $encrypted_password, $salt,$regdate);
        $result = $stmt->execute();
        $stmt->close();

        // check for successful store
        if ($result) {
            $user = $this->getUser($userID, $password);
            //echo '<pre>';print_r($user);echo '</pre>';
            $rs = $this->storeUserDetail($user['uid'],$userNM,$userID,$mobileNO);
            if($rs == 1){
                return $user;
            } else {
                return -1;
            }
        } else {
            return -1; // 0
        }
    }

    // 회원 세부 정보 입력
    public function storeUserDetail($relateduid,$userNM,$email,$mobileNO){
        $mobileNO = preg_replace("/[^0-9]/", "", $mobileNO); //전화번호 숫자만 남기고 제거
        $sql ="INSERT INTO member_data(relateduid,userNM,email,mobileNO) VALUES(?, ?, ?, ?)";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("isss", $relateduid, $userNM, $email, $mobileNO);
        $result = $stmt->execute();
        $stmt->close();
        if($result){
            return 1;
        } else {
            return 0;
        }
    }


    // 로그인 체크
    public function getUser($userID, $password) {
        $stmt = $this->db->prepare("SELECT * FROM members WHERE userID = ?");
        $stmt->bind_param("s", $userID);

        if ($stmt->execute()) {
            $user = $stmt->get_result()->fetch_assoc();
            $stmt->close();

            // verifying user password
            $salt = $user['salt'];
            $encrypted_password = $user['passwd'];
            $hash = $this->checkhashSSHA($salt, $password);
            // check for password equality
            if ($encrypted_password == $hash) {
                // user authentication details are correct
                return $user;
            }
        } else {
            return NULL;
        }
    }

    // 안드로이드/아이폰 로그인 체크
    public function LoginUserChk($userID,$password,$deviceID){
        if(empty($userID) || empty($password)){
            return 0;
        } else {
            $user = $this->getUser($userID, $password);
            if($user['uid']>0){ // 가입자 정보가 있다면
                // 장치 일련번호 체크
                if($user['phoneSE'] == NULL){
                    // 신규 장치번호 입력(최초 로그인)
                    $this->LoginUserEquipInput($userID,$deviceID);
                    return 1;
                } else {
                    if($user['phoneSE'] === $deviceID){
                        return 1; // 일련번호 일치
                    } else {
                        return -1; //일련번호 불일치
                    }
                }
            } else {
                return 0; // 로그인 실패
            }
        }

    }

    // 장치번호 업데이트
    public function LoginUserEquipInput($userID,$deviceID){
        if(strlen($deviceID)>0 && is_numeric($deviceID)){ // 안드로이드폰
            $ostype = 2;
        } else if(strlen($deviceID)>30){ // 아이폰
            $ostype = 1;
        } else { // 기타
            $ostype = 0;
        }

        $sql='update members set phoneSE=?, OStype=? where userID=?';
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("sss", $deviceID, $ostype, $userID);
        $status = $stmt->execute();
        if($status == true){
            return 1;
        } else {
            return 0;
        }
    }//end

    // 장치번호 초기화 (관리자용)
    public function EquipReset($userID){
        $ostype = 0;
        $sql='update members set phoneSE=NULL, OStype=? where userID=?';
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("ss", $ostype, $userID);
        $status = $stmt->execute();
        if($status == true){
            return 1;
        } else {
            return 0;
        }
    }//end

    // 회원 가입 여부 체크
    public function isUserExisted($userID) {
        $stmt = $this->db->prepare("SELECT userID from members WHERE userID = ?");

        $stmt->bind_param("s", $userID);
        $stmt->execute();
        //$stmt->store_result();
        $result = $stmt->get_result();

        if ($result->num_rows > 0) {
            // user existed
            $stmt->free_result();
            $stmt->close();
            return true;
        } else {
            // user not existed
            $stmt->free_result();
            $stmt->close();
            return false;
        }
    }

    // 회원 정보 삭제
    public function deleteUser($userID){
        $stmt = $this->db->prepare("delete FROM members WHERE userID = ?");
        $stmt->bind_param("s", $userID);
        $stmt->execute();
        $stmt->close();
    }

    // 인증이 성공한 상태에서 직접 접속을 시도하는 외부 접속으로부터 보호
    function checkReferer($url) {
        $referer = $_SERVER['HTTP_REFERER'];
        $res = strpos($referer,$url);
        return $res == 0 ? false : true;
    }
}
?>

 <?php
if (!isset($_SESSION)) {
    session_start();
}

// 파일을 직접 실행하면 동작되지 않도록 하기 위해서
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST); // $_POST['loginID'] 라고 쓰지 않고, $loginID 라고 써도 인식되게 함
    //echo '<pre>';print_r($_POST);echo '</pre>'; // 전송받은 배열을 확인하고 싶을 때 사용
    if(isset($userID) && !empty($userID) && isset($password) && !empty($password)) {
        include_once 'config/dbconnect.php';
        require_once 'config/loginClass.php';
        $c = new LoginClass();
        if ($c->isUserExisted($userID) === true) {
            echo '{"result":"0"}'; // echo json_encode(array('result' => '0')); 과 동일
        } else {
            $mobileNO = preg_replace("/[^0-9]/", "", $mobileNO); //전화번호 숫자만 남기고 제거
            // 회원 등록
            $user = $c->storeUser($userID, $userNM, $password, $mobileNO);
            if($user) {// 회원 등록 성공
                $_SESSION['userID'] = $user['userID'];
                $_SESSION['userNM'] = $user['userNM'];
                $_SESSION['admin'] = $user['admin'];
                echo json_encode(array('result' => '1'));
            } else {
                // 회원 등록 실패
                echo json_encode(array('result' => '-1'));
            }
        }
    }else {// 입력받은 데이터에 문제가 있을 경우
        echo json_encode(array('result' => '-2'));
    }
}
?>

 <?php
// 파일을 직접 실행하는 비정상적 동작을 방지 목적
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST); // $_POST['loginID'] 라고 쓰지 않고, $loginID 라고 써도 인식되게 함
    if(isset($userID) && !empty($userID) && isset($password) && !empty($password)) {
        include_once 'config/dbconnect.php';
        require_once 'config/loginClass.php';
        $c = new LoginClass();
        $user = $c->getUser($userID, $password);
        //echo '<pre>'; print_r($user);echo '</pre>';
        if ($user != false) {
            $_SESSION['userID'] = $user['userID'];
            $_SESSION['userNM'] = $user['userNM'];
            $_SESSION['admin'] = $user['admin'];
            echo json_encode(array('result' => '1'));
        } else {
            echo json_encode(array('result' => '0'));
        }
    }else {// 입력받은 데이터에 문제가 있을 경우
        echo json_encode(array('result' => '-2'));
    }
} else { // 비정상적인 접속인 경우
    echo 0; // a.loginChk.php 파일을 직접 실행할 경우에는 화면에 0을 찍어준다.
    exit;
}
?>


직접 실행해 볼 수 있는 테이블 구조 및 관련 파일을 모두 첨부한다.

안드로이드에서 로그인하는 코드 샘플도 포함되어 있다.


mysqlI_login.zip



블로그 이미지

Link2Me

,