PHP를 배울 때 가장 먼저 알아야 할 사항이 디버깅 요령인데 독학으로 배워 게시글 기록을 보면 순서없이 중구난방이다.

최근에서야 디버깅을 이렇게 하면 도움이 되겠다 싶은 걸 적어본다.

 

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

 

파일 A에서 파일 B로 데이터를 넘길 때 파일 B에서 확인하는 방법이다. (의미를 모르면 http://link2me.tistory.com/1110 부터 읽어라)

 

파일A에서 form 으로 넘긴 변수(method="post")가 제대로 잘 넘어오는지 확인하는 방법

- 파일 A란?  PHP Form, Android, C# 등 값을 POST (또는 GET) 방식으로 넘기는 코드를 의미함.

 

<?php
var_dump($_POST); // var_dump 또는 print_r 둘 중에 하나를 선택해서 확인하라.

echo '<pre>';print_r($_POST);echo '</pre>';

출처: https://link2me.tistory.com/1130 [소소한 일상 및 업무TIP 다루기]

echo '<pre>';print_r($_POST);echo '</pre>'; // 가독성이 좋게 하려면 print_r 과 pre 태그를 사용하면 된다.

exit; // 이 명령어 다음에 적힌 코드들은 실행하지 말고 빠져나가라.

       // 변수가 넘어오는지 테스트 목적이므로 아래 코드 실행 방지 목적
?>

로 하면 배열로 넘어온 값을 확인할 수 있다.

print_r() : 변수 정보를 알기 쉬운 형식으로 출력한다.

var_dump() : 기본적으로 print_r()함수와 같지만 데이터 유형 등 출력되는 정보가 많다.

var_export() : 그대로 PHP 스크립트로서 해석할 수 있는 형식으로 출력한다.

 

직접 테스트해 보고자 한다면 로그인 폼 전송예제 http://link2me.tistory.com/1479 에서 파일을 받으면 된다.

 

코드 작성시 체크 포인트

<?php
// 에러 메시지를 찾고자 할 때 추가할 코드 (개발 시에는 반드시 아래 3줄을 추가해서 하라)

ini_set("display_startup_errors", 1);
ini_set("display_errors", 1);
error_reporting(E_ALL);

// 운용 모드에서는

// error_reporting(0); // 모든 오류를 표시하지 않는다.
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){ // 반드시 이 한줄을 넣어라.

    // 보안에 안전하려면
    // POST 방식으로 보낸 데이터가 있는지 체크
    echo '<pre>';print_r($_POST);echo '</pre>';
}

?>



<?php
// 보안을 고려한 코드 작성시 (보통은 php.ini 에 해당항목을 수정한다)

ini_set('error_reporting', E_ALL | E_STRICT);
ini_set('display_startup_errors', 'Off');
ini_set('display_errors', 'Off');

ini_set('log_errors', 'On');
?>
Notice: Undefined index: 라고 경고메시지가 뜨는 것이 싫을 경우에는

코드 상단에 error_reporting(E_ALL ^ E_NOTICE); 를 추가해주면 된다.
error_reporting(0); // 모든 오류를 표시하지 않는다. (운용환경에서는 이걸 사용하라)

하지만 개발을 할 때에는 경고 메시지도 모두 출력되도록 하여 에러를 완전히 잡는 것이 중요하다.
 //페이지 변수 설정
$page = isset($_GET['page'])? trim($_GET['page']) : 1;
파일 B에서 코드 구현시 파일 A에서 값이 넘어오지 않을 때에도 동작되도록 코드를 구현해야 할 경우가 있다.
이런 상황에서 삼항연산자로 간단하게 했더니 경고 메시지가 출력된다.
Notice: Undefined variable:

$ym=$_GET['ym'] ? $_GET['ym'] : date("Ym"); //현재 년월
 
이걸 정확하게
if(isset($_GET['ym'])){
    $ym = $_GET['ym'];
} else {
    $ym = date("Ym");
}
로 수정해줘야 경고메시지가 없어진다는 걸 확인했다.

 
결국 isset 으로 변수 설정 유무 검사를 추가해야만 경고 메시지가 없어진다.

$ym=isset($_GET['ym']) ? $_GET['ym'] : date("Ym"); //현재 년월
잘 만들어진 빌더를 분석하다보면 isset 처리를 하지 않아 경고메시지가 출력되는 걸 종종 발견하게 된다.

기존 코드를 유지보수 하다가 수정한 것이 있어서 http://link2me.tistory.com/1085 에 적어둔게 있다.

 

경고메시지를 php.ini 파일을 수정해서 나오지 않도록 하는 방법을 알아보자.

error_reporting 키워드를 검색어로 찾아서 아래와 같이 수정한다.

 

error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE
- E_DEPRECATED : 향후 PHP 버전에서 동작을 하지 않을 수도 있는 코드에 대해서 로그를 발생 시킨다
- E_NOTICE : 초기화 되지 않은 변수를 사용했을 때 에러 로그를 생성한다.

 

php.ini 파일을 수정했으면 아파치를 재시작하면 변경한 내용으로 적용된다.

php.ini 에 추가하면 에러 버그를 못잡을 수도 있으니 해당 파일 상단에 아래와 같이 처리하는 걸 권장한다.

 

완벽하게 코드를 만드는 습관을 들이는게 중요하다.
사소한 것을 하나씩 무시하다보면 중요한 곳에서 버그가 생길 수 있다.

mysqli_query 에 에러가 발생할 경우 아래와 같이 원인을 찾을 수 있게 코딩하는 것도 좋다.

 

<?php
$sql = "SQL statement here";
$result = mysqli_query($dbconn,$sql) or trigger_error("SQL: $sql - Error: ".mysqli_error(), E_USER_ERROR);
?>

 

SQL 문이 정상적으로 잘 생성되었는지 여부를 확인할 수 있게 echo 문으로 출력해보는 것도 필요하다.

결국 PHP구문을 통해서 생성한 SQL 문이 DB에 저장되도록 하는 것이기 때문이다.

echo $sql; 로 생성된 SQL 구문을 직접 DB에 넣었을 때 에러없이 잘 들어가면 SQL문은 에러가 없다는 뜻이다.

SQL문에서 에러가 생기는 경우도 종종있다. 문법이 잘못되었거나, 오타가 있거나 등등...

//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:'');
    echo $sql; // SQL 문이 정상적으로 실행되는지 여부 파악 목적
    if($result = mysqli_query($this->db,$sql)){
        return $result;
    }
}
 

echo $sql; 출력으로 웹 브라우저 화면상에서 나온 SQL 문을 직접 DB에서 쿼리해보는 것이 가장 좋은 해결 방법이다.

link2me.tistory.com/1917 은 phpMyAdmin 인데 phpMyAdmin 은 잘 다루면 엄청 편리하고, 보안을 신경써야 한다.

 

 

MySQLi 절치지향 방식으로 만든 함수를 PDO 함수로 컨버팅하면서 함수 이상 유무를 확인하는 과정에서 아래와 같이 테스트를 했다.

함수의 결과가 배열일 수도 있고 그냥 String 일 수도 있어서 in_array 함수를 이용하여 배열과 문자열을 구분하여 출력하도록 하면 원하는 결과를 깔끔하게 확인할 수 있다.

 <?php
require_once 'path.php';
require_once $g['path_class'].'dbconnect.php';
require_once $g['path_class'].'adminClass.php';
$a = new adminClass;

$codeID = 4;
$rs = $a->StaffPositionMNCount($codeID);
if(is_array($rst)){
    echo '<pre>';print_r($rs);echo '</pre>';
} else {
    echo $rs;
}
?>

 

 

ajax, jQuery 등을 사용하는 경우 메시지 분석이 어려울 때가 있다.

그래서 echo '<script type="text/javascript">alert("'.$errline.'");</script>'; 로 에러를 확인하지만 문제는 복사가 안된다.

 

echo '<script type="text/javascript">window.prompt("메세지를 복사해주세요", "'.$sql.'");</script>';

로 하면 메시지 복사가 가능해진다.

대부분 에러가 발생하는 원인을 찾으려면 SQL 문을 직접 DB에 입력해보면 에러 메시지가 뭔지 쉽게 확인할 수 있다.

 

 

이제 파일 B 코드 구현 사항이 문제가 없는지 확인하는 방법이다.

즉, Android 와 통신하는데 PHP 코드에는 문제가 없는지 확인하는 방법이라고 봐도 된다.

아래 코드는 로그인 처리하는 파일 B(a.loginChk.php) 코드 예제이다.

초보자의 코드라면 loginClass.php 없이

보통은 여기에서

$sql = "select * from tableName where 조건";

$result=mysqli_query($db,$sql);

$row=mysqli_fetch_array($result);

와 같은 처리를 하는데, 이걸 loginClass Class에 함수로 만들어서 모아둔 것이라고 보면 된다.

 

== 정상적인 코드
<?php
// 파일을 직접 실행하는 비정상적 동작을 방지 하기 위한 목적
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST); // $_POST['loginID'] 라고 쓰지 않고, $loginID 라고 써도 인식되게 함
    if(isset($userID) && !empty($userID) && isset($password) && !empty($password)) {
        include_once 'dbController.php';
        require_once 'loginClass.php';
        $c = new LoginClass();
        $user = $c->getUser($userID, $password);
        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;
}
?>
== 디버깅 코드
<?php
//if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST); // $_POST['loginID'] 라고 쓰지 않고, $loginID 라고 써도 인식되게 함
    // $_POST 변수로 넘어온 값이 라고 가정하고 변수에 값을 직접 넣어서 결과가 정상 반환되는지 확인한다.
    $userID = "jsk005";
    $password = "abc1234";
    if(isset($userID) && !empty($userID) && isset($password) && !empty($password)) {
        include_once 'dbController.php';
        require_once 'loginClass.php';
        $c = new LoginClass();
        $user = $c->getUser($userID, $password);
        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;
}
*/
?>

 

변수가 많을 때에는 직접 변수를 넘겨서 var_dump 로 출력시키고 console.log 로 출력된 메시지를 복사해서 처리하는 방법이 유용할 수 있다.

참조 : https://link2me.tistory.com/2070

 

도움이 되셨다면 00 클릭해 주세요.

728x90
블로그 이미지

Link2Me

,

자바스크립트의 변수를 PHP 에서 읽을 수 있는 방법

"<script>document.write(p1);</script>"; 를 사용하면 된다.

자바스크립트는 별다른 표시가 없으면 윗줄에서 아래줄로 순차적으로 해석한다.


<script>
var p1 = "success";
</script>

<?php
echo "<script>document.write(p1);</script>";
?>

배열도 1차원으로 나열하더라.

   육안(화면)으로 보이는 것과 웹브라우저 소스보기로 보는 거랑은 결과가 다를 수 있음을 확인해야 한다.


PHP 변수 값을 자바스크립트/jQuery 로 전달하는 방법

전제조건 : 자바스크립트는 순차적으로 읽어들이므로 PHP 코드가 자바스크립트보다 위에 나와야 한다.

<script>
var str = '<?php echo $str;?>';
</script>


※ 자바스크립트에서 PHP 로 변수 넘기기 알아야 할 사항

    - 위에서부터 순차적으로 실행되는 구조하에서 javascript 변수를 PHP에서 읽어내는 것은 가능하다.
      하지만 자바스크립트 함수내에서 PHP 변수로 넘기는 것은 안된다.

    - 자바스크립트에서 결과값으로 얻은 변수를 PHP 다른 파일로 넘기는 것은 ajax를 사용하면 된다.

      하지만, ajax 결과를 다시 PHP 변수로 넘긴다?? 안된다는 걸 명심하자.

      ajax 결과를 가지고 클라이언트 HTML 파일을 업데이트할 수는 있다.

   

내가 제대로 이해 못할 수도 있으니 https://opentutorials.org/module/532/6508 게시글 참조하면 도움 될 수도....



PHP 배열 변수를 자바스크립트 배열로 전달하는 방법

JSON(JavaScript Object Notation)은 인터넷에서 자료를 주고 받을 때 그 자료를 표현하는 방법이다.

자료의 종류에 큰 제한은 없으며, 특히 컴퓨터 프로그램의 변수값을 표현하는 데 가장 적합하다.
왜냐하면 JSON은 문자열 뿐만 아니라 배열(Array), 오브젝트(Object) 등 컴퓨터의 모든 변수 형태를 문자열로 표현할 수 있기 때문이다.
JSON에서 표현할 수 있는 데이터 형식으로는 다음과 같은 것들이 있다.
- String (문자열): 큰 따옴표로 묶어 표현, ex) "link2me"
- Number (숫자): 숫자 표현, ex) 1234
- Array (배열): 대괄호로 묶어 표현, ex) [ 'a', 'b', 'c' ]
- Object (객체): 중괄호로 묶어 표현, ex) { key:'value',key2:'value2' }
- Boolean (참/거짓): TRUE 또는 FALSE, ex) true, false
- Null

json_encode 함수를 사용하면 1차원 배열이든 2차원 배열이든 간단하게 자바스크립트 배열로 만들어 준다.
json 은 UTF-8 로 인코딩되어야 인식된다는 걸 명심하자.

파일 Encoding 이 ANSI 로 되어 있으면 결과값이 출력되지 않는다.


<?php

$_POST = array('1','2','3');

echo json_encode($_POST, JSON_FORCE_OBJECT);

?>

<SCRIPT type="text/javascript">

var aa = <?php echo json_encode($_POST);?>;
alert(aa.subject);
// 연관배열에서 key로 값을 찾아준다. 한글도 잘 인식되더라.
</SCRIPT>


<script type='text/javascript'>
<?php
$php_array = array('aaa','bbb','ccc');
$js_array = json_encode($php_array);
echo "var javascript_array = ". $js_array . ";\n";
?>
</script>


다른 방법은 PHP 배열(1차원)을 문자열로 변환한 다음에 new Array()에 넣으면 1차원 배열은 해결된다.

단순한 값들의 나열이라면 배열 타입으로도 충분하다.

<?php

$_POST = array('1','2','3');

?>

<SCRIPT type="text/javascript">
var aa = new Array("<?=implode("\",\"" , $_POST);?>"); // 배열의 값만 문자열로 저장
</SCRIPT>



String to Array

string(문자열)을 구분자로 구분하여 배열로 저장하여 값을 출력
<?php

$flddata ="uid,ItemName,Price,Quantity";
$data = array();
$data = explode(",", $flddata); // 문자열을 배열로 저장

for($i=0; $i < count($data); $i++) {
      echo $data[$i].'<br />';
}
?>


Array to String

배열(array)을 구분자로 구분하여 문자열(string)로 저장

<?php
$arr = array('Hello','World!','Beautiful','Day!');
echo implode(" ",$arr); // 배열을 문자열로 저장
?>



Array 출력

checkbox 에서 선택한 값을 배열로 담아서 ajax 로 넘길 경우 코드와 PHP 파일을 값을 받아서 처리하는 과정이다.

배열을 분리하여 값을 추출하고자 할 경우에 foreach 문을 사용하면 된다.

$('.chkbox:checked').each(function()  // chkbox 라는 클래스명을 준 경우

$('input:checkbox[name="uid[]"]:checked').each(function()  // inputbox name 을 직접 준 경우


$('.btnbox1').click(function(){
    var chkdata = new Array();
    $("input:checked").each(function() {
        chkdata.push($(this).val());
    });
    if(chkdata.length != 0){
        alert(chkdata);
        $.post('ajax.php',{data:chkdata}, function(response) {
            //alert(response);
        });
    } else {
        alert('선택한 항목이 없습니다.');
    }
});


<?php
if(isset($_POST['data'])){
    foreach($_POST['data'] as $column => $value) {
        echo $value;

        // $value 를 가지고 MySQL DB Delete 수행하는 로직 처리

    }
}
?>



728x90
블로그 이미지

Link2Me

,

테이블에서 체크박스를 전체 선택/해제 그리고 체크박스 선택된 것만 특정 액션을 취하도록 하고 싶은 경우가 있다.

이걸 고려한 HTML5 및 JQuery 를 작성해봤다.

프로그램은 테스트를 통해서 몸으로 느끼고 내것으로 만들어야만 하는 작업이라는 걸 계속 체험하고 있다.



전체선택 박스 만들기

<th class="header" width="30"><input type="checkbox" id="checkall" /></th>



선택삭제 박스 만들기

<td colspan="5" style="text-align:left;"><span class="btnbox1">선택삭제</span></td>


.btnbox1 {
    background-color:#BFD7E9;
    border: none;
    padding: 10px 10px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 12px;
    margin: 4px 2px;
    cursor: pointer;
    }


체크 박스 나오게하는 테이블 만들기

=== boardClass.php 파일의 일부 ===

// column 개수, 게시물 총개수 만큼 자동으로 화면 출력
function tablelistView_checkbox($result){
    global $DB_CONNECT;
    if(is_object($DB_CONNECT)  && get_class($DB_CONNECT)=='mysqli'){
        while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
            $view='<tr class="tr1">';
            foreach($row as $column => $value) {
                if($column== 'uid'){
                    $view.='<td><input type="checkbox" class="chkbox" name="uid[]" value="'.$value.'" /></td>';
                }
                $view.='<td class="td2">'.$value.'</td>';
            }
            $view.='</tr>';
            echo $view;
        }
    } else {
        while($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
            $view='<tr class="tr1">';
            foreach($row as $column => $value) {
                if($column== 'uid'){
                    $view.='<td><input type="checkbox" class="chkbox" name="uid[]" value="'.$value.'" /></td>';
                }
                $view.='<td class="td2">'.$value.'</td>';
            }
            $view.='</tr>';
            echo $view;
        }
    }
}


==== display.js ====

$(function(){
    // class td1 중에서 짝수번째 요소만 선택해서 배경색을 지정색으로 표시
    $(".tr1:odd").css("background-color","#F4F9FF");

    $('.tr1').click(function() {
        var idx=$(this).attr('id');
    }).mouseover(function() {
        $(this).children('.td2').css({'backgroundColor':'#DCDCDC','cursor':'pointer'});
    }).mouseout(function() {
        $(this).children('.td2').css({'backgroundColor':'#FFFFFF','cursor':'default'});
    });

    // 전체 선택, 전체 해제
    $("#checkall").change(function () {
        $("input:checkbox").prop('checked', $(this).prop("checked"));
    });

    $('.btnbox1').click(function(){
        var chkdata = new Array();
        // 헤더에 있는 체크박스는 제외
        //$('.chkbox:checked').each(function() {
        $('input:checkbox[name="uid[]"]:checked').each(function() {
            chkdata.push($(this).val());
            //alert($(this).val());
        });
        if(chkdata.length != 0){
            alert(chkdata);
            $.post('ajax.php',{chkdata:chkdata}, function(response) {
                alert(response);
            });
        } else {
            alert('선택한 항목이 없습니다.');
        }
    });

});


==== ajax.PHP ===

값이 POST 방식으로 전달되는 것만 알 수 있게 연습한 파일이다.

실제로는 MySQL DB와 연동하여 수행처리하는 로직을 만들면 된다.


<?php
if(isset($_POST['chkdata'])){
    /*
    foreach($_POST['chkdata'] as $column => $value) {
        echo $value;
        // MySQL 함수와 연동하여 DB Delete 수행 처리
    }
    */
    $response = implode(" , ",$_POST['chkdata']); // 배열을 문자열로 저장
    echo $response;

    if($response) {

       $sql = "delete from tablename where uid in (".$response.")";

        mysqli_query($dbconn,$sql);

    }

}
?>


=== 테이블을 출력하는 파일 전체 ===

http://link2me.tistory.com/1127 와 비교하여 달라진 부분이 뭔지 보면 알 것이다.


<?php
require_once 'dbconnect.php'; // db접속 성공
require_once 'phpclass/dbClass.php';
require_once 'phpclass/boardClass.php';

$c = new MySQLiDbClass();

$link_url = $_SERVER['PHP_SELF']; // 현재 실행중인 파일명 가져오기
$rowsPage = 12;

// 화면에 출력할 칼럼 발췌

$flddata ="uid,ItemName,Price,Quantity";
$where ="";
$curPage = isset($_GET['p']) ? $_GET['p'] : 1;
$result = $c->getDbArray('items',$where,$flddata,'',$rowsPage,$curPage);
$totalcnt = $c->getDbRows('items',$where);

$d = new boardClass();
?>
<!DOCTYPE html>
<head>
<meta charset=UTF-8" />
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
<meta http-equiv="X-UA Compatible" control="IE=edge,chrome=1" />
<link rel="stylesheet" type="text/css" href="../css/table.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="../js/display.js"></script>
</head>
<body>
<div class="container">
    <table class="table" width="800">
        <thead>
            <tr>
                <th class="header" width="30"><input type="checkbox" id="checkall" /></th>
                <th class="header" width="100">No</th>
                <th class="header" width="250">아이템</th>
                <th class="header" width="250">가격</th>
                <th class="header" width="200">수량</th>
            </tr>
        </thead>
        <?php
            // 테이블 리스트
            $d->tablelistView_checkbox($result);
        ?>
        <td colspan="5" style="text-align:left;"><span class="btnbox1">선택삭제</span></td>
    </table>
</div>
<?php $d->PageLinkView($link_url,$totalcnt,$rowsPage,$curPage);?>
</body>
</html>

728x90
블로그 이미지

Link2Me

,

HTML5 기반으로 MySQL 과 연동하여 테이블을 구성하는 것 연습삼아 작성해봤다.

테이블은 Csharp 연동시 샘플 테이블을 가지고 작성했다.

AutoSet9 은 MySQLi 방식으로 연동된다.

dbconnect.php 파일을 통해서 MySQLi DB와 연동하고 dbClass.php 파일을 연결하여 dbClass 함수를 호출하여 코드를 간결하게 작성했으며, 게시판 Class(boardClass) 에서 만든 코드를 이용하여 실제 코드는 몇줄 안되는 것처럼 보인다.


<?php
require_once 'dbconnect.php'; // db접속 성공
require_once 'phpclass/dbClass.php';
require_once 'phpclass/boardClass.php';

$c = new MySQLiDbClass();

$link_url = $_SERVER['PHP_SELF']; // 현재 실행중인 파일명 가져오기
$rowsPage = 12;


// 화면에 출력할 칼럼 발췌

$flddata ="uid,ItemName,Price,Quantity";
$where ="";
$curPage = isset($_GET['p']) ? $_GET['p'] : 1;
$result = $c->getDbArray('items',$where,$flddata,'',$rowsPage,$curPage);
$totalcnt = $c->getDbRows('items',$where);

$d = new boardClass();
?>
<!DOCTYPE html>
<head>
<meta charset=UTF-8" />
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
<meta http-equiv="X-UA Compatible" control="IE=edge,chrome=1" />
<link rel="stylesheet" type="text/css" href="../css/table.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="../js/display.js"></script>
</head>
<body>
<div class="container">
    <table class="table" width="800">
        <thead>
            <tr>
                <th class="header" width="100">No</th>
                <th class="header" width="250">아이템</th>
                <th class="header" width="250">가격</th>
                <th class="header" width="200">수량</th>
            </tr>
        </thead>
        <?php
            // 테이블 리스트
            $d->tablelistView($result);
        ?>
    </table>
</div>
<?php $d->PageLinkView($link_url,$totalcnt,$rowsPage,$curPage);?>
</body>
</html>


아래 코드는 위의 HTML 파일과 연관된 내용을 작성한다.


=== dbinfo.php ===

<?php
$db['host'] = "localhost";
$db['name'] = "csharp";
$db['user'] = "root";  // 원래는 root 사용자를 사용하면 안되는데 연습용인지라...
$db['pass'] = "autoset";
$db['port'] = "3306";
?>


=== dbconnect.php ===

<?php
include_once 'phpclass/dbinfo.php';
$DB_CONNECT = 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;   
    }
}
?>


=== dbClass.php ===

이 파일은 일부만 발췌하여 적는다.

본 코드에 사용된 함수는 http://link2me.tistory.com/1110 게시글에 올린 첨부파일을 받으면 된다.


class MySQLiDbClass {


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

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


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

}


=== boardClass.php ===

테이블 리스트를 보여주는 함수는 MySQL 접속인지, MySQLi 접속인지 자동으로 판단하는 함수 로직을 구현하여 코드의 확장성을 고려했다.

게시판에 주로 사용되는 사항을 함수화하여 코드를 간략화하였으나, 개발자 취향에 따라 코드를 함수화해서 사용하든 전부 나열식으로 코딩하든 개발자의 몫이다.

아울러 페이지 링크 부분은 세심하게 테스트까지 마친 코드이다.


class boardClass {

    // column 개수, 게시물 총개수 만큼 자동으로 화면 출력
    function tablelistView($result){
        global $DB_CONNECT;
        if(is_object($DB_CONNECT)  && get_class($DB_CONNECT)=='mysqli'){
            while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
                $view='<tr class="tr1">';
                foreach($row as $column => $value) {
                    $view.='<td class="td2">'.$value.'</td>';
                }
                $view.='</tr>';
                echo $view;
            }
        } else {
            while($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
                $view='<tr class="tr1">';
                foreach($row as $column => $value) {
                    $view.='<td class="td2">'.$value.'</td>';
                }
                $view.='</tr>';
                echo $view;
            }
        }
    }

    function PageLinkView($link_url,$totalcnt,$rowsPage,$curPage){
        echo '<div style="position:relative;vertical-align:top;padding-top:0;margin-top:0">';
            echo "<span style='position:absolute;top:10px;'>[총 자료수:".$totalcnt."]</span>";
            echo '<div class="pagelink">';
                $Info = $this->PageList($totalcnt,$rowsPage,$curPage,'');
                if($Info['current_block'] > 2){
                    echo "<a href='".$link_url."?p=1'>◀</a> ";
                }
                if($Info['current_block'] > 1){
                    echo "<a href='".$link_url."?p=".$Info['prev']."'>◁</a> ";
                }
                foreach($Info['current'] as $w) {
                    if($curPage == $w){
                        echo "<a href='".$link_url."?p=".$w."'><span style='color:red;font-size:22pt'>".$w."</span></a> ";
                    } else {
                        echo "<a href='".$link_url."?p=".$w."'>".$w."</a> ";
                    }
                }
                if($Info['current_block'] < ($Info['total_block'])){
                    echo "<a href='".$link_url."?p=".$Info['next']."'>▷</a> ";
                }
                if($Info['current_block'] < ($Info['total_block']-1)){
                    echo "<a href='".$link_url."?p=".$Info['totalPage']."'>▶</a> ";
                }
            echo '</div>';
        echo '</div>';
    }


    // $curPage : 현재 페이지, $totalcnt : 총 게시물수
    // $block_limit : 한 화면에 뿌려질 게시글 개수
    function PageList($totalcnt,$rowsPage,$curPage,$block_limit) {
        $block_limit = $block_limit ? $block_limit : 10;  // 한 화면에 보여줄 개수 기본 10으로 설정

        // 총 페이지수 구하기
        $totalPage = ceil($totalcnt/$rowsPage); 
        if($totalPage == 0) {
            ++$totalPage;
        }
        $total_block = ceil($totalPage / $block_limit); //전체 블록 갯수
       
        $curPage = $curPage ? $curPage : 1; // 현재 페이지

        // 현재 블럭 : 화면에 표시될 페이지 리스트
        $current_block=ceil($curPage/$block_limit);
        // 현재 블럭에서 시작페이지
        $fstPage = (((ceil($curPage/$block_limit)-1)*$block_limit)+1);
        // 현재 블럭에서 마지막 페이지
        $endPage = $fstPage + $block_limit -1;
        if($totalPage < $endPage) {
            $endPage = $totalPage;
        }

        // 시작 바로 전 페이지
        $prev_page = $fstPage - 1;
        // 마지막 다음 페이지
        $next_page = $endPage + 1;

        foreach(range($fstPage, $endPage) as $val) {
            $row[] = $val;
        }
        // 배열로 결과를 돌려준다.
        return array(
            'total_block' => $total_block,
            'current_block' => $current_block,
            'totalPage' => $totalPage,
            'fstPage' => $fstPage,
            'endPage' => $endPage,
            'prev' => $prev_page,
            'next' => $next_page,
            'current' => $row
        );
    }

}

728x90
블로그 이미지

Link2Me

,

C# 과 MySQL 연동방법에 대한 설명을 적어본다.

지금은 이런 연동방법을 고민할 필요는 없지만 최근에 네이버 지식인을 보다보니 질의로 올라오는 내용이 많아서 적어본다.


1. 개념 이해

2. phpMyAdmin 상에서 DB 생성 및 테이블 생성

3. C#과 MySQL 연동

이런 순서로 이해를 해야 한다.


1. 개념 이해

    - DB 와 연동하는 방식은 직접 연동방식과 간접 연동방식이 있다.

    - 직접 연동방식 : 연동을 위한 Driver 를 설치해야 한다.

                              http://link2me.tistory.com/758 참조하여 설치

    - 간접 연동방식 : 보안문제를 고려하여 Web 접속 방식으로 연동


2. phpMyAdmin 상에서 DB 생성 및 테이블 생성

    - 먼저 내 PC에 AutoSet9 을 설치하여 APM(Apache + PHP + MySQL) 환경을 만든다.

      http://link2me.tistory.com/797 참조

    - phpMyAdmin 접속을 한다.

      Web 브라우저에서 http://localhost 입력     



DB를 생성하고 나서 SQL 문을 복사하여 붙여넣기를 하면 테이블이 생성되고 샘플 데이터가 추가된다.



테이블 구조는

CREATE TABLE IF NOT EXISTS items (
  uid int(11) NOT NULL AUTO_INCREMENT,
  ItemName varchar(100) NOT NULL,
  Price double NOT NULL,
  Quantity int(11) NOT NULL,
  d_regis datetime NOT NULL,
  PRIMARY KEY (uid)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;


로 만들었다.


3. C# 에서 MySQL 연결

    - MySQL root 패스워드를 통한 연동은 매우 위험하다.

      따라서 해당 DB만 접속할 수 있는 User 및 권한을 부여해야 한다.

      http://link2me.tistory.com/431 참조

   - 샘플 사용자용으로 csharp_user 란 user 를 추가해보자.

     GRANT ALL PRIVILEGES ON csharp.items TO csharp_user@localhost IDENTIFIED BY 'csharp1234';

     GRANT ALL PRIVILEGES ON csharp.items TO csharp_user@'%' IDENTIFIED BY 'csharp1234';



이제 CsharpMySqlSample 소스를 실행하여

app.config 를 수정한다.


그리고 compile을 하면 접속이 성공됨을 확인할 수 있다.


본 소스는 허접하게 접속이 된다는 것만 보여주는 소스 수준이라고 보면 된다.

MySQL.zip


접속 성공하신 분은 공감이나 댓글 달아주세요.

지금 이런 내용을 정리할 시간은 없는데 MySQL 연동 성공이 일단되어야 내용을 이해하고 수정하고 응용하면서 실력을 키워 나갈 수 있기 때문에 허접한 수준이지만 올렸습니다.

사실 2015년도 C# 배울 당시에 연습했던 파일을 찾아서 테스트 해보고 올리는 겁니다.



728x90

'C# > C# SQL' 카테고리의 다른 글

C# MySQL 엑셀로 내보내기  (0) 2016.08.28
C# MySQL Update  (0) 2016.08.22
C# dataGridView CSV 파일로 저장  (0) 2016.01.29
C# MySqlDataReader Format  (0) 2016.01.28
C# SQLite 데이터 삭제 (transaction 반영)  (0) 2016.01.14
블로그 이미지

Link2Me

,

[Oracle] PL/SQL

SQL 2016. 11. 24. 12:21

PL/SQL(Procedure Language / Structured Query Language)은 오라클 DBMS에서 SQL 언어를 확장하기 위해 사용하는 컴퓨터 프로그래밍 언어. 주로 자료 내부에서 SQL 명령문만으로 처리하기에는 복잡한 자료의 저장이나 프로시저와 트리거 등을 작성하는 데 쓰인다.


주석 처리는 -- 또는 /*  */


CREATE OR REPLACE PROCEDURE 프로시져이름 (
    변수명 IN DATATYPE       -- Mode를 생략하면 default 로 IN
    변수명 OUT DATATYPE
    변수명 IN OUT DATATYPE
)
IS
    [선언문];  -- 변수의 선언

    -- v_cnt NUMBER := 0;   --프로시저 선언부에서 변수초기화하는 방법
BEGIN
    실행문;
    [EXCEPTION]
END;
/


/* 예제  */

CREATE OR REPLACE PROCEDURE update_sal
(
   /* IN  Parameter */
   v_empno    IN    NUMBER
)
IS
BEGIN

  UPDATE emp
  SET sal = sal  * 1.1
  WHERE empno = v_empno; -- PL/SQL 블록 내에서는 한 문장이 종료할 때마다 세미콜론(;) 을 사용.

  COMMIT;  -- 프로시저는 자동 커밋되지 않으므로 반드시 INSERT, UPDATE, DELETE 에서 COMMIT 해야한다.
END update_sal;
/     -- PL/SQL 블록은 행에 / 가 있으면 종결됨.


/* 프로시저 호출 */

EXECUTE update_sal(7369);


자료출처 : http://www.gurubee.net/lecture/1041  를 기준으로 다른 자료도 참조하면서 적었다.

교육은 받았는데 오라클 DB를 만질 일이 없다보니 교육도 집중해서 듣지 않아 세부적인 것은 잘 모른다.

그냥 간단한 것만 기록차원에서 적어둔다.


Function은 반드시 그 결과값을 리턴한다.


CREATE OR REPLACE FUNCTION 함수명 (
    변수명 [MODE] DATATYPE,
    변수명 [MODE] DATATYPE
)
RETURN 리턴할데이터타입 --값
IS
    [선언문];
BEGIN
    실행문;
    [EXCEPTION]
END;
/


CREATE OR REPLACE FUNCTION get_table_size
(p_table_name varchar2)

return number

is
  outval number;
BEGIN
  select ROUND(SUM(bytes)/1024/1024) INTO outval
  FROM user_segments 
  WHERE segment_name = p_table_name
  and segment_type ='TABLE'
  group by segment_name;
  RETURN outval;
END;
/

728x90

'SQL' 카테고리의 다른 글

[MySQL] 정규식을 활용한 검색 (REGEXP)  (0) 2016.12.11
MySQL 컬럼 순서 바꾸기  (0) 2016.12.10
[MySQL] 테이블 스키마 설계 고려사항  (0) 2016.11.19
[MySQL] 칼럼명 변경, 추가, 삭제  (0) 2016.10.26
[MySQL] SQL 모음  (0) 2016.09.23
블로그 이미지

Link2Me

,

년도와 월을 선택하면 해당월의 마지막 날짜가 자동으로 변경되는 jQuery 를 작성했다.


PHP 와 jQuery 값을 전달하는 방법을 잘 몰라 고생 좀 했다.


jQuery Ajax 를 이용해서 파일 A 에서 전달한 값을 가지고 파일 B(get_LastDay.php)에서 결과를 계산하고 그 결과를 받아서 다시 파일 A에 PHP 변수로는 전달할 수가 없더라. (방법이 있는데 못찾은 것인지는 모름)


년도는 선택하지 않고 월만 선택하는 것도 고려하다보니, 자바스크립트 함수를 사용하지 않고 Ajax 로 전달해서 PHP 함수식을 이용하여 계산된 결과를 받도록 처리했다.


function getLastDay(year, month){
    if(month==4 || month==6 || month==9 || month==11)
        return 30;
    else if(month==2){ //2월
        if(year%4 == 0) // 2월, 윤년일 때
            return 29;
        else    // 2월, 윤년이 아닐 때
            return 28
    } else {
        return 31;
    }
}


Ajax 로 전달받은 결과는 HTML 을 갱신할 수는 있다.

이 방법을 이용해서 코드를 작성했다.


참고로, 년도와 월을 모두 선택한다면 Ajax 사용하지 않고 위 함수를 이용하여 처리해도 된다.

var year = $("#year option:selected").val();
var month = $("#month option:selected").val();
var lastDate = getLastDay(year, month);

$("#day > option").remove(); // remove all items from list
for(i=1; i<=lastDate; i++){
    $("#day").append("<option value='"+ i +"'>"+ i +"</option>");
}


=== 파일 A ===

<?php
date_default_timezone_set('Asia/Seoul');
$YEAR_LAST = date("Y");
$cur_year = $YEAR_LAST;
$cur_month = date("m");
// 현재 월의 마지막 날짜를 일단 선택하도록 처리하고, 년/월을 선택하면 자동으로 변경
$last_day = date("t", mktime(0, 0, 1, $cur_month, 1, $cur_year));
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function(){ // html 문서를 다 읽어들인 후
    var year;
    var month;
    $('#year').on('change', function(){
        if($("#year option:selected").val() !== ""){
            year = $(this).find(":selected").val();
            month = $("#month option:selected").val();
            if($("#month option:selected").val() !== ""){
                $.post('get_LastDay.php',{year:year,month:month}, function(data) {
                    //alert(data);
                    $("#day > option").remove(); // remove all items from list
                    for(i=1; i<=data; i++){
                        $("#day").append("<option value='"+ i +"'>"+ i +"</option>");
                    }
                });
            }
        }
    });


    $('#month').on('change', function(){
        if($("#month option:selected").val() !== ""){
            year = $("#year option:selected").val();
            month = $(this).find(":selected").val();
            $.post('get_LastDay.php',{year:year,month:month}, function(data) {
                $("#day > option").remove(); // remove all items from list
                for(i=1; i<=data; i++){
                    $("#day").append("<option value='"+ i +"'>"+ i +"</option>");
                }
            });
        }
    });

});
</script>
<body>
<label>년도: </label>
<select id="year">
    <option value=''>년도</option>
    <?php for($i=2010; $i <= $YEAR_LAST; $i++){
        echo("<option value='$i'>$i 년</option>");
        } ?>
</select>

<select id="month">
<option value=''> 월 </option>
<?php for($i=1; $i <= 12; $i++){
    echo("<option value='$i'>$i</option>");
    } ?>
</select>

<select id="day">
<option value=''> 일 </option>
<?php for($i=1; $i <= $last_day; $i++){
    echo("<option value='$i'>$i</option>");
    } ?>
</select>

</body>
</html>


=== 파일 B : get_LastDay.php ===

<?php
$select_year = $_POST['year'];
$select_month = $_POST['month'];

$month_day = Array(31,29,31,30,31,30,31,31,30,31,30,31);

if(isset($select_year) && !empty($select_year) && isset($select_month) && !empty($select_month) ){
    // "t"는 두 번째 인자로 넘어온 해당 연,월에 대한 총 일수를 구하기 위한 파라미터
    $last_day = date("t", mktime(0, 0, 1, $select_month, 1, $select_year));
} else if(isset($select_month) && !empty($select_month)) {
    // 월만 선택한 경우에는 2월의 최대값이 28일지, 29일지 알 수 없으므로 최대 29를 선택하도록 처리
    $last_day = $month_day[$select_month-1];
}
echo $last_day;
?>



728x90
블로그 이미지

Link2Me

,

테이블 생성시 초보자들이 흔히 하는 실수는 primary key 부분 설계를 잘못하는 것 같다.

KIMSQ RB 의 테이블을 가져다 내 나름대로 간단하게 분석하고자 한다.

그누보드, KIMSQ RB 와 같은 빌더 들은 프로그램 고수가 만드는 거라고 보면 된다.
따라서 이런 빌더의 테이블 구조를 분석하는 것은 내 프로그램 지식 향상에 큰 도움이 된다.
여기서 테이블의 칼럼 하나 하나 분석하고자 하는 것은 아니다.

이런 방법으로 테이블 설계가되어 있구나 하는 정도만 이해하도록 하기 위함이다.

회원 ID를 저장할 때 테이블을 분리해서 저장하도록 설계되어 있다.

rb_s_mbrid 테이블의 uid 칼럼 = rb_s_mbrdata 테이블의 memberuid 와 관련이 있도록 설계되어 있다.

rb_s_mbrid 테이블의 uid 칼럼은 정수형 11자리, NOT NULL, AUTO_INCREMENT (자동증가) 로 되어 있다.

즉, 테이블에 데이터가 추가될 때마다 자동으로 증가되도록 설계되어 있다.

데이터를 삭제하고 새로운 데이터를 추가하면, 지워진 데이터 번호가 5번이라고 하자. 새로 추가된 데이터는 자동증가가 되므로 절대 5번이 되지 않는다. 데이터베이스의 기본 사상은 무결점이다.


PRIMARY KEY (`uid`), PRIMARY KEY (`memberuid`)

두개의 값은 항상 서로 같도록 설계하고 있다. rb_s_mbrid 테이블에서는 자동증가되도록 하고 다른 (rb_s_mbrdata) 테이블에서는 자동 증가는 없다.

PHP 코드 상에서 데이타를 저장할 때 두개의 테이블에 나누어서 저장되도록 되어 있다.


rb_s_mbrdata 테이블의 memberuid 칼럼은 rb_s_mbrid 테이블의 uid 칼럼의 FOREIGN KEY 다.


primary key 에 대해 검색하면 https://msdn.microsoft.com/ko-kr/library/ms179610.aspx 에 자세하게 나온다.

MS-SQL 에 대한 사항이지만, primary key 정의는 SQL 이 거의 동일하다고 보면 된다.


primary key

테이블에 대해 primary key 제약 조건을 지정하면 데이터베이스 엔진은 primary key 열에 대해 고유 인덱스를 자동으로 만들어 데이터 고유성을 적용한다.
또한 쿼리에서 primary key가 사용되는 경우 이 인덱스를 사용하여 데이터에 빠르게 액세스할 수 있다.
primary key 제약 조건이 두 개 이상의 열에 정의되는 경우 한 열에 중복된 값이 있을 수 있지만
primary key 제약 조건 정의에 있는 모든 열의 값 조합은 각각 고유해야 한다.

라고 나온다.


FOREIGN KEY

primary key 제약 조건과 달리 외래 키 제약 조건을 만들어도 해당 인덱스가 자동으로 생성되지 않는다.
외래 키 열은 쿼리에서 한 테이블의 외래 키 제약 조건 열을 다른 테이블의 기본 또는 고유 키 열과 연결하여 테이블의 데이터를 병합하는 조인에서 자주 사용된다.
데이터베이스 엔진 에서는 인덱스를 만들어 외래 키 테이블에 있는 관련 데이터를 빠르게 찾을 수 있다.


foreign key (칼럼명) references 부모테이블명(부모칼럼명) on delete cascade;


restrict

  참조하는 부모테이블의 칼럼(column)이 삭제되어도 지우지 마라.

 cascade

  참조하는 부모테이블의 칼럼(column)이 삭제되면 자식 테이블의 칼럼도 모두 삭제하라

 set null

  참조하는 부모테이블의 칼럼(column)이 삭제되면 자식 테이블의 칼럼이 모두 null이 된다.

 no action

  참조하는 부모테이블의 칼럼(column)이 삭제되어도 무시하라.

 set default

  참조하는 부모테이블의 칼럼(column)이 삭제되면 지정된 값으로 대체하라.


on delete rule 또는 on update rule 로 옵션을 지정할 수 있는데, 옵션을 주지 않으면 삭제와 변경이 제한된다.


primary key를 제대로 정의하는 것은 데이터베이스 디자인에 있어서 매우 중요한 출발점이다.
모든 테이블에는 primary key가 있어야 하며, 오직 하나의 primary key만 존재할 수 있다.
회원 테이블을 설계할 때 primary key 로 정의하는 칼럼은 uid 또는 idx 를 많이 사용한다.
id 또는 userID 칼럼은 중복없이 생성되도록 하기 위해서 unique index 를 설정한다.
primary key의 유무가 엄청난 성능 차이를 보인다.
일반적으로 primary key를 기준으로 데이터를 select 한다거나 primary key를 기준으로
다른 컬럼(들)의 값을 update 또는 delete하는 작업이 흔히 수행되기 때문에
테이블에 primary key를 정의해 주면 where 조건절에 primary key가 검색조건으로 사용된 쿼리들의 성능은 현저하게 향상된다.
primary key를 생성하지 않아서 primary key를 사용하는 쿼리들의 성능이 나쁜 것은 물론이며,
테이블에 잘못된 중복 데이터들이 저장됨으로 인하여 데이터 무결성까지 손상되어 있는 비극적인 상황까지 발전한 경우도 있다.

Primary key 컬럼은 반드시 NOT NULL로 정의해야 한다.


KEY `site` (`site`) : 인덱스 설정이 되어 있다는 의미다.

MySQL 의 인덱스는 여러개를 설정해도 실제 동작될 때에는 1개만 동작된다.

Oracle 은 여러개의 인덱스를 자동으로 선택하여 최적의 알고리즘으로 동작한다고 들었다.

따라서, 어떤 인덱스가 동작되도록 할 것인지는 설계자의 몫이다.


테이블 설계시 하나의 테이블에 모든 데이터가 저장되도록 하지 않고 다른 테이블에 분산해서 저장되도록 설계를 잘 하는 것이 중요하다.

테이블 검색시 문자열을 검색하는 것보다 숫자를 검색하면 성능이 훨씬 우수하다.

검색할 결과가 문자열이라고 해도 테이블 설계시 숫자로 검색되도록 설계하여 성능 향상이 되도록 하는 것도 필요하다.


CREATE TABLE IF NOT EXISTS `rb_s_mbrid` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `site` int(11) NOT NULL DEFAULT '0',
  `id` varchar(50) NOT NULL DEFAULT '',
  `pw` varchar(50) NOT NULL DEFAULT '',
  PRIMARY KEY (`uid`),
  KEY `site` (`site`),
  KEY `id` (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


CREATE TABLE IF NOT EXISTS `rb_s_mbrdata` (
  `memberuid` int(11) NOT NULL,
  `site` int(11) NOT NULL DEFAULT '0',
  `auth` tinyint(4) NOT NULL DEFAULT '0',
  `sosok` int(11) NOT NULL DEFAULT '0',
  `level` int(11) NOT NULL DEFAULT '0',
  `comp` tinyint(4) NOT NULL DEFAULT '0',
  `admin` tinyint(4) NOT NULL DEFAULT '0',
  `adm_view` text NOT NULL,
  `email` varchar(50) NOT NULL DEFAULT '',
  `name` varchar(30) NOT NULL DEFAULT '',
  `nic` varchar(50) NOT NULL DEFAULT '',
  `grade` varchar(20) NOT NULL DEFAULT '',
  `photo` varchar(200) NOT NULL DEFAULT '',
  `home` varchar(100) NOT NULL DEFAULT '',
  `sex` tinyint(4) NOT NULL DEFAULT '0',
  `birth1` smallint(6) NOT NULL DEFAULT '0',
  `birth2` smallint(4) unsigned zerofill NOT NULL DEFAULT '0000',
  `birthtype` tinyint(4) NOT NULL DEFAULT '0',
  `tel1` varchar(14) NOT NULL DEFAULT '',
  `tel2` varchar(14) NOT NULL DEFAULT '',
  `zip` varchar(6) NOT NULL DEFAULT '',
  `addr0` varchar(6) NOT NULL DEFAULT '',
  `addr1` varchar(200) NOT NULL DEFAULT '',
  `addr2` varchar(100) NOT NULL DEFAULT '',
  `job` varchar(30) NOT NULL DEFAULT '',
  `marr1` smallint(6) NOT NULL DEFAULT '0',
  `marr2` smallint(4) unsigned zerofill NOT NULL DEFAULT '0000',
  `sms` tinyint(4) NOT NULL DEFAULT '0',
  `mailing` tinyint(4) NOT NULL DEFAULT '0',
  `smail` tinyint(4) NOT NULL DEFAULT '0',
  `point` int(11) NOT NULL DEFAULT '0',
  `usepoint` int(11) NOT NULL DEFAULT '0',
  `money` int(11) NOT NULL DEFAULT '0',
  `cash` int(11) NOT NULL DEFAULT '0',
  `num_login` int(11) NOT NULL DEFAULT '0',
  `pw_q` varchar(250) NOT NULL DEFAULT '',
  `pw_a` varchar(100) NOT NULL DEFAULT '',
  `now_log` tinyint(4) NOT NULL DEFAULT '0',
  `last_log` varchar(14) NOT NULL DEFAULT '',
  `last_pw` varchar(8) NOT NULL DEFAULT '',
  `is_paper` tinyint(4) NOT NULL DEFAULT '0',
  `d_regis` varchar(14) NOT NULL DEFAULT '',
  `tmpcode` varchar(50) NOT NULL DEFAULT '',
  `sns` text NOT NULL,
  `addfield` text NOT NULL,
  `cp` int(11) DEFAULT '0',
  `mcp` int(11) DEFAULT '0',
  `cpcode` int(11) DEFAULT NULL,
  `recommand` varchar(60) DEFAULT NULL,
  `broadcast` int(5) NOT NULL DEFAULT '0',
  PRIMARY KEY (`memberuid`),
  KEY `site` (`site`),
  KEY `auth` (`auth`),
  KEY `comp` (`comp`),
  KEY `sosok` (`sosok`),
  KEY `level` (`level`),
  KEY `admin` (`admin`),
  KEY `email` (`email`),
  KEY `name` (`name`),
  KEY `nic` (`nic`),
  KEY `sex` (`sex`),
  KEY `birth1` (`birth1`),
  KEY `birth2` (`birth2`),
  KEY `birthtype` (`birthtype`),
  KEY `addr0` (`addr0`),
  KEY `job` (`job`),
  KEY `marr1` (`marr1`),
  KEY `marr2` (`marr2`),
  KEY `sms` (`sms`),
  KEY `mailing` (`mailing`),
  KEY `smail` (`smail`),
  KEY `point` (`point`),
  KEY `usepoint` (`usepoint`),
  KEY `now_log` (`now_log`),
  KEY `d_regis` (`d_regis`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


728x90

'SQL' 카테고리의 다른 글

MySQL 컬럼 순서 바꾸기  (0) 2016.12.10
[Oracle] PL/SQL  (0) 2016.11.24
[MySQL] 칼럼명 변경, 추가, 삭제  (0) 2016.10.26
[MySQL] SQL 모음  (0) 2016.09.23
엑셀에서 INSERT 쿼리문 만들기  (0) 2016.07.29
블로그 이미지

Link2Me

,

select 박스를 선택한 값을 jQuery 로 해서 Ajax 로 전송한 결과값을 다시 받은 코드를 구현해봤다.

이 코드를 보면 Ajax 로 값을 어떻게 전달하고, 결과를 다시 어떻게 받은지 알 수 있다.

ajaxPHP.php 파일에서 ehco 의 결과값을 받는다는 걸 알면 응용하는 것은 쉽다.

form 으로 넘기지 않아도 데이터를 전달하고 결과를 받을 수 있다는 걸 알 수 있다.


=== selected html ===

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function(){ // html 문서를 다 읽어들인 후
    $('#selectID').on('change', function(){
        if(this.value !== ""){
            var optVal = $(this).find(":selected").val();
            //alert(optVal);
            $.post('ajaxPHP.php',{optVal:optVal}, function(data) {
                alert(data);  // data는 ajaxPHP.php 파일에서 ehco 문의 결과 값             
            });

        }
    });
});
</script>
<body>
<label>select option: </label>
<select id="selectID">
    <option value="">구분</option>
    <option value="1">Option 1</option>
    <option value="2">Option 2</option>
    <option value="3">Option 3</option>
    <option value="4">Option 4</option>
</select>
</body>
</html>


=== ajaxPHP.php ===

<?php
$ajax = $_REQUEST['optVal'];
if($ajax == 1) {
    echo '첫번째';
} else if($ajax == 2) {
    echo '두번째';
} else if($ajax == 3) {
    echo '세번째';
} else if($ajax == 4) {
    echo '네번째';
}
?>


테스트 해보고 싶으신 분은 코드를 복사해서 테스트 해보세요. 100% 동작되는 코드입니다.


728x90
블로그 이미지

Link2Me

,

select 박스에서 선택한 값을 읽어오는 jQuery 코드 예제다.

selected 된 값을 표현하는 방법은 아래 3가지 모두 가능하다.

this.value;
$("#selectID option:selected").val();

$(this).find(":selected").val();


라디오버튼에서 선택할 경우

$(this).find(":checked").val();


=== 샘플 ===

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function(){ // html 문서를 다 읽어들인 후
    $('#selectID').on('change', function(){
        if(this.value !== ""){
            //var optVal = $("#selectID option:selected").val();
            var optVal = $(this).find(":selected").val();
            alert(optVal);
        }
    });
});
</script>
<body>
<label>select option: </label>
<select id="selectID">
    <option value="">구분</option>
    <option value="1">Option 1</option>
    <option value="2">Option 2</option>
    <option value="3">Option 3</option>
    <option value="4">Option 4</option>
</select>
</body>
</html>

728x90
블로그 이미지

Link2Me

,

일일 통계 생성을 위한 테이블 구조 및 테이블에 데이터를 저장하기 위한 코드를 작성했다.

가장 간단하게 userID 별 접속횟수, 날짜별 접속횟수만 기록되게 구현했다.


테이블 구조

CREATE TABLE IF NOT EXISTS Access_Stats (
  uid int(11) NOT NULL AUTO_INCREMENT,
  date char(8) NOT NULL,
  YM char(6) NOT NULL,
  day char(2) NOT NULL,
  IDCnt int(11) NOT NULL DEFAULT '0',
  dailyCnt int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (uid),
  KEY date (date)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;


=== 일일단위 통계 생성을 위한 코드 ===

<?php
require_once "dbconnect.php";
require_once "phpclass/statsClass.php";
$a=new statsClass();

// 일일 통계 기록
date_default_timezone_set('Asia/Seoul');
$date = date("Ymd", mktime(0,0,0,date("m"), date("d")-1, date("Y"))); // 어제
$YM = substr($date,0,6);
$day = substr($date,6,2);

if($a->Access_Stats($date) == '0'){ // 해당 날짜에 기록된 정보가 없으면
    $sql = "INSERT INTO Access_Stats (date,YM,day,IDCnt,dailyCnt) (select ".$date.",".$YM.",".$day.",count(distinct LogID),sum(hit) from AccessLog where date='".$date."')";
    @mysql_query($sql);
} else {
    $row = $a->AccessLogCnt($date); // 배열로 가져옴
    $sql = "Update Access_Stats SET IDCnt='".$row[0]."',dailyCnt='".$row[1]."' where date='".$date."'";
    @mysql_query($sql);
}

echo "Work done";
exit;
?>


=== statsClass.php ===

<?php
class statsClass {

    function Access_Stats($date){
        global $db;
        $sql ="select count(date) from Access_Stats where date='".$date."'"; // 기록된 데이터 있는지 조회
        $result=mysql_query($sql);
        if($row=mysql_fetch_row($result)){
            return $row[0];
        }
    }

    function AccessLogCnt($date){
        global $db;
        $sql ="select count(distinct userID),sum(hit) from AccessLog where date='".$date."'";
        $result=mysql_query($sql);
        if($row=mysql_fetch_row($result)){
            return $row; // 배열을 반환
        }
    }

}
?>


매일 일정한 시간에 테이블에 데이터를 자동으로 저장하기 위해서는 crontab 을 이용해야 한다.

crontab 을 이용하기 위한 코드는 아래와 같이 하면 된다.

=== accessLog.php ===

!#/usr/local/php/bin/php -q
<?php
// cron 방식 DB 접속
require_once "/usr/local/apache/htdocs/dbconnect.php";
require_once "/usr/local/apache/htdocs/phpclass/statsClass.php";
$a=new statsClass();

// 일일 통계 기록
date_default_timezone_set('Asia/Seoul');
$date = date("Ymd", mktime(0,0,0,date("m"), date("d")-1, date("Y"))); // 어제
$YM = substr($date,0,6);
$day = substr($date,6,2);
if($a->Access_Stats($date) == '0'){
    $sql = "INSERT INTO Access_Stats (date,YM,day,IDCnt,dailyCnt) (select ".$date.",".$YM.",".$day.",count(distinct LogID),sum(hit) from AccessLog where date='".$date."')";
    @mysql_query($sql);
} else {
    $row = $a->AccessLogCnt($date);
    $sql = "Update Access_Stats SET IDCnt='".$row[0]."',dailyCnt='".$row[1]."' where date='".$date."'";
    @mysql_query($sql);
}

echo "
Work done";
exit;
?>


=== crontab 파일내에 코드 추가 ===

crontab 사용법은 http://link2me.tistory.com/990 참조

PHP 와 crontab 에 대한 사항을 좀 더 알고 싶다면 http://link2me.tistory.com/1013 참조


먼저 php 가 설치된 경로를 찾아야 한다.

// PHP 경로 찾기
whereis php


crontab 에 추가할 내용

// 매일 2시 0분에 실행
0 2 * * * /usr/local/php/bin/php /usr/local/apache/htdocs/stats/accessLog.php

// 매 5분마다 실행 ==> 실제 제대로 저장되는지 여부를 테스트
*/5 * * * * /usr/local/php/bin/php /usr/local/apache/htdocs/
stats/accessLog.php

728x90
블로그 이미지

Link2Me

,

C# 에서 Web 접속방식으로 로그인 처리를 위한 방법을 소개한다.


http://link2me.tistory.com/970 에 기본적인 사항을 적어두었다.


HttpClient 방식으로 로그인하는 방법을 알아두면 여러모로 유용하다.

로그인 뿐만 아니라 Web 접속방식으로 데이터를 주고 받을 때 많이 활용된다.

json 형태로 데이터를 주고 받기 위한 함수만 추가로 만들어서 사용하면 된다.


string json 부분을 보면 PHP 로그인 함수 결과값을 받는다.

PHP 에서 도대체 어떤 걸 받는거지? 라고 하는 의문이 들 것이다.

PHP 결과를 받는 것은 echo 문의 결과값이다.

이 결과값이 배열일 수도 있고 단순한 텍스트일 수도 있다.

echo 문으로 출력되는 결과를 어떻게 만들 것인가 하는 것은 PHP 에서 고민하면 된다.

가령 성공하면 1, 실패하면 0, DB접속 실패하면 -1 이런식으로 PHP 로그인 함수를 만들어도 된다.

개발자의 취향에 따라 개발해서 연동하면 된다.


=== LoginForm.cs ====

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Http;
using System.Web.Script.Serialization;
using System.IO;
using System.Configuration;

namespace Dennis_Sentence
{
    public partial class frmLogin : Form
    {
        Boolean CK = false;
        private string strID;

        public frmLogin()
        {
            InitializeComponent();
        }

        public string getstrID   // ID를 알려주는 속성 설정
        {
            get { return strID; }
        }

        private void frmLogin_Load(object sender, EventArgs e)
        {
            txtID.Text = Properties.Settings.Default.LoginIDSave;
            txtPwd.Text = Properties.Settings.Default.SitePasswd;
            if (Properties.Settings.Default.LoginIDSave.Length > 0 && Properties.Settings.Default.SitePasswd.Length > 0)
            {
                IDSave.Visible = false;
                IDdelete.Visible = true;
            }
            else
            {
                IDSave.Visible = true;
                IDdelete.Visible = false;
            }
        }

        /// <summary>
        /// SQL 인젝션 필터 - Select 에서 조건절 필터링
        /// </summary>
        private static string Filtering(string inputSQL)
        {
            return inputSQL.Replace(":", "").Replace("+", "").Replace(";", "").Replace("--", "").Replace("\"", "");
        }

        private void frmLogin_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!CK)
            {
                Application.Exit();
            }
        }

        private void btnOK_Click(object sender, EventArgs e)
        {

            if (this.txtID.Text == "")
            {
                MessageBox.Show("로그인 아이디를 입력하세요", "알림", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                this.txtID.Focus();
            }
            else if (this.txtPwd.Text == "")
            {
                MessageBox.Show("로그인 비밀번호를 입력하세요", "알림", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                this.txtPwd.Focus();
            }
            else
            {
                if (IDSave.Checked)
                {
                    Properties.Settings.Default.LoginIDSave = txtID.Text;
                    Properties.Settings.Default.SitePasswd = txtPwd.Text;
                    Properties.Settings.Default.Save();
                }

                if (IDdelete.Checked)
                {
                    Properties.Settings.Default.LoginIDSave = string.Empty;
                    Properties.Settings.Default.SitePasswd = string.Empty;
                    Properties.Settings.Default.Save();
                }

                mySqlLogin();
            }

        }

        private void mySqlLogin()
        {
            try
            {
                var client = new HttpClient();
                var postData = new List<KeyValuePair<string, string>>();
                string URL = "http://IP주소/Login.php";
                postData.Add(new KeyValuePair<string, string>("loginID", Filtering(txtID.Text.Trim())));
                postData.Add(new KeyValuePair<string, string>("loginPW", Filtering(txtPwd.Text.Trim())));
                var formContent = new FormUrlEncodedContent(postData);
                var result = client.PostAsync(URL, formContent).Result;
                string json = result.Content.ReadAsStringAsync().Result;
                //MessageBox.Show(json);
                if (json == "1") // PHP 로그인 함수에서 로그인 성공시의 echo 결과값
                {
                    CK = true;
                    strID = txtID.Text;
                    this.Close();  // 현재 폼 닫기
                }
                else
                {
                    MessageBox.Show("로그인 실패", "Login Fail", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    CK = false;
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show("Error :" + ex.Message);
            }
        }       

        private void btnCancel_Click(object sender, EventArgs e)
        {
            //CK = false;
            Application.Exit();  // 취소버튼을 누르면 프로그램 완전 종료 처리
        }

        private void txtPwd_KeyDown(object sender, KeyEventArgs e)  // 엔터키를 눌렀다면...
        {
            if (e.KeyCode == Keys.Enter)
            {
                btnOK_Click(sender, e);
            }
        }

        private void IDSave_CheckedChanged(object sender, EventArgs e)
        {
            if (IDdelete.Checked == true)
            {
                IDdelete.Checked = false;
            }
        }

        private void IDdelete_CheckedChanged(object sender, EventArgs e)
        {
            if (IDSave.Checked == true)
            {
                IDSave.Checked = false;
            }
        }
    }
       
}


=== Login.php ===

<?php
session_start();
@extract($_POST);
if(isset($loginID) && !empty($loginID) && isset($loginPW) && !empty($loginPW)) {

    require_once 'phpclass/dbinfo.php';
    require_once 'phpclass/dbClass.php';
    $conn=new MySQLDbClass(); // DB 함수 객체 생성
    $DB_CONNECT = $conn->isConnectDb($DB); // 안드로이드폰에서는 반드시 객체로 생성해야 정상접속
    require_once 'phpclass/loginClass.php';
    $c=new LoginClass(); // 로그인 객체 생성

    $row = $c->WebUserAuthCheck($loginID,$loginPW);  // 로그인 체크 함수
    if(is_array($row)) {
        if(!empty($row['id'])) {
            $_SESSION['userID'] = $row['id'];
            echo 1; // 로그인 성공
        } else {
            echo 0; // 로그인 실패
        }
    } else if($row == '0'){
        echo 0; // 로그인 실패
    } else {
        echo 0; // 로그인 실패
    }

}
?>


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

728x90

'C# > 통신' 카테고리의 다른 글

C# Web 자동로그인 처리  (1) 2018.03.15
C# 과 Web  (0) 2018.03.10
C# webFile 다운로드 함수  (0) 2016.11.12
C# GetAsyncDataFromWeb  (0) 2016.08.21
C# GetDataFromWeb 사용자 함수  (0) 2016.08.20
블로그 이미지

Link2Me

,

HTML, javaScript, jQuery 는 Client에서 해석하는 언어이고, PHP는 서버와의 통신을 위한 스크립트 언어다.

서버상에서 가져온 파일을 읽으려면 클라이언트에서 인식할 수 있도록 해줘야 한다.

아니면 PHP 코드를 HTML 파일보다 먼저 읽어들이도록 위치를 위에다 놓은 것도 방법이다.


눈에 보이지 않게 <div id="div1" data-lat="<?php echo $lat;?>"></div> 를 이용해서 PHP 변수를 기록하면, HTML 에 기록된 내용을 jQuery, javaScript 에서 읽어올 수 있다.


PHP 변수를 받는 방법은 다른 파일에서 넘겨준 걸 읽을 때는 $_GET, $_POST 배열로 받아서 처리하면 된다.

아니면 직접 include_once '읽고자하는 파일'; 을 지정해주고 파일을 include 하면 해당 파일의 변수가 인식된다.


속성값 읽어오기

자바스크립트에서는 document.getElementById('div1').getAttribute('data-lat');

jQuery 에서는 $("#div1").attr('data-lat');


속성값 변경하기

자바스크립트에서는 document.getElementById('div1').setAttribute('data-lat','변경할값');

jQuery 에서는 $("#div1").attr('data-lat','변경할값');


DB에서 테이블 형태로 읽어온 걸 화면에 표시하고 테이블내 한 행의 게시글의 특정 정보를 알아내고자 할 때에는 this 를 사용한다.

group=$(this).attr('data-group');


==== 예제 파일 =====

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function(){ // html 문서를 다 읽어들인 후
    //var lat = $("#div1").attr('data-lat'); // jQuery 방식
    var lat = document.getElementById('div1').getAttribute('data-lat'); // javaScript 방식
    var lon = $("#div2").attr('data-lon');
    alert("lat:"+ lat +" lon:"+ lon);
});
</script>
<body>
<?php
//include_once 'getPHP.php'; 다른 파일 내용을 읽어오고자 할 때
$lat = 33.4505296;
$lon = 126.570667;
?>
<div id="div1" data-lat="<?php echo $lat;?>"></div>
<div id="div2" data-lon="<?php echo $lon;?>"></div>
</body>
</html>

728x90
블로그 이미지

Link2Me

,

C# Web 파일을 PC에 다운로드하기 위해 만든 함수다.

사용법은 Web 파일 다운로드 게시글을 참조하면 된다.


코드

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace NameSpace
{
    class Folder
    {
        public static void MyFolderCreate(string myfolder)
        {
            string MyPath = MyFolder(myfolder);
            if (!Directory.Exists(MyPath))
            {
                Directory.CreateDirectory(MyPath);
            }
        }

        public static string MyFolder(string myfolder)
        {
            string UserPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // User Documents 폴더
            return UserPath + "\\" + myfolder;
        }

        public static string MyfilePath(string myfolder, string appName)
        {
            return Folder.MyFolder(myfolder) + "\\" + appName;
        }

        public static void MyFolderDelete(string path)
        {
            DeleteDirectory(path, false);
        }

        public static void DeleteDirectory(string path, bool recursive)
        {
            if (recursive)
            {
                var subfolders = Directory.GetDirectories(path);
                foreach (var subfolder in subfolders)
                {
                    DeleteDirectory(subfolder, recursive);
                }
            }

            // Get all files of the folder
            var files = Directory.GetFiles(path);
            foreach (var file in files)
            {
                var attribute = File.GetAttributes(file);
                if ((attribute & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
                {
                    File.SetAttributes(file, attribute ^ FileAttributes.ReadOnly);
                }
                File.Delete(file);
            }
            Directory.Delete(path);
        }

        public static string SSplit(string _body, string _parseString, int index)
        {
            // 엑셀 VBA 에서 사용하는 Split 함수처럼 만든 사용자 함수
            string varTemp = _body.Split(new string[] { _parseString }, StringSplitOptions.None)[index];
            return varTemp;
        }
    }
}


728x90
블로그 이미지

Link2Me

,

C#에서 Web 방식으로 파일을 다운로드하는 코드이다.

오래되어 기억은 가물가물하지만 구글링도하고 블로그 검색으로 찾은 걸 약간 수정한거 같기는 하다.

최근에 SSD 이상증상으로 데이터를 살리지 못한 경험도 있고 해서 블로그에 기록해둔다.


사용법 예시

사용법 예시는 전체적으로 동작되는 걸 보여주는게 아니라 이런식으로 활용할 수 있다는 것만 간략하게 기록


private void webFileDown(string mp3sub, string mp3file)
{
    // 파일 다운로드
    string webfilePath = string.Format("http://ipaddress/{0}/{1}", mp3folder, mp3file);
    string localfilePath = Folder.MyfilePath("abcdef", mp3file);
    if (webFile.WebExists(webfilePath))
    {
        int write = webFile.DownloadFile(webfilePath, localfilePath);  // 파일 사이즈를 반환
    }
    else
    {
        MessageBox.Show("다운받을 파일이 존재하지 않습니다");
        return;
    }
}             



코드

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Windows.Forms;

namespace NameSpace  // 수정해서 사용 필요
{
    class webFile
    {
        /// <summary>
        /// 웹파일 다운로드
        /// </summary>
        /// <param name="remoteFilename">웹 서버 파일</param>
        /// <param name="localFilename">PC 저장 파일</param>
        /// <returns>파일 크기를 반환</returns>
        public static int DownloadFile(String remoteFilename, String localFilename)
        {
            // Function will return the number of bytes processed to the caller. Initialize to 0 here.
            int bytesProcessed = 0;

            // Assign values to these objects here so that they can be referenced in the finally block
            Stream remoteStream = null;
            Stream localStream = null;
            WebResponse response = null;

            // Use a try/catch/finally block as both the WebRequest and Stream classes throw exceptions upon error
            try
            {
                WebRequest request = WebRequest.Create(remoteFilename); // 원격 파일 다운을 위한 객체 생성
                if (request != null)
                {
                    response = request.GetResponse(); // 서버로부터 WebResponse 오브젝트 받아옴
                    if (response != null)
                    {
                        // Once the WebResponse object has been retrieved, get the stream object associated with the response's data
                        remoteStream = response.GetResponseStream();
                        //localStream = File.Create(localFilename);  // local File 생성
                        localStream = new FileStream(localFilename, FileMode.OpenOrCreate, FileAccess.ReadWrite);

                        byte[] buffer = new byte[1024];  // 1k 버퍼 할당
                        int bytesRead;

                        // Simple do/while loop to read from stream until no bytes are returned
                        do
                        {
                            bytesRead = remoteStream.Read(buffer, 0, buffer.Length); // 1K 바이트씩 데이터 읽기
                            localStream.Write(buffer, 0, bytesRead); // PC에 데이터 저장
                            bytesProcessed += bytesRead;  // 전체 바이트 수 체크를 위해 누적
                        } while (bytesRead > 0);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                if (response != null) response.Close(); //WebResponse객체 Close
                if (remoteStream != null) remoteStream.Close();
                if (localStream != null) localStream.Close();
            }

            return bytesProcessed;  // 수신한 전체 바이트수를 리턴(파일의 크기)
        }

        /// <summary>
        /// 웹에 파일이 존재하는지 검사하여 있으면 true 반환
        /// </summary>
        /// <param name="url">Web 파일 경로</param>
        /// <returns></returns>
        public static bool WebExists(string url)
        {
            bool ret = true;
            if (url == null)
                return false;
            HttpWebResponse response = null;
            try
            {
                var request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "HEAD";
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException)
            {
                ret = false;
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }
            return ret;
        }


    }
}


728x90

'C# > 통신' 카테고리의 다른 글

C# 과 Web  (0) 2018.03.10
C# Web 접속 로그인함수 만들기(HttpClient 방식)  (0) 2016.11.14
C# GetAsyncDataFromWeb  (0) 2016.08.21
C# GetDataFromWeb 사용자 함수  (0) 2016.08.20
C# comboBox 에 Text, Value 추가 및 POST, JSON  (0) 2016.08.19
블로그 이미지

Link2Me

,

jQuery Mobile 템플릿을 사용하여 Layout 기본 구조를 파악해보자.



jQuery Mobile 에 대한 자세한 설명은 http://www.w3schools.com/jquerymobile/default.asp 에서 영문으로 찬찬히 읽어가면서 습득하면 도움된다.

jQuery Mobile 버전이 달라지면서 표시되는 색상도 변경될 수 있으므로 무조건 버전을 높은걸 사용하는게 좋지 않을 수도 있다. 높은 버전을 사용하면 변경된 부분을 파악해서 수정해주어야 한다.


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="pragma" content="no-cache" />

<!-- Include meta tag to ensure proper rendering and touch zooming -->
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width" />

<!-- Include jQuery Mobile stylesheets -->

<link href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.css" rel="stylesheet" type="text/css" />

<!-- Include the jQuery library -->

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>

<!-- Include the jQuery Mobile library -->

<script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
</head>


<body>
<div data-role="page">
    <div data-role="header" data-position="fixed" data-theme="b">
        <h1>Header title</h1>
    </div>
    <div id="content" data-role="content" data-theme="e">
        <ul data-role="listview">
        <?php
            echo  '<li>';
            echo  '<a href="#">목록이 없습니다.</a>';
            echo  '</li>';
        ?>
        </ul>
    </div>
    <div data-role="footer" data-position="fixed" data-theme="d">
        <table>
        <tr>
        <td width="15%"><a href="index.html" data-role="button" data-icon="plus" data-iconpos="left">추가</a>
        </td>
        <td width="70%" align=center>Footer Title</td>
        <td width="15%"></td>
        </tr>
        </table>
    </div>
</div>
</body>
</html>


일반적인 웹 사이트의 경우 1 페이지 = 1 HTML 파일이지만, jQuery Mobile 에서는 data-role 속성 'page'를 갖는 div 요소가 1페이지가 된다.

http://www.w3schools.com/jquerymobile/tryit.asp?filename=tryjqmob_pages

에서 보면 1 페이지 안에
<div data-role="page" id="pageone">

<div data-role="page" id="pagetwo">

로 구분하여 작성된 것을 실행해 볼 수 있다. 즉 HTML 페이지는 1Page이지만, jQuery Mobile 에서는 2Page 인 것처럼 만들 수 있다는 의미다.


data-theme="b" 를 사용하여 테마를 변경할 수 있다. (a ~ e 까지 5개 테마)

data-inset="true" 는 모서리를 둥글게 처리

data-split-icon="gear" : 스플릿된 우측모양이 기어모양

data-position="fixed" : 하단에 고정하는 기능

data-rel="dialog" : 다이얼로그 팝업창으로 띄워라

<div data-role="header" data-add-back-btn="true" data-back-btn-text="이전">

data-add-back-btn="true" : Back 버튼 표시

data-back-btn-text="뒤로" : 라벨 변경

<ul data-role="listview" data-theme="e" data-inset="true">

data-theme="e" : 리스트 테마의 변경

data-inset="true" : 모서리를 둥글게 처리

<li data-theme="b" >

data-theme="b" : 해당 항목만 별도로 리스트 테마 변경

<li data-role="list-divider">

data-role="list-divider" : 리스트에 제목 설정

<span class="ui-li-count">10</span><!-- class="ui-li-count" 은 카운트 버블 표시 -->

<ul data-role="listview" data-count-theme="b" data-filter="true" data-filter-placeholder="검색어">
        <!--data-count-theme="c" : 카운드 버블의 테마 변경 -->
        <!--data-filter="true" : 검색 필터 => 일치하는 검색어만 표시됨 -->
        <!--data-filter-placeholder="검색어" : 플레이스 홀더 변경 -->
        <li><a href="#index" data-transition="slideup">
        <!--data-transition="slideup" 위쪽으로 슬라이드되면서 페이지 전환 -->
        <h3>메인 페이지</h3>
        </a></li>
        <li><a href="#about" data-transition="slide">
         <!--data-transition="slide" 왼쪽으로 슬라이드되면서 페이지 전환 -->

data-transition="flip"

data-transition="flip" data-direction="reverse"

<li><a href="#access" data-transition="slide">
    <p class="ui-li-aside">보충정보 표시</p>
    <!--class="ui-li-aside" 속성 추가시 보충정보 표시됨 -->
    <h3>오시는 길</h3>
    <p>설명 내용</p> <!-- 설명문이 있는 리스트 표시됨 -->
    <span class="ui-li-count">99</span>
    <!-- class="ui-li-count" 은 카운트 버블 표시 -->
</a></li>
<li><a href="#contact" data-transition="pop">
    <p class="ui-li-aside">보충정보 표시</p>
    <!--class="ui-li-aside" 속성 추가시 보충정보 표시됨 -->
    <h3>문의</h3>
    <p>설명 내용</p> <!-- 설명문이 있는 리스트 표시됨 -->
</a></li>

<div data-role="content">
    <form action="form.php" method="post">
        <div data-role="fieldcontain">
            <label for="name">이름</label>
            <input type="text" id="name"><!-- id는 전체 소스 기준으로 중복되지 않게 처리해라. -->
        </div>
        <div data-role="fieldcontain">
            <label for="gender">성별</label>
            <select name="gender" id="gender" data-role="slider"><!--플립스위치 표시 -->
            <option value="남자">남자</option>
            <option value="여자">여자</option>
            </select>
        </div>
        <div data-role="fieldcontain">
            <fieldset data-role="controlgroup">
                <legend>주제별 문의</legend>
                <input type="checkbox" name="type1" id="type1" value="수주">
                <label for="type1">프로그램 수주</label>
                <input type="checkbox" name="type2" id="type2" value="기획">
                <label for="type2">프로그램 기획</label>
                <input type="checkbox" name="type3" id="type3" value="개발">
                <label for="type3">프로그램 개발</label>
                <input type="checkbox" name="type4" id="type4" value="배포">
                <label for="type4">프로그램 배포</label>
            </fieldset>
        </div>
        <div data-role="fieldcontain">
            <label for="comment">문의 내용</label>
            <textarea id="comment"></textarea>
        </div>
        <div data-role="fieldcontain">
            <input type="button" value="취소" data-theme="a" data-icon="delete" data-inline="true">
            <input type="submit" value="전송" data-theme="a" data-icon="arrow-r" data-inline="true">

        </div>
    </form>

</div>


jQuery 아이콘 모양은 http://demos.jquerymobile.com/1.4.5/icons/ 에서 참조하면 된다.

data-role 의 설명은 http://blog.naver.com/kimchangyoun/70184929188 참조


728x90
블로그 이미지

Link2Me

,

홈페이지에 접속시 index.php 처리 흐름도는 다음 그림과 같다.


프로그램에서 중요한 것은 어떤 로직으로 그릴것인가 하는 점이다.

사용하는 언어에 따른 문법, 사용법은 당연히 익혀야 한다.


1. index.php 파일에는 순수한 PHP 코드만으로 session 이 있으면 바로 메인페이지로 접속하도록 처리한다.

    session 정보가 없으면 로그인 화면을 띄우도록 한다.

    <?php
    if(!isset($_SESSION)) {
        session_start();
    }
    if(isset($_SESSION['userID']) && !empty($_SESSION['userID'])){
        // 세션 정보가 있으면
        include "main.php";       
    } else {
        // 세션 정보가 없으면
        include "loginForm.php";
    }
    ?>


    이 골격 기반위에 mobile 접속체크 기능을 추가할 수도 있다.

    추가한다면 loginClass.php 파일안에 mobile 체크 함수를 추가할 수 있다.


2. loginForm.php 파일에는 HTML header, body 정보가 들어가 있다.

    - 로그인 정보는 ID, PW 정보이므로 암호화하여 전송하는 것이 안전하다.

    - POST 전송방식으로 전송하여 ID,PW 정보 내용이 보이지 않도록 한다.

    - POST 전송방식 loginForm.php 파일

    <!DOCTYPE html>
    <html>
    <head>
        <title>로그인</title>
        <meta charset="utf-8" />    
        <meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0,user-scalable=no"/>
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="expires" content="0" />
        <meta http-equiv="pragma" content="no-cache" />

        <!-- Include jQuery Mobile stylesheets -->

        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.css">

        <!-- Include the jQuery library -->

        <script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>

        <!-- Include the jQuery Mobile library -->

        <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>

        <!-- 개발자 본인이 만든 jQuery -->

        <script src="js/loginScript.js"></script>
    </head>
    <body>
    <div id="content" data-role="content" style="margin-top:5%;">
        <center>
        <form id="loginForm" method="post" action="#" >
            <input type="text" name="userID" id="userID" value="" placeholder="아이디" style="width:50%" />
            <input type="password" name="password" id="password" value="" placeholder="패스워드" style="width:50%"/>
            <button type="submit" data-inline="true">로그인</button>
            <button type="reset" data-inline="true">다시작성</button>
        </form>
        </center>
    </div>
    </body>
    </html>


    === loginScript.js ===

    $(document).ready(function(){
        $("#loginForm").submit(function(){
            var loginID = $("#userID").val();
            var loginPW = $("#password").val();

            if(loginID =='') {
                alert("아이디를 입력하세요");
                $("#userID").focus();
                return false;
            }
           
            if(loginPW =='') {
                alert("패스워드를 입력하세요!");
                $("input[type='password']").focus();
                //$("#password").focus();
                return false;
            }    
            $.post('loginChk.php',{userID:loginID, password:loginPW}, function(msg) {
                if(msg==1){ // loginChk.php 파일에서 echo 결과값
                    window.location.href = 'main.php';
                } else {
                    alert('다시 로그인 하세요');
                }
            });
            return false;
        });

        $("input[type='reset']").click(function(){
            if(!confirm("정말 입력을 취소하시겠습니까?")){
                return false;
            }
        });
    });


3. loginChk.php 파일

<?php
if(empty($_POST['userID']) || empty($_POST['password'])){
    echo 0; // 실패
} else {
    $loginID=$_POST['userID'];
    $loginPW=$_POST['password'];

    require_once 'dbconnect.php';
    require_once 'phpclass/loginClass.php';

    $c=new LoginClass();
    $row=$c->UserAuthCheck($loginID,$loginPW);
    if(is_array($row)){
        if(!isset($_SESSION)) {
               session_start();
           }
        $_SESSION['userID'] = $row['userID'];
        $_SESSION['level'] = $row['level'];
        echo 1; // 로그인 성공
    } else {
        if(!isset($_SESSION)) {
               session_start();
           }
        session_destroy();
        echo 0; // 실패
    }
}
?>


※ dbconnect.php 파일 만드는 방법은 http://link2me.tistory.com/1110 참조하라.


=== loginClass.php 파일 발췌 ===

로그인 검사는 해킹 공격적인 요소를 필터링 하기 위한 것도 고려했다.

<?php
class LoginClass {
    function UserAuthCheck($u,$p) {
        if(!isset($u) || !isset($p) || empty($u) || empty($p)) {
            return 0;
        } else {
            global $db;           
            $u = preg_replace("/[\s\t\'\;\"\=\--]+/","", $u); // 공백이나 탭 제거(사용자 실수 방지)
            $p = preg_replace("/[\s\t\'\;\"\=\--]+/","", $p); // 공백이나 탭 제거, 특수문자 제거
            // SQL injection 검사
            $u = htmlentities($u); // <script>documnet.cookie();</script> 공격 방지, 한글인식 불가
            $p = htmlentities($p); // < 를 \< 로 바꿔준다.
            $u = str_replace(array("'",""","'",'"'), array("&#39;","&quot;","&#39;","&quot;"), $u);
            if(preg_match('/[\']/',$u)) return 0; // no quotes
            if(preg_match('/[\/\\\\]/', $u)) return 0; // no slashes
            if(preg_match('/(and|null|where|limit)/i', $u)) return 0; // i는 대소문자 구별하지 말라
            if(!preg_match('/^[0-9a-zA-Z\~\!\@\#\$\%\^\&\*\(\)]{7,}$/',$p)) return 0; // 7자리이상 허용 문자만 통과
            $sql = "select * from member where pw=md5('".$p."') and id= '".$u."' ";
            if($result = mysql_query($sql,$db)) { //성공
                $row = mysql_fetch_array($result);
                if($row == NULL) return 0;
                return $row;
            } else {
                return '-1';
            }
        }
    }

}//end class LoginClass

?>


4. main.php 파일에도 HTML header, body 정보가 들어가 있다.

   메인 페이지 내용을 작성하여 원하는 데이터를 출력한다.

   DB에서 조회하여 가져온 데이터를 테이블 형식으로 보여주고자 한다면

   너무 많은 자료를 가져오면 부하문제도 생기고 화면 스크롤 문제도 생기므로

   페이징 처리를 해서 보여줘야 한다.

   http://link2me.tistory.com/1112 참조


5. 변수가 제대로 넘어오는지 체크하고자 할 경우

아래 코드를 추가하고 exit; 를 넣은 이유는 다음 코드를 실행하지 말고 중단해서 변수가 제대로 넘어오는지 여부를 한번에 확인하고자 하는 목적이다.


@extract($_POST);
var_dump($_POST);
exit;

728x90
블로그 이미지

Link2Me

,

phpMyAdmin 에서 특정한 테이블만 삭제한다는 것을 실수로 DB 전체를 날려버렸다.

정신이 아득하다. 검색해서 실수로 날린 DB 복구방법으로 시도를 했는데 안된다.

아~~ 미처버리겠다는 생각이 들었고 나온 방법으로 수동 비슷하게도 복구를 시도해봤다.

그런데 문제는 PHP 소스코드 구현 방식에 약간 문제있는 부분이 있다는 걸 알게되었고, 이 방법으로는 정상적인 복구가 안된다.


최종적으로 복구를 한 방법을 적어둔다.


# cd /usr/local/mysql/data

에 가면 방금 삭제한 로그를 기록한 파일이 있다.

시간대를 보면 확인할 수 있다.

해당 파일을 보니 mysql-bin.000003 로 되어 있다.


복구방법에 보니까 이걸 한줄 한줄 실행해서 파일 하나로 합치라는 명령어가 있다.

그런데 이건 잘못된 듯하다.


/usr/local/mysql/bin/mysqlbinlog -d testdb mysql-bin.000003 > resque.sql

를 실행한다.

여기서 testdb 대신 실제 사용하는 DB명으로 수정해야 한다.

이렇게 하면 복구를 위한 1단계 준비는 되었다.


※ grep "insert" resque.sql > resque1.sql 이런거 하라고 되어 있는 곳도 있던데 이런거 하면 약간의 명령어는 나온다. 하지만 100% 복구 방법이 절대 아니다. 이거 해본다고 시간만 낭비했다.


2단계로 이 파일을 PC로 백업한다.

  mysql-bin.000003 파일도 PC로 복사를 해두는 편이 좋다고 생각하면 복사를 하라.

  테스트를 거치다보니 동일한 파일에 시간대가 달라지면서 계속해서 작업한 내용이 쌓이더라.


3단계로 이 파일을 EditPlus 로 열어서 맨 하단에 보면 drop table 이라고 표시된 부분이 보일 것이다.

  이 부분을 삭제 또는 주석처리 해주어야 한다.

  그런 다음에 저장하고 이 파일(rescue.sql )을 다른 이름으로 변경(rescue_modify.sql )하여 다시 서버에 복사를 한다.


4단계

# mysql -u 계정아이디 -p DB이름 < rescue_modify.sql
를 해주고 나면 패스워드 입력하고 나면 복구가 된다.


이렇게 복구하면 혹시라도 다시 만든 테이블이 있다면 삭제되어 버린다.

즉, 복구한 명령어를 가진 파일로 업데이트를 해버린다는 말이다.

728x90

'리눅스' 카테고리의 다른 글

sftp 파일 전송 shell script  (0) 2017.03.09
리눅스 파일/디렉토리 구조  (0) 2017.03.09
리눅스 날짜시간 변경  (0) 2016.10.24
2개의 APM(Apach + PHP + MySQL) 소스 설치  (0) 2016.07.17
SSH chroot 설정방법  (0) 2016.07.04
블로그 이미지

Link2Me

,

PHP 에서 페이징 처리하는 방법이다.
Paging 이란 전체 자료를 가져오는 것이 아니라 일정한 갯수만큼 화면에 가져오도록 처리하는 로직이다.


1. 한 페이지에 보여줄 개수를 정한다.

2. DB에서 전체 자료수(total Rows)에서 총 페이지수를 구한다.

3. 실제 페이지 번호가 표시될 개수를 정한다. 보편적으로 10개씩 보여주도록 할 수 있다.

4. 첫페이지로 가는 버튼

5. 마지막 페이지로 가는 버튼

6. 이전 블록으로 가는 버튼

7. 다음 블록으로 가는 버튼

 

변수를 정의해보자.

1. $totalcnt : 총 게시물수

2. $rowsPage : 한 페이지에 보여줄 개수

3. $totalPage = ceil($totalcnt/$rowsPage); // 총 페이지수

    총페이지수가 0 이면 1로 표기

    if($totalPage == 0) {

          ++$totalPage;

    }

4. $total_block = ceil($totalPage / $block_limit); //전체 블록 갯수

5. $curPage = $curPage ? $curPage : 1; // 현재 페이지

6. $block_limit : 한 화면에 뿌려질 게시글 개수

7. $current_block=ceil($curPage/$block_limit); // 현재 블럭 : 화면에 표시될 페이지 리스트

8. $fstPage = (((ceil($curPage/$block_limit)-1)*$block_limit)+1); // 현재 블럭의 시작

9. $endPage = $fstPage + $block_limit -1; // 현재 블럭의 마지막

    if($totalPage < $endPage) {
        $endPage = $totalPage;
     }
10. $prev_page = $fstPage - 1; // 시작 바로 전 페이지

11. $next_page = $endPage + 1; // 마지막 다음 페이지

 

 

이제 본문에 뿌릴 개수를 함수로 만들어 보자.

<?php
class MySQLDbClass {

 

    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 선택
        return $selc ? $conn : false;
    }

 

    //DB데이터 ARRAY -> 테이블에 출력할 데이터 배열
    // order by : 정렬 순서, rowsPage : 화면에 출력할 개수, curPage : 현재 페이지
    function getDbArray($table,$where,$flddata,$orderby,$rowsPage,$curPage){
        global $db;
        $curPage = $curPage ? $curPage : 1; // 현재 페이지가 없으면 1로 설정
        $sql = 'select '.$flddata.' from '.$table.($where?' where '.$this->getSqlFilter($where):'').($orderby?' order by '.$orderby:'').($rowsPage?' limit '.(($curPage-1)*$rowsPage).', '.$rowsPage:'');
        //echo $sql;
        $result = mysql_query($sql);
        return $result;
    }

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

}//end dbClass

 

화면 하단에 뿌릴 페이징 처리 함수 만들기

dbClass 함수 안에 넣어도 되고 별도의 클래스를 만들어서 호출해서 사용해도 된다.

// $curPage : 현재 페이지, $totalcnt : 총 게시물수
// $block_limit : 한 화면에 뿌려질 게시글 개수
function PageList($totalcnt,$rowsPage,$curPage,$block_limit) {
    $block_limit = $block_limit ? $block_limit : 10;  // 한 화면에 보여줄 개수 기본 10으로 설정

    // 총 페이지수 구하기
    $totalPage = ceil($totalcnt/$rowsPage); 
    if($totalPage == 0) {
        ++$totalPage;
    }
    $total_block = ceil($totalPage / $block_limit); //전체 블록 갯수
   
    $curPage = $curPage ? $curPage : 1; // 현재 페이지

    // 현재 블럭 : 화면에 표시될 페이지 리스트
    $current_block=ceil($curPage/$block_limit);
    // 현재 블럭에서 시작페이지
    $fstPage = (((ceil($curPage/$block_limit)-1)*$block_limit)+1);
    // 현재 블럭에서 마지막 페이지
    $endPage = $fstPage + $block_limit -1;
    if($totalPage < $endPage) {
        $endPage = $totalPage;
    }

    // 시작 바로 전 페이지
    $prev_page = $fstPage - 1;
    // 마지막 다음 페이지
    $next_page = $endPage + 1;

    foreach(range($fstPage, $endPage) as $val) {
        $row[] = $val;
    }
    // 배열로 결과를 돌려준다.
    return array(
        'total_block' => $total_block,
        'current_block' => $current_block,
        'totalPage' => $totalPage,
        'fstPage' => $fstPage,
        'endPage' => $endPage,
        'prev' => $prev_page,
        'next' => $next_page,
        'current' => $row
    );
}

 

페이징 화면에 출력하기

HTML 문법은 bootstrap3 또는 bootstrap4에 맞게 Class만 수정해주면 된다.

function PageLinkView($link_url,$totalcnt,$rowsPage,$curPage){
    echo '<div style="position:relative;vertical-align:top;padding-top:0;margin-top:0">';
        echo "<span style='position:absolute;top:10px;'>[총 자료수:".$totalcnt."]</span>";
        echo '<div class="pagelink">';
            $Info = $this->PageList($totalcnt,$rowsPage,$curPage,'');
            if($Info['current_block'] > 2){
                echo "<a href='".$link_url."?p=1'>◀</a> ";
            }
            if($Info['current_block'] > 1){
                echo "<a href='".$link_url."?p=".$Info['prev']."'>◁</a> ";
            }
            foreach($Info['current'] as $w) {
                if($curPage == $w){
                    echo "<a href='".$link_url."?p=".$w."'><span style='color:red;font-size:22pt'>".$w."</span></a> ";
                } else {
                    echo "<a href='".$link_url."?p=".$w."'>".$w."</a> ";
                }
            }
            if($Info['current_block'] < ($Info['total_block'])){
                echo "<a href='".$link_url."?p=".$Info['next']."'>▷</a> ";
            }
            if($Info['current_block'] < ($Info['total_block']-1)){
                echo "<a href='".$link_url."?p=".$Info['totalPage']."'>▶</a> ";
            }
        echo '</div>';
    echo '</div>';
}   

 

사용법 예제

<?php
include_once 'dbinfo.php';
require_once 'phpclass/dbClass.php';

$conn = new MySQLDbClass(); // DB 함수
$db = $conn->isConnectDb($DB);

// 화면에 출력할 칼럼 발췌
$flddata ="(select name from cate where uid=d.cat1) as cat1,subject,content";
$rowsPage = 12;
$curPage = isset($_GET['p']) ? $_GET['p'] : 1;
$result = $conn->getDbArray('data d','',$flddata,'',$rowsPage,$curPage);
$totalcnt 구하는 함수 처리

 

본문 Layout : 테이블을 작성해서 $result 배열 결과물을 table td 태그안에 기록

페이징 Layout : 페이징 화면 출력

 

?>

 

함수로 만든 모든 것을 표기하지는 않았다.

이런 형태로 만들어 볼 수 있다는 것만 알 수 있게 작성했다.

 

실 사용 예제

- 네이버지식인에 링크를 걸어줬더니 성의없는 답변이라는 댓글을 보고서 실제 사용하는 예제를 추가했음.

- 어떻게 처리하는지에 대한 흐름만 이해하면 되는 사항.

<?php
if(!isset($_SESSION)) {
    session_start();
}
 
require_once '../dbconnect.php';
require_once '../phpclass/dbClass.php';
require_once '../phpclass/bbsClass.php';
require_once '../phpclass/adminClass.php';
$a = new adminClass();
$b = new bbsClass();
$c = new MySQLDbClass();
 
// 설문 테이블 상태 변경 체크
$a->surveyDBupdate();
 
$url = $_SERVER['PHP_SELF']; // 현재 실행중인 파일명 가져오기
$page = isset($_GET['page'])? trim($_GET['page']):1;//페이지 변수 설정
$rowsPage = 10// 한 화면에 표시되는 게시글 수
$curPage = isset($_GET['p']) ? $_GET['p'] : 1;
$bd_name = isset($_GET['bd_name']) ? $_GET['bd_name'] :'';
$mode = isset($_GET['mode']) ? $_GET['mode'] :'list';
$sel = isset($_GET['sel'])? $_GET['sel'] : '';
 
$flddata ="*";// 화면에 출력할 칼럼 발췌
$where = isset($_GET['where']) ? $_GET['where']: '';
$keyword = isset($_GET['keyword']) ? $_GET['keyword']: '';
$xorderbyisset($xorderby) ? $xorderby : 'uid DESC';
if($where && $keyword) {
    if($where == 'title'$sql = "title LIKE '%".$keyword."%' ";
    if($where == 'content'$sql = "content LIKE '%".$keyword."%' ";
    if($where == 'unify') {
        $sql = "(title LIKE '%".$keyword."%' OR content LIKE '%".$keyword."%') ";
    }
else {
    $sql ='';
}
if(!empty($sel)){
    if($keyword){
        $sql .= " and status = ".$sel;
    } else {
        $sql = " status = ".$sel;
    }
}
 
//echo $sql.'<br />';
 
$link_url=($bd_name?'bd_name='.$bd_name.'&amp;':'').($mode?'mode='.$mode.'&amp;':'').($sel?'sel='.$sel.'&amp;':'').($where?'where='.$where.'&amp;':'').($keyword?'keyword='.urlencode(stripslashes($keyword)).'&amp;':'');
$g['bbs_reset'= $url// 초기화
 
$table ='poll_admin';
$rows$c->getDbArray($table,$sql,$flddata,$xorderby,$rowsPage,$curPage);
$NUM = $c->getDbRows($table,$sql); // 전체 게시글수
$TPG = $b->getTotalPage($NUM,$rowsPage);
?>
 
<!DOCTYPE html>
<head>
<title><?php echo $title;?></title>
<meta charset="utf-8">
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../vendor/bootstrap/css/bootstrap.min.css">
<link href="vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic" rel="stylesheet" type="text/css">
<link rel="stylesheet" type="text/css" href="../css/survey.css" />
<script src="../vendor/jquery/jquery.min.js"></script>
<script src="../vendor/bootstrap/js/bootstrap.min.js"></script>
<script src="../js/modal.js"></script>
</head>
<body>
<div class="container">
<table class="table table-bordered">
<tr>
    <td align=center><font class='title'><b>설문조사<br><br>
    <div class="pull-left info bmargin">
        <select name='sel' onchange='document.searchf.sel.value=this.value;document.searchf.submit();'>
        <option value=''>전체목록보기</option>
        <option value='1' <?php if("1"==$sel):?> selected<?php endif?>>진행중목록</option>
        <option value='2' <?php if("2"==$sel):?> selected<?php endif?>>종료 목록</option>");
        </select>
    </div>
    <div class="pull-right info bmargin">
        <a href='survey_admin.php'><button class="w3-button w3-blue-grey w3-tiny">관리</button></a>&nbsp;
        <a href='add_form.php?mode=new'><button class="w3-button w3-blue-grey w3-tiny">등록</button></a>
    </div>
<!--  설문 내용 -->
<table class='w3-table w3-bordered'>
    <thead>
        <tr class="w3-blue-grey">
            <th width="8%">No</th>
            <th width="43%">설문 제목</th>
            <th width="11%">총응답</th>
            <th width="13%">시작일</th>
            <th width="13%">종료일</th>
            <th width="10%">상 태</th>
        </tr>
    </thead>
    <tbody>
        <?php $i=1;foreach($rows as $R):?>
        <tr>
            <td><?php echo $i;?></td>
            <td>
            <?php
                $memo="&nbsp;<a href='survey_memo.php?bd_name=".$R['bd_name']."&mode=list&sel=".$sel."'><img src='./image/memo.gif' border='0' alt='메모보기'></a>";
                if($R['enddate'< date("Y-m-d")){
                    echo "<a href='survey_res.php?bd_name=".$R['bd_name']."&sel=".$sel."'> ".$R['title']."</a>$memo</td>";
                    $status = "종 료";
                } else {
                    if($R['startdate'> date("Y-m-d")) $status = "준비중";
                    else $status = "진행중</td>";
                    echo "<a href='survey.php?bd_name=".$R['bd_name']."&sel=".$sel."'> ".$R['title']."</a>$memo</td>";
                }
            ?>
            </td>
            <td><?php echo $R['totalcnt'];?></td>
            <td><?php echo $R['startdate'];?></td>
            <td><?php echo $R['enddate'];?></td>
            <td><?php echo $status;?></td>
        </tr>
        <?php $i++;endforeach;?>
    </tbody>
</table>
<div><br></div>
<div class='searchbox'>
    <form name="searchf" class="form-inline" action="<?php echo $url.'?'.$link_url;?>">
        <input type="hidden" name="mode" value="<?php echo $mode?>" />
        <input type="hidden" name="sel" value="<?php echo $sel?>" />
        <input type="hidden" name="p" value="1" />
        <select name="where" class="form-control input-sm">
            <option value="unify">통합</option>
            <option value="title">제목</option>
            <option value="content">설명</option>
        </select>
        <div class="input-group input-group-sm">
            <input type="text" name="keyword" value="" class="form-control input-search" placeholder="검색어">
            <span class="input-group-btn">
                <button type="button" class="btn btn-default" onclick="this.form.where.value='title';this.form.keyword.value='',this.form.submit();" title="리셋"><i class="glyphicon glyphicon-repeat"></i></button>
                <button type="submit" class="btn btn-info" title="검색"><i class="glyphicon glyphicon-search"></i></button>
            </span>
        </div>
    </form>
</div>
<div class="pull-right info">
    <a href="<?php echo $g['bbs_reset']?>" class="btn btn-default btn-sm pull-right">처음목록</a>
</div>
<?php $b->PageLinkView($url,$NUM,$rowsPage,$curPage,$link_url);?>
</td>
</tr>
</table>
</div>
</body>
</html>
<?php mysqli_close($db);?>
 

 

<?php
class bbsClass extends MySQLDbClass {
 
    function PageLinkView($link_url$totalcnt$rowsPage$curPage$m) {
        echo '<div id="paging">';
        echo '<ul class="pagination">';
        $Info = $this -> PageList($totalcnt$rowsPage$curPage'');
        if ($Info['current_block'> 2) {
            echo "<li><a href='" . $link_url . "?p=1&$m'>◀</a></li> ";
        }
        if ($Info['current_block'> 1) {
            echo "<li><a href='" . $link_url . "?p=" . $Info['prev'] . "&$m'>◁</a></li> ";
        }
        foreach ($Info['current'as $w) {
            if ($curPage == $w) {
                echo "<li class='act'><a href='" . $link_url . "?p=" . $w . "&$m'><span style='color:red;'>" . $w . "</span></a></li> ";
            } else {
                echo "<li><a href='" . $link_url . "?p=" . $w . "&$m'>" . $w . "</a></li> ";
            }
        }
        if ($Info['current_block'< ($Info['total_block'])) {
            echo "<li><a href='" . $link_url . "?p=" . $Info['next'] . "&$m'>▷</a></li> ";
        }
        if ($Info['current_block'< ($Info['total_block'- 1)) {
            echo "<li><a href='" . $link_url . "?p=" . $Info['totalPage'] . "&$m'>▶</a></li> ";
        }
        echo '</ul>';
        echo '</div>';
    }
 
    // $curPage : 현재 페이지, $totalcnt : 총 게시물수
    // $block_limit : 한 화면에 뿌려질 게시글 개수
    function PageList($totalcnt,$rowsPage,$curPage,$block_limit) {
        $block_limit = $block_limit ? $block_limit : 10;  // 한 화면에 보여줄 개수 기본 10으로 설정
 
        // 총 페이지수 구하기
        $totalPage = ceil($totalcnt/$rowsPage);
        if($totalPage == 0) {
            ++$totalPage;
        }
        $total_block = ceil($totalPage / $block_limit); //전체 블록 갯수
 
        $curPage = $curPage ? $curPage : 1// 현재 페이지
 
        // 현재 블럭 : 화면에 표시될 페이지 리스트
        $current_block=ceil($curPage/$block_limit);
        // 현재 블럭에서 시작페이지
        $fstPage = (((ceil($curPage/$block_limit)-1)*$block_limit)+1);
        // 현재 블럭에서 마지막 페이지
        $endPage = $fstPage + $block_limit -1;
        if($totalPage < $endPage) {
            $endPage = $totalPage;
        }
 
        // 시작 바로 전 페이지
        $prev_page = $fstPage - 1;
        // 마지막 다음 페이지
        $next_page = $endPage + 1;
 
        foreach(range($fstPage$endPageas $val) {
            $row[] = $val;
        }
        // 배열로 결과를 돌려준다.
        return array(
            'total_block' => $total_block,
            'current_block' => $current_block,
            'totalPage' => $totalPage,
            'fstPage' => $fstPage,
            'endPage' => $endPage,
            'prev' => $prev_page,
            'next' => $next_page,
            'current' => $row
        );
    }
 
    //총페이지수
    function getTotalPage($num,$rec){
        return @intval(($num-1)/$rec)+1;
    }
 
}//end class boardClass

 

 
<?php
extract($_GET);
extract($_POST);
class MySQLDbClass {
    protected $db;
    private $host = 'localhost';
    private $database = 'survey';
    private $userid = 'root';
    private $password = 'autoset';
 
    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
 
?>

 

728x90
블로그 이미지

Link2Me

,