728x90
본 게시글은 처음 시작은 단순한 정리 개념이었는데, PHP 기본을 이해하는 핵심이라고 봐도 좋다.

네이버지식인 질문을 보면 PHP 개념은 모른 상태에서 Android 앱과의 통신을 어떻게 하는지 알고 싶은 Copy&Paste 초보자 도움 요청을 많이 본다. 가장 중요한 것은 기본 개념을 얼마나 잘 이해하고 있는가다.

스스로 로직을 그려보고 테스트하고 디버깅하면서 조금씩 성장할 수 있다.


모든 내용을 하나의 파일로 처리할 수는 없다. 파일을 모듈단위로 나누어서 처리하는게 좋다.

통신할 때 파일 처리에 대한 기본 개념을 알아야 한다.



(GET,POST 개념을 모른다면 일단 눌러서 읽어본다. http://link2me.tistory.com/398)


파일간에 정보를 넘겨주고 받기 위해서는 $_GET 배열, $_POST 배열을 사용하여 변수를 넘긴다.

$_GET 배열, $_POST 배열 구분없이 둘다 인식하도록 하려면 PHP 파일 B에서 $_REQUEST 배열을 사용한다.


아래 표에서 PHP 관련 게시글은 초보자 도움 링크를 추가한 것이니 꼭 읽어보시길 ^^


PHP

 - LoingForm.php (파일A)에서 loginID, loginPW 값을 POST 방식으로 보낸다.

 - PHP 파일B에서 읽어들일 때 $_POST 배열로 읽어서 처리한다.

 - 배열변수를 MySQL DB 변수로 보내서 결과를 return 받아서 로그인 성공과 실패를 판단한다.

 - 로그인 성공이면 main.php or list.php 와 같은 파일로 이동시킨다.

 - 로그인 실패면 LoginForm.php 파일로 다시 이동시킨다.

 MySQL DB 생성 및 사용자 권한 부여 방법 : http://link2me.tistory.com/431 참조

 MySQL 연동 기본 코딩 방법 : http://link2me.tistory.com/1213 참조

 PHP 디버깅 요령 및 경고 메시지 처리 방법 : https://link2me.tistory.com/1130 참조

 PHP 변수지정 기초 지식 : https://link2me.tistory.com/523 참조

 PHP isset 와 empty 설명 : https://link2me.tistory.com/996 참조

 닥치고 객체지향 MySQLi 연동방식 예제 : http://link2me.tistory.com/1395 참조

 제대로 배우는 자바스크립트 Form 전송 기초 : http://link2me.tistory.com/954 참조

 회원가입 및 중복체크 Form 예제 : https://link2me.tistory.com/1480 참조

 PHP Legacy 함수를 PDO Class 로 변경하는 방법 : https://link2me.tistory.com/1636 참조

 PHP PDO Class 및 부트스트랩 로그인 폼/처리 예제 : http://link2me.tistory.com/1402 참조

 Windows 기반 APM(Apaceh + PHP + MySQL) 설치 https://link2me.tistory.com/797  참조

 PHP 함수의 결과는 정수일까? String일까? https://link2me.tistory.com/1487 참조

 Android

PHP 와 Android 간 연동 처리 개념

 - Android 에서 로그인 정보를 조회한다고 하면 loginID, loginPW 값을 POST 방식으로 보낸다.

 - PHP 파일B에서 읽어들일 때 $_POST 배열로 읽어서 처리한다.

 - DB 조회 결과를 echo 문으로 출력한다.
 - echo 출력 결과를 읽어서 로그인 성공, 실패 여부를 판단 처리한다.

   가령, echo 1 이면, Android 에서는 1의 결과로 로그인 성공으로 다음 Activity 로 전환처리한다.

 - 많은 값을 결과로 돌려 받아야 하는 경우에는

   echo json_encode(배열) 로 받은 결과를 파싱하여 처리한다.

  Android JSON 파헤치기(필수사항) : https://link2me.tistory.com/1247  참조

  Android Volley 라이브러리 사용 예제 : https://link2me.tistory.com/1533 

  Android Retrofit2 라이브러리 사용 예제 : https://link2me.tistory.com/1806

  Android AsyncTask Class화하여 사용하는 방법 : https://link2me.tistory.com/1516 

  Android 암호화 로그인 처리 : https://link2me.tistory.com/1231

  Android - MySQL 연동 Web Part : http://link2me.tistory.com/1022

  Android Studio 기반 로그인 예제 : http://link2me.tistory.com/1230 

  Android Studio & PHP PDO 기반 회원가입 예제 : http://link2me.tistory.com/1405

  Android Studio & PHP PDO 기반 로그인 예제 : http://link2me.tistory.com/1404 

 C#

 - C# 에서 로그인 정보를 조회한다고 하면 loginID, loginPW 값을 POST 방식으로 보낸다.

 - PHP 파일B에서 읽어들일 때 $_POST 배열로 읽어서 처리한다.

 - DB 조회 결과를 echo 문으로 출력한다.

 - echo 출력 결과를 읽어서 C# 에서 로그인 성공, 실패 여부를 판단 처리한다.

  C# Web 접속 로그인 예제 : http://link2me.tistory.com/1118 

 

 윈도우즈 환경에서 리눅스 서버를 설치하고 Web서버를 운용할 수 있다.

 APM(Apache + PHP + MariaDB) 를 설치하는 방법을 자세히 알려주고 있다.

 - Window10 에 CentOS7(리눅스) 설치 및 APM 구성 : https://link2me.tistory.com/1885

 - 윈도우기반 APM 설치 툴 autoset9 : http://link2me.tistory.com/797

 - Apache 환경설정 방법 : http://link2me.tistory.com/426, http://link2me.tistory.com/999

 - PHP 환경 설정 방법 : http://link2me.tistory.com/967, http://link2me.tistory.com/986


Web(PHP 파일B) 에서 변수가 없거나 값이 넘어오지 않을 경우에는 동작하지 않도록 코딩을 해야 한다.


초보자들이 가장 많이 하는 실수(내가 초보시절에 겪은 실수)는 통신방식을 고려하지 않고 코딩을 하거나 서버 세팅정보를 대충 하는 것이다. 대화해보면 코딩 좀 하는 분도 이런걸 대략 하는 분이 있다. (한국어와 영어 소통하는 것과 같은 것)

UTF-8 로 세팅한다는 의미는 파일 Encoding Mode 도 UTF-8 로 하고, 서버에 세팅도 UTF-8 로 하고 DB에도 UTF-8 로 해야 한다는 것이다. (엑셀은 EUC-KR 방식으로 CSV 파일 내보내기를 한다)


참고사항


DB 연결정보는 로그인 처리 뿐만 아니라 거의 모든 PHP에서 사용한다고 볼 수 있다.

모든 PHP 파일에서 중복해서 DB 연결 정보를 코딩하는 것은 비효율적이므로, 파일을 분리하여 dbconnect.php 파일로 작성해두기만 하면 코딩이 심플해지고 가독성도 좋아진다.


dbconnection 을 하는 파일을 만드는 방법을 알아보자.


require문, include문 : 자주 사용하는 PHP 코드를 다른 파일에 모아 두고 필요할 때 파일을 읽어들여서 사용할 수 있도록 하는 명령


require "파일명";

- 만일 지정된 파일이 존재하지 않을 경우에는 php.ini에 설정된 include_path에서 파일을 찾는다.

- include_path에도 파일이 존재하지 않는다면 require문을 작성한 현재 파일이 있는 디렉토리에서 찾는다.

- 현재 디렉토리에도 없다면 오류표시하고 정지된다.


require와 include의 차이점

- require문은 오류가 발생했을 경우에 Fatal Error가 되어 정지가 되어버린다.

- require_once() : 지정한 파일을 한 번 읽어 들이면 같은 처리 중에는 다시 읽어 들일 수 없다.

- include문은 오류가 발생했을 경우에 Warning을 출력하고 처리코드를 수행한다.

- include_once() : 지정된 파일을 이미 읽어 들어 경우에는 다시 파일을 읽어 들이지 않는다.


PHP Connect to MySQL

- MySQL (procedural) : MySQL DB에서만 동작하며, , PHP 7.0 이상에선 동작안됨. PHP 5.5에서 deprecated

- MySQLi (procedural) : MySQL DB에서만 동작한다.

- MySQLi (object-oriented) : MySQL DB에서만 동작한다.
- PDO(PHP Data Objects) :
Oracle, PostgreSQL, SQLite, MySQL 등 12가지의 DB에서 동작한다.


Connecting to MySQL using the legacy MySQL functions

절차지향(procedural) 접속 함수는 MySQLi 방식과 MySQL 방식이 있다.

MySQL 설치방식에 따라 둘다 지원할 수도 있고 둘 중에 하나만 지원할 수도 있다.

MySQL 방식과 MySQLi 방식은 연결 방식이 약간 다르므로 코딩시 실수하지 않도록 주의가 필요하다.

======== dbinfo.php ======

<?php
$db['host'] = "localhost";
$db['name'] = "";
$db['user'] = "";
$db['pass'] = "";
$db['port'] = "3306";
?>


======= dbconnect.php ========

PHP 프로그램 내에서 MySQL 데이터베이스에 접근하는 함수가 mysqli_connect()이다.

$dbconn 라고 했지만 $db 또는 $conn 등 개발자 취향에 따라 변수명을 지정한다.

dbClass.php 에 만든 사용자 함수에 global $dbconn 연결 부분과 관련된 사항이다.


MySQLi 접속용과 MySQL 접속용 코드가 약간 다르다는 걸 확인하고 맞게 사용해야 한다.

MySQLi

<?php
include_once 'phpclass/dbinfo.php';
$dbconn = isConnectDb($db);

function isConnectDb($db)
{
    $conn = mysqli_connect($db['host'],$db['user'],$db['pass'],$db['name'],$db['port']);
    mysqli_set_charset($conn, "utf8");  // DB설정이 잘못되어 euc-kr 로 되어 있으면 문제가 됨
    if (mysqli_connect_errno()) {
       echo "Failed to connect to MySQL: " . mysqli_connect_error();
       exit;
    } else {
      return $conn;   
    }
}
?>

 MySQL

<?php
include_once 'phpclass/dbinfo.php';
$dbconn = isConnectDb($db);

function isConnectDb($db) {
    $conn = @mysql_connect($db['host'].':'.$db['port'],$db['user'],$db['pass']);
    //Set encoding
    mysql_query("SET CHARSET utf8");
    mysql_query("SET NAMES 'utf8' COLLATE 'utf8_general_ci'");
    if(!$conn){
        die('Not connected :' . mysql_error());
        exit;
    }
    $selc = mysql_select_db($db['name'],$conn); // 접근한 계정으로 사용할 수 있는 DB 선택
    // 연결 식별자($conn) 는 생략 가능하며, 생략시 가장 최근에 설정한 연결 식별자가 사용된다.
    return $selc ? $conn : false;
}
?>


아래 두 명령의 차이점에 대해 이해하자.

MySQL

 mysql_query ("select * from tableName"); // 최근에 열려진 db conection 을 자동으로 사용
 mysql_query ("select * from tableName", $dbconn); // db connection을 지정해서 사용

 MySQLi

 mysqli_query ($dbconn, "select * from tableName"); // db connection 지정만 허용


dbconnect.php 함수를 만들었으면 이제 실제 코드상에서 사용하는 방법을 알아보자.

LoginForm.php 인 A 파일에서 입력한 데이터를 받아서 처리하는 loginChk.php 인 파일 B의 일부 로직이다.

코딩을 하면서 고려할 점은 loginChk.php 파일을 단독으로 실행했을 때 파일이 실행되어서는 안되도록 체크하는 로직을 반드시 추가해야 한다. 즉, 파일 A에서 입력된 변수가 없으면 파일 B는 동작되지 않도록 해야 한다.

파일B에서 값이 제대로 넘어왔는지 체크하는 방법은 http://link2me.tistory.com/1130 를 참조하면 도움된다.


아래 코드는 실제로 사용하는 코드다.

안드로이드에서 받은 입력값과 웹 LoginForm.php 에서 전달받은 값을 구분하여 체크하는 로직이다.

안드로이드폰/아이폰은 고유한 ID값을 가지고 있는데 이 ID값이 넘어오면 안드로이드 로그인으로 구분하도록 if문을 사용했다.

대부분 세션 스타트를 session_start(); 로만 처리하는데

if(!isset($_SESSION)) {
    session_start();
}

로 해주어야 한다. 그래야 경고 메시지가 나오지 않는다.


=== loginChk.php ====

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

@extract($_POST); // POST 전송으로 전달받은 값 처리
// $_POST['loginID'] 라고 쓰지 않고, $loginID 라고 써도 인식되게 하려면 extract($_POST); 를 써주면 된다.

// 변수가 존재하거나 값이 있는 경우에만 데이터 업데이트를 하도록 하는 로직
// 이 파일명으로 직접 접속하면 변수 값이 넘어오지 않으므로 실행 불가되도록 처리
if(isset($loginID) && !empty($loginID) && isset($loginPW) && !empty($loginPW)) {

   require_once $_SERVER['DOCUMENT_ROOT'].'/dbconnect.php'; // db접속
   require_once $_SERVER['DOCUMENT_ROOT'].'/loginClass.php';
   $c=new LoginClass(); // 로그인 처리 관련 함수를 모아서 작성한 클래스

   $deviceID = $deviceID ? $deviceID : '';  // 안드로이드 접속인지 PHP Web 접속인지 판단

    if(empty($deviceID)){ // 장치 값이 없으면, 즉 Web 접속이면
        $row = $c->WebUserAuthCheck($loginID,$loginPW);
        if(is_array($row)) {
            if($row['code'] > 0) {
                $_SESSION['userID'] = $row['id'];
                $_SESSION['userPW'] = md5($loginPW);
                $_SESSION['code'] = $row['code'];
                $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
                $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT'];
                $c->AccessLog($_SESSION['userID'],''); // 접속 로그 기록

                echo("<meta http-equiv='Refresh' content='0; URL=mobile/list.php'>");
            } else {
                echo '권한 불가';
            }
        } else if($row == '0'){
            $msg ='정보가 올바르지 않습니다';
            echo "<script>alert('".$msg."');history.go(-1);</script>";
        } else {
            $msg ='정보가 올바르지 않습니다';
            echo "<script>alert('".$msg."');history.go(-1);</script>";
        }

    } else {  // 안드로이드 접속이면
        $result = $c->MobileUserAuthCheck($loginID,$loginPW,$deviceID);
        if($result > 0 ) {
            session_save_path('./_tmp/session');

            $_SESSION['userID'] = $loginID;
            $_SESSION['userPW'] = md5($loginPW);
            $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
            $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT'];
            $c->AccessLog($loginID,$deviceID); // 접속 로그 기록

            echo 1; // 로그인 성공 결과를 1로 처리
            // 안드로이드에서는 화면출력하는 결과값으로 로그인 성공/실패 판단 처리
        } else if($result == 0) {
            echo 0; // Login Fail

        } else {
            echo -1; // Phone Dismatch

        }
    }

} else {  // 이 부분은 Web 접속 변수가 없는 경우를 처리하는 부분
    // $_POST 전송값이 없이 바로 이 파일을 실행하면 로그인 창으로 돌려보내라.
    echo("<meta http-equiv='Refresh' content='0; URL=loginForm.php'>");
}
?>


loginChk.php 파일에서 보면 WebUserAuthCheck($loginID,$loginPW) 함수를 사용한 것을 볼 수 있다. 이 함수는 loginClass.php 파일에 작성되어 있는데, loginClass.php 함수중에서 Web 로그인 체크하는 부분만 발췌했다.

사용자가 해킹을 시도할 의도가 있어도 방지하는 코드를 추가된 것을 확인할 수 있다.


==== loginClass.php =====

 <?php
class LoginClass {
    function WebUserAuthCheck($u,$p) {
        if(!isset($u) || !isset($p) || empty($u) || empty($p)) {
            return 0;
        } else {
            global $dbconn; // global 키워드를 사용하여 변수에 선언할 경우 함수 밖의 변수를 참조할 수 있다
            $u = preg_replace("/[\s\t\'\;\"\=\--]+/","", $u); // 공백이나 탭 제거(사용자 실수 방지)
            $p = preg_replace("/[\s\t\'\;\"\=\--]+/","", $p); // 공백이나 탭 제거, 특수문자 제거
            // SQL injection 검사
            $u = mysqli_real_escape_string($dbconn,$u); // <script>documnet.cookie();</script> 공격 방지
            $p =
mysqli_real_escape_string($dbconn,$p); //
            if(preg_match('/[\/\\\\]/', $u)) $this->popup('비정상적 접근입니다'); // no slashes
            //if(preg_match('/(and|null|where|limit)/i', $u)) { // i는 대소문자 구별하지 말라
            //    $this->popup('비정상적 접근입니다');
            //} // 회원아이디가 일치하는 경우가 생겨서 이 구문은 사용을 자제해야 할 듯해서 주석처리함.
            if(!preg_match('/^[0-9a-zA-Z\~\!\@\#\$\%\^\&\*\(\)]{7,}$/',$p)) { // 최소7자리 이상 허용 문자만 통과
                $this->popup('정보가 올바르지 않습니다');
                // 같은 클래스안에 있는 다른 함수를 사용할 때 $this 로 기술
            }

            $sql = "select code, id ";
            $sql.= "from member where pw=md5('".$p."') and id= '".$u."' ";
            if($result = mysql_query($sql,$dbconn)) { //성공
                $row = mysql_fetch_array($result);
                if($row == NULL) return 0;
                return $row;
            } else {
                return '-1';
            }
        }
    }

    // 로그인함수 경고메시지
    function popup($msg) {
        echo "<script>alert('".$msg."');history.go(-1);</script>";
    }
} // End of LoginClass
?>


위 SQL 인젝션 방지 코드가 완벽하지 않을 수도 있다.

정규식 예제 : https://link2me.tistory.com/1489 를 참조하면 조금 더 도움될 것으로 본다.

그리고 구글링으로 PHP 정규식 을 검색해서 코드를 완벽하게 보완하면 좋을 것이다.



첨부파일 (db 연결함수)

dbconn.ZIP


본 첨부파일은 초보자 분들이 타이핑 하면서 실수하지 않게 제공하는 것입니다.

블로그내 다른 소스를 복사해서 활용하고 싶다면 c browser 를 검색해서 설치하고 사용하면 됩니다.

도움되셨다면 댓글이나 공감 부탁드립니다.



추가 작성 : 2016-11-23일자 (네이버지식인 답변시 추가)

DB를 연결하는 방법만 언급하다보니 함수화하는 것과 연결고리를 잘 모르는 분을 위해서 적어본다.

통계처리용으로 만는 함수다. 함수화를 해두면 나중에 추가할 사항이 있으면 함수만 추가하면 된다.

MySQLi 를 사용하는 환경이면 사용자 함수도 MySQLi 기반으로 수정해주면 된다.


=== statClass.php ===


이런 함수를 호출해서 사용하는 방법은 간단하다.

<?php

require_once "statsClass.php";
$s=new StatsClass(); // 객체 생성(인스턴스화)
$row = $s->today_statsCount(); // 배열이므로 배열로 받아서

?>

<?php echo '개인별(오늘/어제) : '.$row[0].'/'.$yes[0];?></th>


도움이 되셨다면 00 해 주세요. 좋은 글 작성에 큰 힘이 됩니다.


728x90
블로그 이미지

Link2Me

,