728x90

서버가 PDO를 지원하지 못한다고 해서 부득이하게 MySQLi 방식으로 변경해야 했다.

모든 코드를 전부 변경하려니 보통 난감한 상황이 아니다.

물론 완전 Legacy PHP 코드로 변경하면 좀 수월할 수도 있는데 stmt 로 변경하는 걸 고려했다.

 

PDO 로 작성된 코드 예시

<?php
class adminClass {
 
    function getUserNMFromIdx($idx){
        $sql = "SELECT userNM FROM members WHERE idx=?";
        $params = array($idx);
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        if($row = $stmt->fetch()){
            if($row[0== NULL)    return '';
            return $row[0];
        } 
    }    
}
 
?>

 

 

MySQLi 코드로 변경하는 방법

<?php
class adminClass {
 
    function sql($sql$params) {
        global $db;
        // $params : array 를 사용해야 한다.
        $stmt = $db->prepare($sql);
        $types = str_repeat('s'count($params)); //types
        $stmt->bind_param($types, ...$params); // bind 
        $stmt->execute();
        $result = $stmt->get_result();
        return $result->fetch_array(); // 배열 결과 처리
    }
 
    function getUserNMFromIdx($idx){
        $sql = "SELECT userNM FROM members WHERE idx=?";
        $params = array($idx);
        $row = $this->sql($sql$params);
        if($row[0== NULL)    return '';
        return $row[0];
    }    
}
 
?>

 

 

 

 

블로그 이미지

Link2Me

,
728x90

PHP와 혼용된 HTML Form 태크의 값을 넘길 때 변수명이 너무 많으면 일일이 값을 기입하여 전달하기가 쉽지 않다.

게다가 해킹 방지를 위해서는 key 값은 암호화처리를 해서 넘기는 것이 좋다.

JSEncrypt 암호화코드를 적용하려고 하니 일일이 변수명에 대한 값을 기록해야 하는 거 같아 이 방법을 사용하지 PHP 암호화 코드를 적용하고 복호화하는 방법을 택했다.

idx 값이 보통 숫자인데 이 값을 그대로 노출해서 수정/삭제를 하면 값을 변경하여 처리하는 해킹시도에 노출되기 쉽다.

그래서 반드시 암호화해서 처리를 하여야 한다.

<form class='form-horizontal' id='MNRegister'>
    <input type="hidden" name="idx" value="<?php echo $a->Encrypt($idx)?>" />
    <table class='table table-bordred'>
        <tr>
            <th style='width:15%'>성명</th>
            <td style='width:35%'>
                <?php echo $a->letterMasking($row['userNM']).'('.$a->IDMasking($row['userID']).')';?>
            </td>
            <th style='width:15%'>휴대폰℡</th>
            <td style='width:35%'>
                <?php echo $a->phoneNoMasking($a->Decrypt($row['mobileNO']));?>
            </td>
        </tr>
        <tr>
            <th style='width:15%'>직위</th>
            <td style='width:35%'><select class="browser-default custom-select" name="codeID">
            <?php
                foreach($posArr as $k=>$v){
                    if($row['codeID']==$k){
                        echo "<option value='".$k."' selected>".$v."</option>";
                    } else {
                        echo "<option value='".$k."'>".$v."</option>";
                    }
                }
            ?>
            </select>
            </td>
            <th style='width:15%'>팀서열</th>
            <td style='width:35%'>
                <input class="form-control input-sm" type="text" name="regNO" value="<?php echo $row['regNO'];?>">
            </td>
        </tr>
        <tr>
            <th style='width:15%'>본부</th>
            <td style='width:35%'>
                <input class="form-control input-sm" type="text" name="group2" value="<?php echo $row['group2'];?>">
            </td>
            <th style='width:15%'>담당</th>
            <td style='width:35%'>
                <input class="form-control input-sm" type="text" name="group3" value="<?php echo $row['group3'];?>">
            </td>
        </tr>
        <tr>
            <th style='width:15%'>부서</th>
            <td style='width:35%'>
                <input class="form-control input-sm" type="text" name="group4" value="<?php echo $row['group4'];?>">
            </td>
            <th style='width:15%'>팀명</th>
            <td style='width:35%'>
                <input class="form-control input-sm" type="text" name="group5" value="<?php echo $row['group5'];?>">
            </td>
        </tr>
        <tr>
            <th style='width:15%'>회원등급</th>
            <td style='width:35%'><select class="browser-default custom-select" name="admin">
            <?php
                foreach($sysrole as $k=>$v){
                    if($row['admin']==$k){
                        echo "<option value='".$k."' selected>".$v."</option>";
                    } else {
                        echo "<option value='".$k."'>".$v."</option>";
                    }
                }
            ?>
            </select>
            </td>
            <th style='width:15%'>개인정보</th>
            <td style='width:35%'><select class="browser-default custom-select" name="smart">
            <?php
                foreach($personinfo as $k=>$v){
                    if($row['smart']==$k){
                        echo "<option value='".$k."' selected>".$v."</option>";
                    } else {
                        echo "<option value='".$k."'>".$v."</option>";
                    }
                }
            ?>
            </select>
            </td>
        </tr>
        <tr>
            <th style='width:15%'>로그인</th>
            <td style='width:35%'><select class="browser-default custom-select" name="access">
            <?php
                foreach($access as $k=>$v){
                    if($row['access']==$k){
                        echo "<option value='".$k."' selected>".$v."</option>";
                    } else {
                        echo "<option value='".$k."'>".$v."</option>";
                    }
                }
            ?>
            </select>
            </td>
            <th style='width:15%'>Status</th>
            <td style='width:35%'><select class="browser-default custom-select" name="hidden">
            <?php
                foreach($hidden as $k=>$v){
                    if($row['hidden']==$k){
                        echo "<option value='".$k."' selected>".$v."</option>";
                    } else {
                        echo "<option value='".$k."'>".$v."</option>";
                    }
                }
            ?>
            </select>
            </td>
        </tr>
    </table>
</form>
 

 

 

jQuery 코드

form id NMRegister 값을 serialize하여 모든 변수를 한꺼번에 POST ajax로 넘길 수 있다.

function MNRegChk(idx,curPage,where,keyword,cat1,cat2,bidx,sort){
    //if(CheckErr($('input[name=userID]'),'아이디를 입력하세요.') == false) return false;
    //if(CheckErr($('input[name=userNM]'),'성명을 입력하세요.') == false) return false;
 
    var params = $('#MNRegister').serialize();
    $.post('MemberRegChk.php',params,function(msg){
        //prompt('msg',msg);
        var uri = $('#urlPath').attr('url-path');
        if(msg == 1){
            alert('등록되었습니다.');
            $('#dialog').dialog('close');
            MemberListTable(where,keyword,curPage,uri,bidx,sort,cat1,cat2,'');
        } else if(msg == 2){
            alert('수정되었습니다');
            $('#dialog').dialog('close');
            MemberListTable(where,keyword,curPage,uri,bidx,sort,cat1,cat2,'');
        } else if(msg == 0){
            alert('변경에 실패했습니다');
        }
    },'json');
 
}
 
function CheckErr(jsel,msg) {
    var count = jsel.val().length;
    if(count < 1) {
        alert(msg);
        jsel.focus();
        return false;
    }
    return true;
}
 

 

 

 

 

 

 

블로그 이미지

Link2Me

,
728x90

https://link2me.tistory.com/2311

 

접속로그 통계 (신규, 중복 동시 처리)

접속로그 통계 구현을 위해서 로그를 쌓고 있는 테이블에서 데이터를 가공해야 한다. 접속로그 테이블에는 접속실패, 접속성공 등 모든 접속 시도 데이터를 저장해야 한다. CREATE TABLE `rb_accessLog`

link2me.tistory.com

SQL 데이터를 차트로 그리는 통계를 구현하는 코드를 예제로 작성했다.

 

statsClass.php

<?php
class statsClass {
    // 테이블 비우기
    function AccessLogTableTruncate($tablename){
        global $db;
        $sql ="TRUNCATE TABLE ".$tablename."";
        mysqli_query($db,$sql);
    }
 
    function rb_access_Stats($date){
        global $db;
        $sql ="select count(date) from rb_access_Stats where date='".$date."'"// 기록된 데이터 있는지 조회
        $result=mysqli_query($db,$sql);
        if($row=mysqli_fetch_row($result)){
            return $row[0];
        }
    }
 
    function AccessLogCnt($date){
        global $db;
        $sql ="select count(distinct userID),sum(hit) from rb_accessLog_tmp where date='".$date."'";
        $result=mysqli_query($db,$sql);
        if($row=mysqli_fetch_row($result)){
            return $row;
        }
    }
 
    // 통계데이터가 쌓이고 있는지 검사하는 로직
    function AccessLogIsData($date){
        global $db;
        $sql ="select userID from rb_accessLog_tmp where date='".$date."'";
        $result=mysqli_query($db,$sql);
        if($row=mysqli_fetch_row($result)){
            if($row[0== NULL) { // 데이터가 하나도 없으면
                return 0;
            } else {
                return 1;
            }
        }
    }
 
    // 년월 DB 추출
    function extract_YM(){
        global $db;
        $sql ="select distinct(YM) from rb_access_Stats order by YM DESC";
        $result = mysqli_query($db,$sql);
        return $result;
    }
 
    // 년월의 max date 구해서 배열 -> 문자열 만들기
    function maxdate_YM($ym){
        global $db;
        date_default_timezone_set('Asia/Seoul');
        if(empty($ym)){
            $cur_year = date("Y");
            $cur_month = date("m");
        } else {
            $cur_year = substr($ym,0,4);
            $cur_month = substr($ym,4,2);
        }
        // 현재 월의 마지막 날짜를 일단 선택하도록 처리하고, 년/월을 선택하면 자동으로 변경
        $last_date = date("t"mktime(001$cur_month1$cur_year));
        $R=array();
        for($i=0;$i < $last_date$i++){
            $R[$i]=$i+1;
        }
        return $R// 배열로 반환
    }
 
 
    function dailyCnt_value($ym){
        global $db;
        date_default_timezone_set('Asia/Seoul');
        if(empty($ym)){
            $ym = date("Ym"); // 입력이 없으면 현재월의 데이터를 추출하라.
            $cur_year = date("Y");
            $cur_month = date("m");
        } else {
            $cur_year = substr($ym,0,4);
            $cur_month = substr($ym,4,2);
        }
        $R=array();
        // 현재 월의 마지막 날짜를 일단 선택하도록 처리하고, 년/월을 선택하면 자동으로 변경
        $last_date = date("t"mktime(001$cur_month1$cur_year));
        for($i=1;$i <= $last_date$i++){
            $R[$i]='';
        }
        $sql ="select day,dailyCnt from rb_access_Stats ";
        $sql.="where YM='".$ym."'";
        $result = mysqli_query($db,$sql);
        while($row=mysqli_fetch_row($result)){
            // DB에 저장되는 날짜가 01, 02로 저장되는 것을 1, 2로 출력되도록 처리
            $R[intval($row[0])] = $row[1];
        }
        return $R// 배열로 반환
    }
 
    function userCnt_value($ym){
        global $db;
        date_default_timezone_set('Asia/Seoul');
        if(empty($ym)){
            $ym = date("Ym"); // 입력이 없으면 현재월의 데이터를 추출하라.
            $cur_year = date("Y");
            $cur_month = date("m");
        } else {
            $cur_year = substr($ym,0,4);
            $cur_month = substr($ym,4,2);
        }
        $R=array();
        // 현재 월의 마지막 날짜를 일단 선택하도록 처리하고, 년/월을 선택하면 자동으로 변경
        $last_date = date("t"mktime(001$cur_month1$cur_year));
        for($i=1;$i <= $last_date$i++){
            $R[$i]='';
        }
        $sql ="select day,IDCnt from rb_access_Stats ";
        $sql.="where YM='".$ym."'";
        $result = mysqli_query($db,$sql);
        while($row=mysqli_fetch_row($result)){
            // DB에 저장되는 날짜가 01, 02로 저장되는 것을 1, 2로 출력되도록 처리
            $R[intval($row[0])] = $row[1];
        }
        return $R// 배열로 반환
    }
 
}

 

 

stats_db.php

<?php
require_once 'path.php';// root 폴더를 기준으로 상대적인 경로 자동 구하기
//require_once $g['path_root'].'sessionChk.php'; // 세션 체크
if(isset($_POST['ym'])){
    require_once $g['path_config'].'dbconnect.php';
    require_once $g['path_class'].'statsClass.php';
 
    $s = new statsClass;
 
    $ym = $_POST['ym'];
    $data1 = $s->dailyCnt_value($ym);
    $data2 = array_values($s->userCnt_value($ym));
    $ticks = $s->maxdate_YM($ym);
    $R = array('data1'=>$data1,'data2'=>$data2'ticks'=>$ticks);
    echo json_encode($R);
}
?>

 

 

차트 출력 파일 : accessStats.php

<?php
error_reporting(0);
//*
ini_set("display_startup_errors"1);
ini_set("display_errors"1);
error_reporting(E_ALL);
// */
 
require_once 'path.php';// root 폴더를 기준으로 상대적인 경로 자동 구하기
require_once $g['path_config'].'config.php';
require_once $g['path_config'].'dbconnect.php';
require_once $g['path_class'].'statsClass.php';
 
$s = new statsClass();
$R = $s->extract_YM();
 
date_default_timezone_set('Asia/Seoul');
if(isset($_GET['ym'])){
    $ym = $_GET['ym'];
else {
    if(date("d"=== '01'){ // 1 일에는 전월 출력하도록 설정
        $ym = date("Ym"mktime(0,0,0,date("m")-1, date("d"), date("Y")));
    } else {
        $ym = date("Ym");
    }
}
$ticks = json_encode($s->maxdate_YM($ym));
$line1 = json_encode(array_values($s->dailyCnt_value($ym)));
$line2 = json_encode(array_values($s->userCnt_value($ym)));
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<?php header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1 ?>
<?php header('Pragma: no-cache'); // HTTP 1.0 ?>
<?php header('Expires: 0'); // Proxies ?>
<?php header('X-Frame-Options:SAMEORIGIN',true);?>
<?php header('X-Content-Type-Options: nosniff',true);?>
<?php header('X-XSS-Protection:1;mode=block',true);?>
<title>일일 접속 통계</title>
<link rel="shortcut icon" href="/img/etc/favicon.ico">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/mdb.lite.css" rel="stylesheet">
<link href="/css/jquery-ui.css" rel="stylesheet">
</head>
<body>
 
<div class="row">
    <div class="col-md-2">
    </div>
    <div class="col-md-8 col-xl-8 col-lg-8">
        <p class="h5 my-4">일일 접속 통계</p>
        <div class="card shadow mb-4">
            <canvas id="myChart"></canvas>
        </div>
            <div class="float-right info mt-4">
            <select class="browser-default custom-select" name="month" id="selectmonth">
            <option value="">년월 선택</option>
            <?php
                while ($row = mysqli_fetch_array($R)){
                    echo "<option value='".$row[0]."' ";
                    if($row[0=== $ymecho "selected='selected'";
                    echo ">".$row[0]."</option>\n";
                }
            ?>
            </select>
            </div>
    </div>
</div>
<script type="text/javascript" src="/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="/js/popper.min.js"></script>
<script type="text/javascript" src="/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/js/mdb.lite.min.js"></script>
<script type="text/javascript" src="/js/jquery-ui.js"></script>
<script type="text/javascript" src="/js/jsencrypt.min.js"></script>
<script type="text/javascript" src="/js/user/user.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
<script>
var xAxis = <?php echo $ticks;?>;
var adIDData1 = <?php echo $line1;?>;
var adIDData2 = <?php echo $line2;?>;
 
drawPlot(adIDData1, adIDData2, xAxis);
 
function drawPlot(adIDData1, adIDData2, xAxis){
    var ctx = document.getElementById("myChart").getContext('2d');
    var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
      labels: xAxis ,
      datasets: [
          {
            label: '로그인수',
            data: adIDData1 ,
            backgroundColor: 'rgba(50, 169, 132, 0.5)',
            borderColor: 'rgba(50,169,132,1)',
            borderWidth: 1
          },
          {
            label: '사용자수',
            data: adIDData2 ,
            backgroundColor: 'rgba(54, 162, 235, 0.5)',
            borderColor:'rgba(54, 162, 235, 1)',
            borderWidth: 1
          },
 
        ]
    },
    options: {
      scales: {
        yAxes: [{
          ticks: {
            beginAtZero: true
          }
        }]
      }
    }
    });
}
 
$('#selectmonth').on('change',function(){
    if(this.value !== ""){
        var optVal=$(this).find(":selected").val();
        $.post('stats_db.php',{ ym:optVal },function(msg){
            //console.log(msg); // 배열 형태로 넘어오는지 확인 목적
            var jsonObj = $.parseJSON(msg); // JSON 문자열을 JavaScript object 로 반환
            var data1 = $.map(jsonObj.data1, function(el) { return el });
            var data2 = jsonObj.data2;
            var xAxis = jsonObj.ticks;
            drawPlot(data1,data2,xAxis);
        });
    }
});
</script>
</body>
</html>
 

 

 

블로그 이미지

Link2Me

,
728x90

strtotime()는 두 날짜를 UNIX 시간으로 변환하고 그로부터 초 수를 계산한다.

먼저 new DateTime()을 사용하여 날짜를 선언한다. 
그런 다음 첫 번째 날짜의 DateInterval() 오브젝트 diff()를 사용하여 차이의 정수 값을 가져오고 두 번째 날짜를 매개 변수로 전달한다. 년은 y 객체를 사용, 월은 m 객체, 일은 d 객체를 사용하면 된다.

<?php
$firstDate  = new DateTime("2022-01-01");
$secondDate = new DateTime("2022-04-24");
$intvl = $firstDate->diff($secondDate);
 
echo $intvl->y . " 년, " . $intvl->m." 월 and ".$intvl->d." 일";
 
// 날짜수를 계산
echo $intvl->days . " days ";
?>

 

DB와 연동하여 신청일자, 폐지일자 데이터를 가져와서 유형을 구분하고 DB 저장하기 위한 로직 예제이다.

<?php
 
$sql = "select * from customer ";
$result =  mysqli_query($db$sql);
while($R = mysqli_fetch_array($result)){
 
    $regdate = preg_replace("/[^0-9]/","",$R['reg_date']);
    $revodate  = preg_replace("/[^0-9]/","",$R['revo_date']);
    $datediff = getDateDiff($regdate$revodate);
 
}
mysqli_close($db); // 디비 접속 닫기
 
 
// 문자열 날짜를 입력받아 날짜 차이를 계산한다.
function getDateDiff($regDate$revoDate){
    date_default_timezone_set('Asia/Seoul');
    $date1 = new DateTime(date("Y-M-d", strtotime($regDate)));
    if($revoDate == '99991231'){
        $date2 = new DateTime(date("Y-M-d")); // 유지시 현재 날짜 반환
    } else {
        $date2 = new DateTime(date("Y-M-d", strtotime($revoDate)));
    }
 
    $intvl = $date2->diff($date1);
    $GapDate = $intvl->days;
    return DateType($GapDate);
}
 
// 날짜 타입 구분
function DateType($GapDate){
    
    if($GapDate >= 180){
        return "6개월";
    } else if($GapDate >= 90){
        return "3개월";
    } else if($GapDate >= 60){
        return "2개월";
    } else if($GapDate >= 30){
        return "1개월";
    } else if($GapDate >= 10){
        return "10일이상";
    } else {
        return "10일이내";
    }
}
 
?>

 

 

 

 

블로그 이미지

Link2Me

,
728x90

AES256 암호화/복호화에 대한 예제이다.

Java 에서 AES256 암호화/복호화시에는 key를 16바이트 키를 사용해도 문제가 되지 않는다.

Java 에서 암호화 한 것을 PHP에서 복호화할 때에는 16바이트 키를 사용한 것은 엉뚱한 결과를 반환하더라.

key 길이가 다르면 PHP 복호화시 문제가 된다는 걸 잊지마시길 !!

 

Java 에서 암호화/복호화 하는 경우와 Android 에서 사용하는 경우 import 문이 달라서인지 코드가 약간 다르다.

 

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;
 
public class AES256Cipher {
    private static String key = "testggisuitken1959imy91jb7076jas"// AES 암호화  키
//    private static String key = "cde0123456789abf"; // 16 바이트키
    public static byte[] ivBytes = { 0x000x000x000x000x000x000x000x000x000x000x000x000x000x000x000x00 };
 
    public static String AES_Encode(String str, String key)    throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
 
        byte[] textBytes = str.getBytes("UTF-8");
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
        Cipher cipher = null;
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
 
        Base64.Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(cipher.doFinal(textBytes));
    }
 
    public static String AES_Decode(String str, String key)    throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
 
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] textBytes =decoder.decode(str);
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
        return new String(cipher.doFinal(textBytes), "UTF-8");
    }
 
    // 암호화
    public static String encrypt(String data) {
        try {
            data = AES_Encode(data, AES256Cipher.key);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return data;
    }
 
    // 복호화
    public static String decrypt(String data) {
        try {
            data = AES_Decode(data, AES256Cipher.key);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return data;
    }
}
 

 

 

PHP 코드

<?php
ini_set("display_startup_errors"1);
ini_set("display_errors"1);
error_reporting(E_ALL);
 
$key = "testggisuitken1959imy91jb7076jas";
//$key = "cde0123456789abf";
 
$encypted_text = "t7VJP1+3mcZlcJsh9nChPSUYOZSw+QIl2UFJlvkis8Y=";
$text = "암호화 예제";
 
echo '평문 : '.$text.'<br/>';
echo 'PHP 암호화  : '.AES_encrypt($text).'<br/>';
echo 'Java 암호문 : '.$encypted_text.'<br/>';
echo 'PHP  복호화 : '.AES_decrypt($encypted_text).'<br/>';
 
// AES 암호화
function AES_encrypt($plain_text){
    global $key;
    $encryptedMessage = openssl_encrypt($plain_text"aes-256-cbc"$keytrue,str_repeat(chr(0), 16));
    return base64_encode($encryptedMessage);
}
 
// AES 복호화
function AES_decrypt($base64_text){
    global $key;
    $decryptedMessage = openssl_decrypt(base64_decode($base64_text), "aes-256-cbc"$keytrue, str_repeat(chr(0), 16));
    return $decryptedMessage;
}
 
?>
 

 

Java 에서 암호화하고 PHP 에서 복호화하는 것 뿐만 아니라

PHP 에서 암호화하고 Java 에서 복호화하는 것도 문제없이 잘 된다.

 

블로그 이미지

Link2Me

,
728x90

PHP 에서 특정 날짜를 구하는 예제이다.

<?php
ini_set("display_startup_errors", 1);
ini_set("display_errors", 1);
error_reporting(E_ALL);

$today = date("Y-m-d");
$end_date = date('Y-m-d', strtotime('-1 day'));

echo $today.'<br/>';
echo $end_date.'<br/>';

date("Y-m-d H:i:s", strtotime("-1 day")); // 어제 
date("Y-m-d H:i:s", strtotime("now")); // 현재 
date("Y-m-d H:i:s", strtotime("+1 day")); // 내일 
date("Y-m-d H:i:s", strtotime("+1 week")); // 일주일 후 
date("Y-m-d H:i:s", strtotime("-1 month")); // 한달 전 
date("Y-m-d H:i:s", strtotime("+1 month")); // 다음달 
date("Y-m-d H:i:s", strtotime("+1 week 2 days 3 hours 4 seconds")); // 1주 2일 3시간 4초 후 
date("Y-m-d H:i:s", strtotime("next Thursday")); // 다음주 목요일 
date("Y-m-d H:i:s", strtotime("last Monday")); // 지난 월요일

$date = "2021-04-01";
$today = date('Y-m-d', strtotime($date));
$end_date = date('Y-m-d', strtotime($date.' -1 day'));
$c_date =  date("Y-m-d H:i:s", strtotime($date. ' + 3 days'));

echo $today.'<br/>';
echo $end_date.'<br/>';
echo $c_date;
?>
블로그 이미지

Link2Me

,
728x90

https://newsapi.org/v2/top-headlines?country=kr&category=science&apiKey=a30a7298cf91404494ce049edc3d0e5a 에 있는 자료를 안드로이드에서 가져와서 Recyclerview 로 처리하는 걸 하고 싶은데 안된다는 내용이다.


안드로이드 앱에서는 아래와 같은 에러가 발생한다.


분명히 Web에서 직접 URL을 입력하면 결과를 출력하고 있다.

직접 API 를 신청하는 것도 해봤다.




해결하는 방법은 PHP CURL 을 이용하면 된다.

<?php
// PHP cURL 모듈은 다양한 종류의 프로토콜을 사용하여 서버와 통신할 수 있도록 도와주는 모듈로 외부 사이트의 정보를 취득할 수 있다.
// 서버에 PHP CURL 모듈이 설치되어 있어야 한다.
$url = "https://newsapi.org/v2/top-headlines?country=kr&category=science&apiKey=a30a7298cf91404494ce049edc3d0e5a";
// curl이 설치 되었는지 확인
if (function_exists('curl_init')) {
    
    $ch = curl_init(); // curl 리소스 초기화
    curl_setopt($ch, CURLOPT_URL, $url); // url 설정    
    curl_setopt($ch, CURLOPT_HEADER, 0); // 헤더는 제외하고 content 만 받음    
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 응답 값을 브라우저에 표시하지 말고 값을 리턴

    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json'));
    curl_setopt($ch, CURLOPT_VERBOSE, true);

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); //true로 설정시 일부 https 사이트는 안 열림
    curl_setopt($ch, CURLOPT_SSLVERSION,1); //ssl 셋팅

    $content = curl_exec($ch);    
    curl_close($ch); // 리소스 해제

    $R = json_decode($content,TRUE); // JSON to Array
    echo json_encode($R); // JSON

} else {
    // curl 라이브러리가 설치 되지 않음. 다른 방법 알아볼 것
    echo "This website not installed PHP's curl function.";
}
?>


서버에 올려진 이 URL 을 호출하면 원하는 News API 자료를 가져올 수 있다.

앱 출력 결과




블로그 이미지

Link2Me

,
728x90

SMS OTP 인증 구현을 위한 첫번째 단계 설계 개념이다.

ID/PW 인증 방식에 SMS OTP 인증을 추가하는 개념이다.


1. ID/PW 인증
   - 로그인한 정보에 오늘 날짜 SMS 인증 기록 유무를 가져온다.
   - 오늘날짜 인증기록이 없으면 SMS 인증으로 분기한다.
   - SMS 인증 기록이 있으면, PIN 번호 인증을 한다.
2. SMS OTP 인증 (1일 1회 인증 원칙)
   - SMS 인증 API를 통해 휴대폰으로 인증번호 발송
   - 인증번호 6자리를 입력하고 검증(verify) API 로 전송
   - 검증(verify) API 로부터 success return을 받으면
   - 서버에 사용자 인증 시각 정보를 기록한다.
   - 전일 인증 기록이 있을 경우 당일 인증 요청이 없는 것으로 간주하고 사용자 인증 정보를 update 한다.
   - error를 받으면 에러 상황에 맞는 것을 Popup으로 보여주고 로그인 종료처리한다.

위 로직을 기반으로 PHPClass 함수를 정의하고 코드 구현 예정이다.


Android : 서버 인증 결과를 JSON 으로 받아서 화면에서 인증 처리

  - Custom Dialog 방식 또는 New Activity 방식

PHP : Ajax를 이용한 인증 처리 로직 수정 보완

블로그 이미지

Link2Me

,
728x90

네이버 지오코더 API 를 이용하여 주소 → 위치좌표를 반환하는 PHP 코드와 네이버 지도상에 마커를 보여주는 Javascript 구현 코드 예제다.

IP주소 및 경로 등록이 되어있어야만 Naver Map 이 화면에 보여지며, Naver Cloud 신청에 대한 사항은 https://link2me.tistory.com/1832 게시글을 참조하면 된다.

 

주소 → 위치좌표 변환을 위해서는 Naver Cloud 에서 Geocorder API가 신청되어 있어야 한다.

 

Web 브라우저에 보이기 위해서는 Web Dynamic Map 이 신청되어 있어야 한다.

 

 

<?php
//error_reporting(0);
//error_reporting(E_ALL);
//ini_set("display_errors", 1);

function getNaverGeocode($addr) {
    $addr = urlencode($addr);
    $url = "https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode?query=".$addr;
    $headers = array();
    $headers[] ="X-NCP-APIGW-API-KEY-ID:xz06ez230a";
    $headers[] ="X-NCP-APIGW-API-KEY:e0A5km9e7Rh5S9QOkr1TRfa4NW8MaDblKAXcrQXL";

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

$shop_name = "광제당한의원";
$addr = "경기도 안산시 단원구 선부광장1로 56";
$geo = getNaverGeocode($addr);
$data = json_decode($geo,1);

$map_y_point = $data['addresses'][0]['x']; // x 좌표값과 y좌표값이 바뀌어서 출력됨
$map_x_point = $data['addresses'][0]['y'];

$lat = $map_x_point;
$lng = $map_y_point;
?>
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta http-equiv="expires" content="0" />
<meta http-equiv="pragma" content="no-cache" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<script src="https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=
xz06ez230a&submodules=geocoder"></script>

</head>
<body>
<div class="container-fluid text-center">
    <div class="row">
        <div class="col-md-12">
            <div class="content" id="content">
                <div id="map" style="width:100%;height:450px;"></div>
            </div>
        </div>
    </div>
</div>

<script>
var lat = "<?php echo $lat;?>";
var lng = "<?php echo $lng;?>";
var shop_name = "<?php echo $shop_name;?>";
var addr = "<?php echo $addr;?>";
var HOME_PATH = window.HOME_PATH || '.';

var map = new naver.maps.Map('map', {
   useStyleMap: true,
   center: new naver.maps.LatLng(lat, lng), //지도의 초기 중심 좌표
   zoom: 15, //지도의 초기 줌 레벨
   minZoom: 7, //지도의 최소 줌 레벨
   zoomControlOptions : { //줌 컨트롤의 옵션
       position : naver.maps.Position.TOP_RIGHT
   },
   mapTypeControl : true
});

// 마커 표시
var marker = new naver.maps.Marker({
    position: new naver.maps.LatLng(lat, lng),
    map: map
});

var contentString = [
        '<div style="text-align:center;padding-left:15px;padding-right:15px;padding-top:5px;">',
        '   <h4>'+shop_name+'</h4>',
        '   <p>'+addr+'<br />',
        '   </p>',
        '</div>'
    ].join('');

var infowindow = new naver.maps.InfoWindow({
    content: contentString
});

naver.maps.Event.addListener(marker, "click", function(e) {
    if (infowindow.getMap()) {
        infowindow.close();
    } else {
        infowindow.open(map, marker);
    }
});

infowindow.open(map, marker);
</script>
</body>
</html>
 

 

참고사이트

https://github.com/navermaps/maps.js/tree/master/examples/map

 

https://navermaps.github.io/maps.js/docs/tutorial-3-geocoder-geocoding.example.html

 

https://navermaps.github.io/android-map-sdk/guide-ko/0.html

 

https://sir.kr/g5_tip/10880

 

 

블로그 이미지

Link2Me

,
728x90

PHPExcel 이 deprecated 되어 PHP 7.2 이상에서 지원이 안되므로 PHPSpreadsheet 를 설치해야 한다.


이용환경 : CentOS 7


PHP 7.3 yum 설치 스크립트 : https://link2me.tistory.com/1841 참조


설치 방법

- 윈도우 환경에서는 https://getcomposer.org/download/ 에서 설치 파일을 다운로드 하는 거 같다.

- 리눅스 설치 환경에서는 composor 가 설치되어 있어야 한다.

https://zetawiki.com/wiki/%EB%A6%AC%EB%88%85%EC%8A%A4_composer_%EC%84%A4%EC%B9%98

에 나온 방법대로 설치를 한다.


먼저 vi /etc/php.ini 에서 allow_url_fopen = On 이 되어 있어야 아래 코드가 동작된다.


curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
composer -V
export COMPOSER_ALLOW_SUPERUSER=1
composer -V
echo "export COMPOSER_ALLOW_SUPERUSER=1" >> ~/.bashrc
cat ~/.bashrc | grep export




이제 PhpSpreadsheet 의 설치는 PHP가 설치된 경로에서 한다.


cd /var/www/html/

composer require phpoffice/phpspreadsheet




실 사용 예제

기존 PHPExcel 라이브러리를 이용하여 사용하던 코드에서 변경할 부분만 변경해서 사용하면 된다.

<?php
error_reporting(0);
ini_set('memory_limit', -1); // 메모리 제한을 해제해준다.

require_once 'path.php';// root 폴더를 기준으로 상대적인 경로 자동 구하기
require_once $g['path_root'].'sessionChk.php'; // 세션 체크
require_once $g['path_config'].'config.php';
require_once $g['path_class'].'dbconnect.php';
require_once $g['path_class'].'adminClass.php';
require_once $g['path_admin'].'PHPExcel.php';
$a = new adminClass();

$fname="members";
$posArr=$a->StaffPositionMNArray();

$objPHPExcel = new PHPExcel();
$objPHPExcel->setActiveSheetIndex(0); //set first sheet as active

$objSheet = $objPHPExcel->getActiveSheet();

$objPHPExcel->getDefaultStyle()->getFont()->setSize(12); // 폰트 사이즈
$objSheet->SetCellValue('A2', "번호");
$objSheet->SetCellValue('B2', "성명");
$objSheet->SetCellValue('C2', "직급");
$objSheet->SetCellValue('D2', "아이디");
$objSheet->SetCellValue('E2', "부서1");
$objSheet->SetCellValue('F2', "부서2");
$objSheet->SetCellValue('G2', "부서3");
$objSheet->SetCellValue('H2', "부서4");
$objSheet->SetCellValue('I2', "등록일자");
$objSheet->SetCellValue('J2', "최근접속");
cellColor('A2:J2', 'F28A8C'); // 헤더 배경색 지정

$i=3; // 값을 기록할 셀의 시작위치
$rowCount = 1; // 넘버링

$sql="select * from members ";
$sql.=" order by idx";
$result=mysqli_query($db,$sql);
while($R=mysqli_fetch_array($result)){

    $objSheet->SetCellValue('A'.$i, $rowCount);
    $objSheet->SetCellValue('B'.$i, $R['username']);
    $objSheet->SetCellValue('C'.$i, $posArr[$R['codeID']]);
    $objSheet->SetCellValue('D'.$i, $R['userid']);
    $objSheet->SetCellValue('E'.$i, $R['group2']);
    $objSheet->SetCellValue('F'.$i, $R['group3']);
    $objSheet->SetCellValue('G'.$i, $R['group4']);
    $objSheet->SetCellValue('H'.$i, $R['group5']);
    $objSheet->SetCellValue('I'.$i, substr($R['regdate'],0,10));
    $objSheet->SetCellValue('J'.$i, SETDATE($R['date']));

    $i++;
    $rowCount++;
}

// 표 그리기
$i--;
$objSheet->getStyle('A2:J'.$i)->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);

// 헤더 칼럼 가운데 정렬
$objSheet->getStyle('A2:J2')->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);

// 셀 높이
$objSheet->getRowDimension(1)->setRowHeight(20);

// 칼럼 사이즈 자동 조정
$objSheet->getColumnDimension('A')->setWidth(6); // setWidth(18);  // 칼럼 크기 직접 지정
$objSheet->getColumnDimension('B')->setWidth(8);  // 칼럼 크기 직접 지정
$objSheet->getColumnDimension('C')->setWidth(10);
$objSheet->getColumnDimension('D')->setWidth(10);
$objSheet->getColumnDimension('E')->setWidth(21);
$objSheet->getColumnDimension('F')->setWidth(19);
$objSheet->getColumnDimension('G')->setWidth(18);
$objSheet->getColumnDimension('H')->setWidth(18);
$objSheet->getColumnDimension('I')->setWidth(11);
$objSheet->getColumnDimension('J')->setWidth(11);

// 파일 PC로 다운로드
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename='.$fname.'.xlsx');
header('Cache-Control: max-age=0');

$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, "Excel2007");
$objWriter->save('php://output');
exit;

// 엑셀의 셀 배경색 지정
function cellColor($cells,$color){
    global $objSheet;

    $objSheet->getStyle($cells)->getFill()->applyFromArray(array(
        'type' => PHPExcel_Style_Fill::FILL_SOLID,
        'startcolor' => array(
             'rgb' => $color
        )
    ));
}

function SETDATE($date){
    $date = preg_replace("/[^0-9]/", "", $date);    // 숫자 이외 제거
    return preg_replace("/([0-9]{4})([0-9]{2})([0-9]{2})$/", "\\1-\\2-\\3", $date);
}

?>
 



이제 PHPSpreadsheet 라이브러리를 이용한 코드 예제를 보면 변경된 부분이 뭔지 알 수 있다.

<?php
error_reporting(0);
ini_set('memory_limit', -1); // 메모리 제한을 해제해준다.

require_once 'path.php';// root 폴더를 기준으로 상대적인 경로 자동 구하기
require_once $g['path_root'].'sessionChk.php'; // 세션 체크
require_once $g['path_config'].'config.php';
require_once $g['path_class'].'dbconnect.php';
require_once $g['path_class'].'adminClass.php';
require_once $g['path_root'].'vendor/autoload.php';
$a = new adminClass();

$fname="members";
$posArr=$a->StaffPositionMNArray();

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$objPHPExcel = new Spreadsheet();
$objPHPExcel->setActiveSheetIndex(0); //set first sheet as active

$objSheet = $objPHPExcel->getActiveSheet();

$objPHPExcel->getDefaultStyle()->getFont()->setSize(12); // 폰트 사이즈
$objSheet->SetCellValue('A2', "번호");
$objSheet->SetCellValue('B2', "성명");
$objSheet->SetCellValue('C2', "직급");
$objSheet->SetCellValue('D2', "아이디");
$objSheet->SetCellValue('E2', "부서1");
$objSheet->SetCellValue('F2', "부서2");
$objSheet->SetCellValue('G2', "부서3");
$objSheet->SetCellValue('H2', "부서4");
$objSheet->SetCellValue('I2', "등록일자");
$objSheet->SetCellValue('J2', "최근접속");
// 헤더 배경색 지정
$objSheet->getStyle('A2:J2')->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setARGB('F28A8C');

$i=3; // 값을 기록할 셀의 시작위치
$rowCount = 1; // 넘버링

$sql="select * from members ";
$sql.=" order by idx";
$result=mysqli_query($db,$sql);
while($R=mysqli_fetch_array($result)){

    $objSheet->SetCellValue('A'.$i, $rowCount);
    $objSheet->SetCellValue('B'.$i, $R['username']);
    $objSheet->SetCellValue('C'.$i, $posArr[$R['codeID']]);
    $objSheet->SetCellValue('D'.$i, $R['userid']);
    $objSheet->SetCellValue('E'.$i, $R['group2']);
    $objSheet->SetCellValue('F'.$i, $R['group3']);
    $objSheet->SetCellValue('G'.$i, $R['group4']);
    $objSheet->SetCellValue('H'.$i, $R['group5']);
    $objSheet->SetCellValue('I'.$i, substr($R['regdate'],0,10));
    $objSheet->SetCellValue('J'.$i, SETDATE($R['date']));

    $i++;
    $rowCount++;
}

// 표 그리기
$i--;
$objSheet->getStyle('A2:J'.$i)->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);

// 헤더 칼럼 가운데 정렬
$objSheet->getStyle('A2:J2')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);

// 셀 높이
$objSheet->getRowDimension(1)->setRowHeight(20);

// 칼럼 사이즈 자동 조정
$objSheet->getColumnDimension('A')->setWidth(6); // setWidth(18);  // 칼럼 크기 직접 지정
$objSheet->getColumnDimension('B')->setWidth(8);  // 칼럼 크기 직접 지정
$objSheet->getColumnDimension('C')->setWidth(10);
$objSheet->getColumnDimension('D')->setWidth(10);
$objSheet->getColumnDimension('E')->setWidth(21);
$objSheet->getColumnDimension('F')->setWidth(19);
$objSheet->getColumnDimension('G')->setWidth(18);
$objSheet->getColumnDimension('H')->setWidth(18);
$objSheet->getColumnDimension('I')->setWidth(11);
$objSheet->getColumnDimension('J')->setWidth(11);

// 파일 PC로 다운로드
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename='.$fname.'.xlsx');
header('Cache-Control: max-age=0');

/* // OLD 버전
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, "Excel2007");
$objWriter->save('php://output');
*/
$writer = new Xlsx($objPHPExcel);
$writer->save('php://output');
exit;

function SETDATE($date){
    $date = preg_replace("/[^0-9]/", "", $date);    // 숫자 이외 제거
    return preg_replace("/([0-9]{4})([0-9]{2})([0-9]{2})$/", "\\1-\\2-\\3", $date);
}

?>
 


블로그 이미지

Link2Me

,
728x90

회원가입, 로그인, 게시판 글 등록시 스팸방지를 위해서 캡차코드를 적용할 수 있다.


https://www.phpcaptcha.org/ 에서 파일을 다운로드 하여 홈페이지에 업로드한다.


샘플코드를 간단하게 줄여서 테스트하고 적어둔다.


Form 입력코드

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
  <title>Securimage Example Form</title>
  <link rel="stylesheet" href="securimage.css" media="screen">
  <style type="text/css">
  <!--
  div.error { display: block; color: #f00; font-weight: bold; font-size: 1.2em; }
  span.error { display: block; color: #f00; font-style: italic; }
  .success { color: #00f; font-weight: bold; font-size: 1.2em; }
  form label { display: block; font-weight: bold; }
  fieldset { width: 90%; }
  legend { font-size: 24px; }
  .note { font-size: 18px;
  -->
  </style>
</head>
<body>

<fieldset>
<legend>Example Form</legend>
<form method="post" action="capchado.php" id="contact_form">
  <input type="hidden" name="do" value="contact">
  <p>
    <label for="ct_name">Name*:</label>
    <input type="text" id="ct_name" name="ct_name" size="35" value="">
  </p>

  <div>
    <?php
      require_once 'securimage.php';
      $options = array();
      $options['input_name'] = 'ct_captcha'; // change name of input element for form post
      $options['disable_flash_fallback'] = false; // allow flash fallback
      echo Securimage::getCaptchaHtml($options);
    ?>
  </div>

  <p>
    <br>
    <input type="submit" value="전송">
  </p>

</form>
</fieldset>

</body>
</html>


Form 에서 전송받은 데이터를 처리하는 코드

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

if ($_SERVER['REQUEST_METHOD'] == 'POST' && @$_POST['do'] == 'contact') {
    var_dump($_POST); // 디버깅 목적으로 찍어보라.

    $captcha = @$_POST['ct_captcha'];
    require_once dirname(__FILE__) . '/securimage.php';
    $securimage = new Securimage();

    if ($securimage->check($captcha) == false) {
        $captcha_error = '잘못된 보안코드가 입력되었습니다.';
        echo '<br/><br/>'.$captcha_error.'<br/>';
    } else {
      echo '<br/><br/>캡차 제대로 입력했어요<br/>';
    }

} // POST
?>


이 코드를 jQuery 로 처리하기 위해서는 소스보기로 해서 캡차의 input name 값이 뭔지 확인을 해보고 jQuery 입력체크를 하면 된다.

블로그 이미지

Link2Me

,
728x90

개발용 서버에서 기능 테스트를 할 때 안전하게 전화번호 부분을 일괄 임시번호로 변경하면 개인정보 보호에 더 좋을 수 있어서 일괄 변경하는 기능을 만들어서 적용해봤다.

 

<?php
require_once '../sessionChk.php'// 세션 체크
require_once "../config/dbconnect.php";
 
$i = 0;
 
$sql = "SELECT idx FROM SYS_MEMBER";
$result = mysqli_query($db,$sql);
while($row = mysqli_fetch_row($result)){
    $i++;
    $mobileNO = '010-1000-'.sprintf('%04d',$i);
    $mobileNO = str_replace('-','',$mobileNO);
    $sql = "UPDATE SYS_MEMBER SET mobileNO='$mobileNO' WHERE idx=".$row[0];
    mysqli_query($db,$sql);
}
 
echo $i.' rows Updated';
 
?>
 

 

 

 

 

<?php
if(!isset($_SESSION)) {
    session_start();
}
require_once 'path.php';// root 폴더를 기준으로 상대적인 경로 자동 구하기
require_once $g['path_root'].'sessionChk.php';
require_once $g['path_root'].'deviceChk.php';
if($mtype == 3){
    require_once $g['path_root'].'ipFiltering.php';
}
require_once $g['path_config'].'dbconnect.php';
require_once $g['path_class'].'dbDataClass.php';
$d = new DBDataClass();
 
$sql ="select * from members";
$result=mysqli_query($db,$sql);
$i=0;
while($row=mysqli_fetch_array($result)){
    $i++;
    if(strlen($row['mobileNO'])>0){
        $telNO = TelNumSplitArr($row['mobileNO'])."0001".sprintf("%04d",$i);
        echo $telNO.'<br/>';
        $QKEY ="mobileNO='".$telNO."'";
        $d->getDbUpdate('members',$QKEY,'uid="'.$row['uid'].'"');
    }
 
    if(strlen($row['officeNO'])>0){
        $officeNO = TelNumSplitArr($row['officeNO'])."0001".sprintf("%04d",$i);
        //echo $officeNO.'<br/>';
        $QKEY ="officeNO='".$officeNO."'";
        $d->getDbUpdate('members',$QKEY,'uid="'.$row['uid'].'"');
    }
 
}
 
//전화번호를 정규식을 이용하여 지역번호, 010과 같은 앞자리는 그대로 두기 위해서 앞부분만 추출한다.
function TelNumSplitArr($tel){
    $tel = preg_replace("/[^0-9]/"""$tel);    // 숫자 이외 제거
    if (substr($tel,0,2)=='02')
        return preg_replace("/([0-9]{2})([0-9]{3,4})([0-9]{4})$/""\\1"$tel);
    else
        return preg_replace("/([0-9]{3})([0-9]{3,4})([0-9]{4})$/""\\1"$tel);
}
 
?> 

 

블로그 이미지

Link2Me

,
728x90

PHP 에서 문자를 발송할 때 ***님이라고 이름을 변경해서 보내는 문자를 할 때 좋은 기능이 될 거 같아서 적어둔다.


<?php
$str = '안녕하세요. [name]님. 오늘 날씨가 참 좋습니다. 이번 모임은 OO에서 개최합니다.';
$arr = array('홍길동','이순신','김구','을지문덕');

foreach($arr as $name){ // 배열에만 동작하는 반복문 foreach문
    // 콜백을 이용한 정규 표현식 검색과 치환을 수행
    // preg_replace_callback ( $pattern , $callback , $str )
    // 매치가 발견되면 새 str 반환되고, 그렇지 않으면 변경되지 않은 str 가 반환
    $text_message = preg_replace_callback('#\[name\]#',
        function($match) use ($name) {
            return replaceForm($name);
        }, $str);
    echo $text_message.'<br/>';
}

function replaceForm($name) {
    static $idx = 0;
    $idx++;
    return str_replace('{{idx}}', $idx, $name);
}

?>


블로그 이미지

Link2Me

,
728x90

PHP 날짜와 시간 차이에 대한 테스트 결과다.

그냥 복사해서 테스트해보면 결과를 확인 할 수 있다.

 

<?php
date_default_timezone_set('Asia/Seoul');
$start = '2019-03-23';
$end = '2019-03-25';
$gap = DateDiff($start,$end);
echo '<pre>';print_r($gap);echo '</pre>';

echo DateDisplay( $gap->y, $gap->m, $gap->d).'<br />';
echo $gap->days.'일<br /><br />';

$curTime = date("Y-m-d H:i:s"); // 현재 날짜 및 시간
$access_date = "2019-03-26 09:56:22";

$date1 = strtotime($access_date);
$date2 = strtotime($curTime);
$gaptime = $date2 - $date1;

echo $gaptime.'<br />'; // 초단위 시간으로 반환
echo time_diff($access_date,$curTime).'<br />'; // 초단위 시간으로 반환

$seconds = $gaptime % 60;
$minutes = floor(($gaptime % 3600) / 60);
$hours = floor($gaptime / 3600);
echo $hours.":".$minutes.":".$seconds.'<br />';

$gap = DateDiff($access_date,$curTime);
echo $gap->format('%h:%i:%s').'<br /><br />';

echo '<pre>';print_r($gap);echo '</pre>';
echo DateDisplay( $gap->y, $gap->m, $gap->d).'<br />';

function DateDiff($startDate,$endDate){
    $date1 = new DateTime($startDate);
    $date2 = new DateTime($endDate);

    $gap = $date1->diff($date2);
    return $gap;
}

function DateDisplay($y,$m,$d){
    $gap ='Diff : ';
    if($y > 0) $gap.=$y."년 ";
    if($m > 0) $gap.=$m."월 ";
    $gap.=$d."일 ";
    return $gap;
}

function time_diff($datetime1, $datetime2) {
  return date('U',strtotime($datetime2))-date('U',strtotime($datetime1));
}
?>

 

 

로그인 시도 실패후 5분이 경과되면 다시 로그인을 할 수 있도록 만들기 위한 함수를 만들어 보자.

5분 = 300초 이므로

 

DB 테이블 칼럼에 저장된 시간을 $access_date = "2019-03-26 09:56:22";
이라 하고

현재 시간을 $curTime = date("Y-m-d H:i:s"); // 현재 날짜 및 시간

$gap = time_diff($access_date,$curTime); // 초단위 시간으로 반환

if($gap > 300){

   로그인 차단 설정을 허용으로 변경

} else {

   로그인 차단 메시지 팝업

}

블로그 이미지

Link2Me

,
728x90

jQuery 로 select 박스가 2개인 것의 값을 제어하는 걸 테스트하고 적어둔다.

 

여기서 알아둘 사항은 Javascript/jQuery 로 현재 URL, 경로 가져오는 방법이다.

//window.location is an object in javascript.
window.location.host             #returns host
window.location.hostname     #returns hostname
window.location.path             #return path
window.location.href             #returns full current url
window.location.port             #returns the port
window.location.protocol       #returns the protocol

// in jquery you can use
$(location).attr('host');          #returns host
$(location).attr('hostname');  #returns hostname
$(location).attr('path');         #returns path
$(location).attr('href');         #returns href
$(location).attr('port');         #returns port
$(location).attr('protocol');   #returns protocol



// To get the URL of the parent window from within an iframe
$(window.parent.location).attr('href');


http://www.abc.com:8082/index.php#tab2?foo=789

Property                                Result
----------------------------------------------------
$(location).attr('host')            www.abc.com:8082
$(location).attr('hostname')    www.abc.com
$(location).attr('port')            8082
$(location).attr('protocol')      http:
$(location).attr('pathname')   index.php
$(location).attr('href')           http://www.abc.com:8082/index.php#tab2
$(location).attr('hash')         #tab2
$(location).attr('search')       ?foo=789

 

 

기본적인 HTML 문법과 PHP를 혼용하여 사용하고 있다.

PHP는 대체문법을 사용하여 깔끔하게 보기좋게 정렬을 하고 있고, 함수화를 통해서 코드를 심플하게 보이도록 구현되어 있다.

 

<?php
include_once "connect.php";
include_once "dbDataClass.php";
$d = new DBDataClass();
$cat1 = isset($_GET['cat1'])? $_GET['cat1'] : 0;
$cat2 = isset($_GET['cat2'])? $_GET['cat2'] : 0;
?>
구분1 <select name="cat1" id="cat1">
    <option value="">+ 구분</option>
    <?php $_CAT1 = $d->getDbArray('menu_items''parent_id=0''*'''01);?>
    <?php while($_CA1 = mysqli_fetch_array($_CAT1)):?>
    <option value="<?php echo $_CA1['id']?>"<?php if($_CA1['id']==$cat1):?> selected<?php endif ?>><?php echo $_CA1['name']?></option>
    <?php endwhile ?>
    </select>
 
    &nbsp;&nbsp;&nbsp;구분2
    <select name="cat2" id="cat2">
    <option value="">+ 구분</option>
    <?php if($cat1):?>
    <?php $_CAT2 = $d->getDbArray('menu_items''parent_id='.$cat1, '*'''01); ?>
    <?php while($_CA2 = mysqli_fetch_array($_CAT2)):?>
    <option value="<?php echo $_CA2['id']?>"<?php if($_CA2['id']==$cat2):?> selected<?php endif ?>><?php echo $_CA2['name']?></option>
    <?php endwhile ?>
    <?php endif ?>
    </select>&nbsp;&nbsp;&nbsp;
    <!--구분 -->
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$('#cat1').on('change',function(){
    var cat1 = $("#cat1 option:selected").val(); // this.value
    location.href = $(location).attr('pathname'+ '?cat1='+cat1;
});
$('#cat2').on('change',function(){
    var cat1 = $("#cat1 option:selected").val();
    var cat2 = $("#cat2 option:selected").val();
    location.href = window.location.pathname + '?cat1='+cat1+'&cat2='+cat2;
});
</script>

 

 아래 코드 예시는 Secure Coding을 고려하여 작성한 코드 중에서 필요한 부분만 발췌하여 적은 것이다.

MDB(Material Design Bootsrap4) 코드를 적용한 select 가 포함되어 있다.

<?php
$link_url = "MemberList.php"// 현재 실행중인 파일명 가져오기
$rowsPage = 10// 한 화면에 표시되는 게시글 수
$curPage = isset($_GET['p']) ? $a->NoFilter($_GET['p']) : 1;
$m = isset($_GET['m']) ? $a->XSSFilter($_GET['m']) :'list';
$cat1 = isset($_GET['cat1']) ? $a->XSSFilter($_GET['cat1']) :'';
 
$g['url_link']=($m?'m='.$m.'&amp;':'').($cat1?'&amp;cat1='.$cat1.'&amp;':'').($where?'where='.$where.'&amp;':'').($keyword?'keyword='.urlencode(stripslashes($keyword)).'&amp;':'');
$g['bbs_reset'= $link_url.'?'.($m?'m='.$m.'&amp;':'');
 
?>
 
<div class="table-responsive text-nowrap">
<p class="h4 mb-4">회원 현황</p>
<div class="float-left info">
    <?php if$keyword ):?><strong>"<?php echo $keyword?>"</strong> 검색결과 : <?php endif?>
    <?php echo number_format($NUM)?>개 (<?php echo $curPage;?>/<?php echo $TPG;?>페이지)
</div>
 
<?php if($_SESSION['authID'== 2):?>
<div class="float-right info">
<select id="cat1" class="browser-default custom-select">
<?php $cats = $a->getDbArray('orgTree''parent_id=0''*'''01);?>
    <option value="">-본부-</option>
    <?php foreach($cats as $C): ?>
        <option value="<?php echo $C['id'];?>"<?php if($C['id']==$cat1):?> selected<?php endif;?>><?php echo $C['name'];?></option>
    <?php endforeach;?>
</select>
</div>
<?php endif;?>
 
<script>
$('#cat1').on('change',function(e){
    e.preventDefault();
    var cat1 = $("#cat1 option:selected").val(); // this.value
    var uri = $('#urlPath').attr('url-path');
    MemberListTable(where,keyword,curPage,uri,cat1);
});
</script>
 

 

 

블로그 이미지

Link2Me

,
728x90

음력 달력 예제를 가지고 수정해서 만들어본 코드다.


달력의 모양은 위와 같다.

ㅇ bootstrap 코드로 수정 보완

    - 해상도에 따라 일부 좀 수정해야 할 부분이 있음.

ㅇ jQuery 일정 등록 기능 추가

   - 해당 셀에서 마우스 클릭하면 일정 등록 추가 화면 팝업

   - 등록된 일정에 마우스를 클릭하면 삭제 여부 문의 및 삭제 처리

   - 코드를 좀 더 보완해야 할 듯....

ㅇ 음력 및 간지 지원 (음력 지원 DB 활용)

ㅇ 대체공휴일 코드 추가

    - 어린이날, 설날, 추석 대체공유일 코드

ㅇ 기념일 등록

    - 기념일을 등록하는 코드 파일은 미 구현(DB에 직접 기록하는 방법으로 테스트)

    - 태어난 연도 이전에는 표시되지 않도록 하는 코드는 미구현


음력은 함수 lun2sol.php 파일은 만세력 달력을 찾아보니 데이터가 불일치한다.

그래서 MySQL DB 데이터 기준으로 동작되도록 코드를 수정했다.

검색해보니 고영창 만세력 코드가 있는데 이것으로 테스트는 해봤지만 이 코드에 맞춰서 테스트는 아직 안해봤다.

MySQL DB파일 사이즈가 좀 되다보니 용량이 조금 크다고 볼 수도 있다.


테이블 구조

 CREATE TABLE IF NOT EXISTS `memorials` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `category` int(4) NOT NULL,
  `subject` text NOT NULL,
  `start_year` char(4) DEFAULT NULL,
  `memorial_date` varchar(4) NOT NULL,
  `dateType` tinyint(2) NOT NULL DEFAULT '0',
  `writing_date` date NOT NULL DEFAULT '0000-00-00',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

--
-- 테이블의 덤프 데이터 `memorials`
--

INSERT INTO `memorials` (`id`, `category`, `subject`, `start_year`, `memorial_date`, `dateType`, `writing_date`) VALUES
(1, 1, '홍길동 생일', '1978', '0827', 1, '2018-10-30'),
(2, 1, '이정민 생일', '1979', '1215', 1, '2018-10-30'),
(3, 1, '홍진경 생일', '1992', '0614', 0, '2018-10-30');

-- --------------------------------------------------------

--
-- 테이블 구조 `memorial_data`
--

CREATE TABLE IF NOT EXISTS `memorial_data` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `relatedid` int(11) NOT NULL,
  `solar_date` date NOT NULL DEFAULT '0000-00-00',
  `lunar_date` date NOT NULL DEFAULT '0000-00-00',
  `yun` tinyint(1) NOT NULL DEFAULT '0',
  `subject` text NOT NULL,
  `category` int(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `relatedid` (`relatedid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

-- --------------------------------------------------------

--
-- 테이블 구조 `tbl_events`
--

CREATE TABLE IF NOT EXISTS `tbl_events` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `start` date NOT NULL,
  `end` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;



<?php
define("PHP_SELF", $_SERVER['PHP_SELF']);
error_reporting(error_reporting() & ~E_NOTICE);
if (!isset($cellh))
    $cellh = 70; // date cell height
if (!isset($tablew))
    $tablew = 650; //table width
$cellw = 130;
//---- 오늘 날짜
$thisyear = date('Y'); // 4자리 연도
$thismonth = date('n'); // 0을 포함하지 않는 월
$today = date('j'); // 0을 포함하지 않는 일

// $year, $month 값이 없으면 현재 날짜
$year = isset($_GET['year']) ? $_GET['year'] : $thisyear;
$month = isset($_GET['month']) ? $_GET['month'] : $thismonth;
$day = isset($_GET['day']) ? $_GET['day'] : $today;

//------ 날짜의 범위 체크
if (($year > 2038) or ($year < 1900))
    ErrorMsg("연도는 1900 ~ 2038년만 가능합니다.");

$last_day = date('t', mktime(0, 0, 0, $month, 1, $year)); // 해당월의 총일수 구하기

$prevmonth = $month - 1;
$nextmonth = $month + 1;
$prevyear = $nextyear = $year;
if ($month == 1) {
    $prevmonth = 12;
    $prevyear = $year - 1;
} elseif ($month == 12) {
    $nextmonth = 1;
    $nextyear = $year + 1;
}
$pre_year = $year - 1;
$next_year = $year + 1;


include_once 'dbconnect.php'; // DB 연결
include_once 'lun2sol.php';  //양력.음력 변환 인클루드

/****************** lunar_date ************************/
$predate = date("Y-m-d", mktime(0, 0, 0, $month - 1, 1, $year));
$nextdate = date("Y-m-d", mktime(0, 0, 0, $month + 1, 1, $year));

$sql = "SELECT solar_date,ganji,lunar_date,yun FROM lunar_data where solar_date between '$predate' and '$nextdate' ";
$result = mysqli_query($dbconn, $sql) or die(mysqli_error($dbconn));
while ($R = mysqli_fetch_array($result)) {
    $lunarData[] = array(0 => date("n-j", strtotime($R['solar_date'])), 1 => $R['ganji'], 2 => date("n.j", strtotime($R['lunar_date'])), 3 => date("j", strtotime($R['lunar_date'])), 4 => $R['yun']);
}
//echo '<pre>';print_r($lunarData);echo '</pre>';
/****************** lunar_date ************************/

/****************** 기념일 데이터 ************************/
// 음력 기념일을 생성하면 시작년도부터 해당 양력일자를 자동으로 생성 처리??
$sql = "SELECT category,subject,memorial_date,dateType FROM memorials";
$result = mysqli_query($dbconn, $sql);
while ($R = mysqli_fetch_array($result)) {
    if($R['dateType'] == 1){ // 음력
        //$tmp = lun2sol($year . $R['memorial_date']); // 정확도가 맞는지 확인 필요
        $lunar_temp = $year ."-".substr($R['memorial_date'],0,2)."-".substr($R['memorial_date'],2,2);
        $rsql = "SELECT solar_date,num,yun,lunar_date FROM lunar_data where lunar_date='".$lunar_temp."'";
        $rs = mysqli_query($dbconn, $rsql);
        $RS = mysqli_fetch_array($rs);
        $tmp = strtotime($RS[0]);
        if(substr($RS[0],0,4) !== $year){ // 음력 기념일이 같은 해가 아니면
            $sql = "SELECT count(relatedid) FROM memorial_data where relatedid=".$RS[1]." and solar_date='".$RS[0]."' and yun=".$RS[2]." and subject='".$R['subject']."' ";
            $rt = mysqli_query($dbconn, $sql);
            $RT = mysqli_fetch_array($rt);
            if($RT[0] == 0){ // 일치하는 데이터가 없으면
                $sql ="INSERT INTO memorial_data (relatedid,solar_date,lunar_date,yun,subject,category) ";
                $sql.="VALUES (".$RS[1].",'".$RS[0]."','".$RS[3]."','".$RS[2]."','".$R['subject']."','".$R['category']."')";
                mysqli_query($dbconn, $sql);
            }
        }
    } else { // 양력
        $tmp = strtotime($year ."-".substr($R['memorial_date'],0,2)."-".substr($R['memorial_date'],2,2));
    }
    $memorialData[] = array(0 => date("n-j",$tmp), 1 => $R['category'], 2 => $R['subject']);
}

// 음력 기념일이 같은 해에 없는 경우 테이블에 생성된 데이터를 조회 및 추가
$sql = "SELECT solar_date,subject,category FROM memorial_data where solar_date between '$predate' and '$nextdate' ";
$result = mysqli_query($dbconn, $sql);
while ($R = mysqli_fetch_array($result)) {
    $tmp = strtotime($R[0]);
    $memorialData[] = array(0 => date("n-j",$tmp), 1 => $R['category'], 2 => $R['subject']);
}

/****************** 휴일 정의 ************************/
$Holidays = Array();
$Holidays[] = array(0 => '1-1', 1 => '신정');
$Holidays[] = array(0 => '3-1', 1 => '삼일절');
$Holidays[] = array(0 => '5-5', 1 => '어린이날');
$Holidays[] = array(0 => '6-6', 1 => '현충일');
$Holidays[] = array(0 => '7-17', 1 => '제헌절');
$Holidays[] = array(0 => '8-15', 1 => '광복절');
$Holidays[] = array(0 => '10-3', 1 => '개천절');
$Holidays[] = array(0 => '10-9', 1 => '한글날');
$Holidays[] = array(0 => '12-25', 1 => '성탄절');

//$tmp = lun2sol($year . "0101");  //설날
$tmp = strtotime(Lun2SolDate($year."-01-01"));
$Holidays[] = array(0 => date("n-j", ($tmp - (3600 * 24))), 1 => '');
$Holidays[] = array(0 => date("n-j", $tmp), 1 => '설날');
$Holidays[] = array(0 => date("n-j", ($tmp + (3600 * 24))), 1 => '');

//$tmp = lun2sol($year . "0408");  //석가탄신일
$tmp = strtotime(Lun2SolDate($year."-04-08"));
$Holidays[] = array(0 => date("n-j", $tmp), 1 => '석탄일');

//$tmp = lun2sol($year . "0815"); //추석
$tmp = strtotime(Lun2SolDate($year."-08-15"));
$Holidays[] = array(0 => date("n-j", ($tmp - (3600 * 24))), 1 => '');
$Holidays[] = array(0 => date("n-j", $tmp), 1 => '추석');
$Holidays[] = array(0 => date("n-j", ($tmp + (3600 * 24))), 1 => '');

// 어린이날 대체공휴일 검사 : 어린이날은 토요일, 일요일인 경우 그 다음 평일을 대체공유일로 지정
$childdayChk = isWeekend($year."-05-05");
if($childdayChk == 0) $Holidays[] = array(0 => date("n-j", strtotime($year."-05-06")), 1 => '대체공휴일');
if($childdayChk == 6) $Holidays[] = array(0 => date("n-j", strtotime($year."-05-07")), 1 => '대체공휴일');

// 설날 대체공휴일 검사
if(isWeekend(Lun2SolDate($year."-01-01")) == 0)
    $Holidays[] = array(0 => date("n-j", strtotime(Lun2SolDate($year."-01-03"))), 1 => '');
if(isWeekend(Lun2SolDate($year."-01-01")) == 1)
    $Holidays[] = array(0 => date("n-j", strtotime(Lun2SolDate($year."-01-03"))), 1 => '');
if(isWeekend(Lun2SolDate($year."-01-02")) == 0)
    $Holidays[] = array(0 => date("n-j", strtotime(Lun2SolDate($year."-01-03"))), 1 => '');


// 추석 대체공휴일 검사
if(isWeekend(Lun2SolDate($year."-08-14")) == 0)
    $Holidays[] = array(0 => date("n-j", strtotime(Lun2SolDate($year."-08-17"))), 1 => '');
if(isWeekend(Lun2SolDate($year."-08-15")) == 0)
    $Holidays[] = array(0 => date("n-j", strtotime(Lun2SolDate($year."-08-17"))), 1 => '');
if(isWeekend(Lun2SolDate($year."-08-16")) ==0)
    $Holidays[] = array(0 => date("n-j", strtotime(Lun2SolDate($year."-08-17"))), 1 => '');

/****************** 휴일 정의 ************************/

/****************** schedule ************************/
$sql = "SELECT * FROM tbl_events where start between '$predate' and '$nextdate' ";
$result = mysqli_query($dbconn, $sql);
while ($R = mysqli_fetch_array($result)) {
    $schedule[] = array(0 => date("n-j", strtotime($R['start'])), 1 =>date("n-j", strtotime($R['end'])) ,2 => $R['title'],3 => $R['id']);
}
//echo '<pre>';print_r($schedule);echo '</pre>';
/****************** schedule ************************/

?>

<!DOCTYPE html>
<html lang="ko">
<head>
<title>PHP Calendar</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<style>
    body{margin-top: 20px; }
    .all {border-width: 1;border-color: #cccccc;border-style: solid;}
    font {font-family: 굴림체;font-size: 12px;color: #505050;    }
    font.title {font-family: 굴림체;font-size: 12px;font-weight: bold;color: #2579CF;    }
    font.week {font-family: 돋움,돋움체;color: #ffffff;font-size: 8pt;    letter-spacing: -1;}
    font.holy {font-family: tahoma;font-size: 22px;color: #FF6C21;}
    font.blue {font-family: tahoma;font-size: 22px;color: #0000FF;}
    font.black {font-family: tahoma;font-size: 22px;color: #000000;}
    font.lunar {font-family: tahoma;font-size: 14px;color: #0000bb;}
    font.gangi {font-family: tahoma;font-size: 14px;color: #424242;}
    font.sblue {font-family: tahoma;font-size: 14px;color: blue;    }
    font.green {font-family: tahoma;font-size: 14px;color: green;    }
    font.red {font-family: tahoma;font-size: 14px;color: red;}
    font.num {font-family: tahoma;font-size: 14px;background-color: #DBA901;}
    font.gray {font-family: tahoma;font-size: 14px;color: #bbbbbb;}
    .main {float: left;width: 70%;border: 5px solid #ccc;background-color: #fff;m }
    .right {float: right;width: 20%;background-color: #fff;border: 5px solid #eee;}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script>
$(document).ready(function() {
    $(".calcell").click(function(){
        var val=$(this).attr("id");
        var date = val.split('-');
        var year = date[0];
        var month = date[1];
        var day = date[2];
        var title = prompt('Event Title:');
        $.ajax({
            url : 'add-event.php',
            type : 'POST',
            data :{year:date[0],month:date[1],day:date[2],title:title},
            success : function(data){
                if(data == 1){
                    location.reload();
                } else if(data == 0) {
                    alert('등록에 실패했습니다.');
                }
            },
            error: function(jqXHR, textStatus, errorThrown){
                alert("arjax error : " + textStatus + "\n" + errorThrown);
            }
        });
    });

    $(".num").click(function(e){
        var val=$(this).attr("uid");
        var deleteMsg = confirm("정말 삭제하시겠습니까?");
        if(deleteMsg){
            $.ajax({
                url : 'delete-event.php',
                type : 'POST',
                data :{id:val},
                success: function (data) {
                    if(data == 1){
                        location.reload();
                    } else if(data == 0) {
                        alert('삭제에 실패했습니다.');
                    }
                }
            });
        }
    });
});
</script>
</head>
<body>
<div class="container">
<table class="table table-bordered table-responsive">
  <tr align="center" >
    <td>
        <a href=<?php echo 'calendar.php?year='.$pre_year.'&month='.$month . '&day=1'; ?>>◀◀</a>
    </td>
    <td>
        <a href=<?php echo 'calendar.php?year='.$prevyear.'&month='.$prevmonth . '&day=1'; ?>>◀</a>
    </td>
    <td height="50" bgcolor="#FFFFFF" colspan="3">
        <a href=<?php echo 'calendar.php?year=' . $thisyear . '&month=' . $thismonth . '&day=1'; ?>>
        <?php echo "&nbsp;&nbsp;" . $year . '년 ' . $month . '월 ' . "&nbsp;&nbsp;"; ?></a>
    </td>
    <td>
        <a href=<?php echo 'calendar.php?year='.$nextyear.'&month='.$nextmonth.'&day=1'; ?>>▶</a>
    </td>
    <td>
        <a href=<?php echo 'calendar.php?year='.$next_year.'&month='.$month.'&day=1'; ?>>▶▶</a>
    </td>
  </tr>
  <tr class="info">
    <th style="width:14%;text-align:center;">일</td>
    <th style="width:14%;text-align:center;">월</th>
    <th style="width:14%;text-align:center;">화</th>
    <th style="width:14%;text-align:center;">수</th>
    <th style="width:14%;text-align:center;">목</th>
    <th style="width:14%;text-align:center;">금</th>
    <th style="width:14%;text-align:center;">토</th>
  </tr>
  <tr height=<?php echo $cellh;?>>

<?php
    $date = 1;
    $offset = 0;
    $ck_row = 0;
    //프레임 사이즈 조절을 위한 체크인자
    $R = array();

    while ($date <= $last_day) {
        $mday = $date;

        if ($date == '1') {
            // 시작 요일 구하기 : date("w", strtotime($year."-".$month."-01"));
            $offset = date('w', mktime(0, 0, 0, $month, $date, $year)); // 0: 일요일, 6: 토요일
            SkipOffset($offset, mktime(0, 0, 0, $month, $date, $year));
        }
        if ($offset == 0)
            $style = "holy"; // 일요일 빨간색으로 표기
        else if($offset == 6)
            $style = "holy"; // 토요일 빨간색 또는 파란색
        else
            $style = "black";

        // 법정 공휴일
        for ($i = 0; $i < count($Holidays); $i++) {
            if ($Holidays[$i][0] == "$month-$date") {
                $style = "holy";
                $mday = "$date";
                $holidata = $Holidays[$i][1];
                break;
            }
        }

        // 음력 일자 및 간지 데이터
        for ($i = 0; $i < count($lunarData); $i++) {
            if ($lunarData[$i][0] == "$month-$date") {
                if($lunarData[$i][4] == 1){ // 윤달이면
                    $lunarday = '(閏)'.$lunarData[$i][2];
                } else {
                    $lunarday = $lunarData[$i][2];
                }
                $gaingi_text = $lunarData[$i][1];
            }
        }

        // 기념일 : 결혼, 생일, 제사, 기타 등
        for ($i = 0; $i < count($memorialData); $i++) {
            if ($memorialData[$i][0] == "$month-$date") {
                $memorialdata = $memorialData[$i][2];
                break;
            }
        }

        // 사용자 일정 데이터
        $dType1 = array();
        for ($i = 0; $i < count($schedule); $i++) {
            if ($schedule[$i][0] == "$month-$date") {
                $dType1[] = array(0=>$schedule[$i][2],1=>$schedule[$i][3]);
            }
        }
      
        if ($date == $today && $year == $thisyear && $month == $thismonth) { // 오늘 날짜
            echo "<td valign=top bgcolor=#99FFFF class='calcell' id='".$year."-".$month."-".$mday."'>";
        } else {
            echo "<td valign=top class='calcell' id='".$year."-".$month."-".$mday."'>";
        }
            CalendarPrint($style,$mday,$lunarday,$gaingi_text,$holidata,$memorialdata,$dType1);
            echo "</td>\n";

        // 출력후 값 초기화
        $holidata = "";
        $memorialdata ="";

        $date++; // 날짜 증가
        $offset++;
        if ($offset == 7) {
            echo "</tr>";
            if ($date <= $last_day) {
                echo "<tr height=$cellh>";
                $ck_row++;
            }
            $offset = 0;
        }

    }// end of while

    if ($offset != 0) {
        SkipOffset((7 - $offset), '', mktime(0, 0, 0, $month + 1, 1, $year));
        echo "</tr>\n";
    }
    echo("</td>\n");

    function ErrorMsg($msg) {
        echo " <script>window.alert('$msg');history.go(-1);</script>";
        exit;
    }

    function CalendarPrint($style,$mday,$lunarday,$gaingi,$holidata='',$memorialdata='',$dType1=''){
        echo "<font class=".$style.">$mday</font><br/>";
        echo "<font class=lunar>$lunarday</font><br/>";
        echo "<font class=gangi>$gaingi</font><br/>";
        if(strlen($holidata)>0) echo "<font class=red>$holidata</font><br/>";
        if(strlen($memorialdata)>0) echo "<font class=sblue>$memorialdata</font><br/>";
        if(count($dType1)>0) { // 배열 출력
            for ($i = 0; $i < count($dType1); $i++) {
                echo "<font class=num uid=".$dType1[$i][1].">".$dType1[$i][0]."</font><br/>";
            }
        }
    }

    function SkipOffset($no, $sdate = '', $edate = '') {
        for ($i = 1; $i <= $no; $i++) {
            $ck = $no - $i + 1;
            if ($sdate)
                $num = date('n.j', $sdate - (3600 * 24) * $ck);
            if ($edate)
                $num = date('n.j', $edate + (3600 * 24) * ($i - 1));

            echo "<td valign=top><font class=gray>$num</font></td>";
        }
    }

    function Lun2SolDate($date){
        global $dbconn;
        $sql = "SELECT solar_date FROM lunar_data where lunar_date='".$date."'";
        $result = mysqli_query($dbconn, $sql);
        $R = mysqli_fetch_array($result);
        return $R[0];
    }

    function isWeekend($date){
        // 앙력 날짜의 요일을 리턴
        // 일요일 0 토요일 6
        return date("w", strtotime($date));
    }

?>
    </tr>
</table>
</div>
</body>
</html>



코드 구현 파일

calendar.zip

lunar_data.zip


참조한 사이트

- 참조한 URL을 찾게되면 추가할 예정



본 자료가 도움되었다면 000 해주세요. 좋은 글 작성에 큰 힘이 됩니다.


'Web 프로그램 > PHP 응용 및 활용' 카테고리의 다른 글

PHP 날짜와 시간 차이  (0) 2019.03.26
jQuery Select Box 선택값 제어  (0) 2019.01.05
법정공휴일  (0) 2018.11.03
PHP 달력 만들기 소스  (0) 2018.10.30
날짜 선택  (0) 2018.10.26
블로그 이미지

Link2Me

,
728x90

법정공휴일은 '관공서의 공휴일에 관한 규정'(대통령령)에 의해 공휴일이 된 날을 말한다.
법령에 따르면 법정공휴일은 일요일, 국경일, 1월 1일, 음력 1월 1일(설날)과 전후 이틀, 석가탄신일(음력 4월 8일),
어린이날(5월 5일), 현충일(6월 6일), 음력 8월 15일(추석)과 전후 이틀, 성탄절(12월 25일),
보궐선거를 제외한 각종 선거투표일 등 정부에서 수시로 정하는 날 등이다.
국경일은 ‘국경일에 관한 법률’에 의한 3ㆍ1절, 제헌절, 광복절, 개천절, 한글날을 말한다.

대체공휴일제의 도입 (안 제3조)
– 설날, 추석 연휴가 다른 공휴일과 겹치는 경우 그 날 다음의 첫 번째 비공휴일을 공휴일로 함
– 어린이날이 토요일 또는 다른 공휴일과 겹치는 경우 그 날 다음의 첫 번째 비공휴일을 공휴일로 함
(어린이날 외의 토요일은 대체공휴일에 포함되지 않는다)


음력기준으로 법정공휴일인 설날, 추석과 어린이날은 대체 공휴일을 고려하여 코딩해야 한다.



블로그 이미지

Link2Me

,
728x90

PHP로 만들어진 달력을 활용해보고자 많은 자료를 검색해봤지만 결국에는 기본적인 개념이 충실한 PHP 달력 만들기 소스코드를 좀 더 정교하게 가다듬어 정리를 하는 것이 답인 거 같다.


달력은 일정관리, 음력일정, 음력 기념일 등을 관리할 수 있어야 하므로 외국 소스를 활용하는 것은 큰 도움이 안되더라.


bootstrap 기반으로 포팅하고 약간 수정해서 정리한 걸 적어둔다.


양력기반으로 일정추가가 잘된 소스는 https://phppot.com/php/php-calendar-event-management-using-fullcalendar-javascript-library/ 를 참조하면 도움이 될 것이다.

그리고 https://www.phpzag.com/create-event-calendar-with-jquery-php-and-mysql/ 자료도 도움이 된다.



음력 기념일, 일정 등이 포함된 버전으로 만들기 위해서는 좀 더 정리가 필요하다.

음력 일정까지 정리되는 달력은 다른 소스를 가지고 수정 작업을 하고 있는 중이다.


<?php
//---- 오늘 날짜
$thisyear = date('Y'); // 4자리 연도
$thismonth = date('n'); // 0을 포함하지 않는 월
$today = date('j'); // 0을 포함하지 않는 일

//------ $year, $month 값이 없으면 현재 날짜
$year = isset($_GET['year']) ? $_GET['year'] : $thisyear;
$month = isset($_GET['month']) ? $_GET['month'] : $thismonth;
$day = isset($_GET['day']) ? $_GET['day'] : $today;

$prev_month = $month - 1;
$next_month = $month + 1;
$prev_year = $next_year = $year;
if ($month == 1) {
    $prev_month = 12;
    $prev_year = $year - 1;
} else if ($month == 12) {
    $next_month = 1;
    $next_year = $year + 1;
}
$preyear = $year - 1;
$nextyear = $year + 1;

$predate = date("Y-m-d", mktime(0, 0, 0, $month - 1, 1, $year));
$nextdate = date("Y-m-d", mktime(0, 0, 0, $month + 1, 1, $year));

// 1. 총일수 구하기
$max_day = date('t', mktime(0, 0, 0, $month, 1, $year)); // 해당월의 마지막 날짜
//echo '총요일수'.$max_day.'<br />';

// 2. 시작요일 구하기
$start_week = date("w", mktime(0, 0, 0, $month, 1, $year)); // 일요일 0, 토요일 6

// 3. 총 몇 주인지 구하기
$total_week = ceil(($max_day + $start_week) / 7);

// 4. 마지막 요일 구하기
$last_week = date('w', mktime(0, 0, 0, $month, $max_day, $year));
?>

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Bootstrap Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
  <style>
    font.holy {font-family: tahoma;font-size: 20px;color: #FF6C21;}
    font.blue {font-family: tahoma;font-size: 20px;color: #0000FF;}
    font.black {font-family: tahoma;font-size: 20px;color: #000000;}
  </style>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
  <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<table class="table table-bordered table-responsive">
  <tr align="center" >
    <td>
        <a href=<?php echo 'index.php?year='.$preyear.'&month='.$month . '&day=1'; ?>>◀◀</a>
    </td>
    <td>
        <a href=<?php echo 'index.php?year='.$prev_year.'&month='.$prev_month . '&day=1'; ?>>◀</a>
    </td>
    <td height="50" bgcolor="#FFFFFF" colspan="3">
        <a href=<?php echo 'index.php?year=' . $thisyear . '&month=' . $thismonth . '&day=1'; ?>>
        <?php echo "&nbsp;&nbsp;" . $year . '년 ' . $month . '월 ' . "&nbsp;&nbsp;"; ?></a>
    </td>
    <td>
        <a href=<?php echo 'index.php?year='.$next_year.'&month='.$next_month.'&day=1'; ?>>▶</a>
    </td>
    <td>
        <a href=<?php echo 'index.php?year='.$nextyear.'&month='.$month.'&day=1'; ?>>▶▶</a>
    </td>
  </tr>
  <tr class="info">
    <th hight="30">일</td>
    <th>월</th>
    <th>화</th>
    <th>수</th>
    <th>목</th>
    <th>금</th>
    <th>토</th>
  </tr>

  <?php
    // 5. 화면에 표시할 화면의 초기값을 1로 설정
    $day=1;

    // 6. 총 주 수에 맞춰서 세로줄 만들기
    for($i=1; $i <= $total_week; $i++){?>
  <tr>
    <?php
    // 7. 총 가로칸 만들기
    for ($j = 0; $j < 7; $j++) {
        // 8. 첫번째 주이고 시작요일보다 $j가 작거나 마지막주이고 $j가 마지막 요일보다 크면 표시하지 않음
        echo '<td height="50" valign="top">';
        if (!(($i == 1 && $j < $start_week) || ($i == $total_week && $j > $last_week))) {

            if ($j == 0) {
                // 9. $j가 0이면 일요일이므로 빨간색
                $style = "holy";
            } else if ($j == 6) {
                // 10. $j가 0이면 토요일이므로 파란색
                $style = "blue";
            } else {
                // 11. 그외는 평일이므로 검정색
                $style = "black";
            }

            // 12. 오늘 날짜면 굵은 글씨
            if ($year == $thisyear && $month == $thismonth && $day == date("j")) {
                // 13. 날짜 출력
                echo '<font class='.$style.'>';
                echo $day;
                echo '</font>';
            } else {
                echo '<font class='.$style.'>';
                echo $day;
                echo '</font>';
            }
            // 14. 날짜 증가
            $day++;
        }
        echo '</td>';
    }
 ?>
  </tr>
  <?php } ?>
</table>
</div>

</body>
</html>


음력을 지원하는 달력의 모습


음력 달력에 대한 소스 코드 설명은 http://link2me.tistory.com/1545 를 참조하면 된다.

'Web 프로그램 > PHP 응용 및 활용' 카테고리의 다른 글

PHP 달력 소스 코드 (음력, 간지, 기념일, 일정등록)  (9) 2018.11.05
법정공휴일  (0) 2018.11.03
날짜 선택  (0) 2018.10.26
접속단말 및 IP주소  (0) 2018.06.11
PHP 글자수 줄임 표시  (0) 2018.06.09
블로그 이미지

Link2Me

,
728x90

PHP에서 날짜 선택을 깔끔하게 하는 코드를 적어둔다.


<?php
//---- 오늘 날짜
$thisyear = date("Y");
$thismonth = date("m");
$today = date("d"); // 1, 2, 3, ..., 31

//------ $year, $month 값이 없으면 현재 날짜
$year = isset($_GET['year']) ? $_GET['year'] : $thisyear;
$month = isset($_GET['month']) ? $_GET['month'] : $thismonth;
$day = isset($_GET['day']) ? $_GET['day'] : $today;

$start_date = date("Y", mktime(0, 0, 0, date("m"), date("d"), date("Y") - 1));
$end_date = date("Y", mktime(0, 0, 0, date("m"), date("d"), date("Y") + 3));
?>


<TR>
    <TD >시작날짜</TD>
    <TD colspan="2" rowspan="1">
    <select name="start_date1">
    <?php for($i=$start_date;$i<$end_date;$i++):?><option value="<?php echo $i?>"<?php if($year==$i):?> selected="selected"<?php endif?>><?php echo $i?>년</option><?php endfor?>
    </select>
    <select name="start_date2" >
    <?php for($i=1;$i<13;$i++):?><option value="<?php echo sprintf('%02d',$i)?>"<?php if($month==$i):?> selected="selected"<?php endif?>><?php echo sprintf('%02d',$i)?>월</option><?php endfor?>
    </select>
    <select name="start_date3" >
    <?php for($i=1;$i<32;$i++):?><option value="<?php echo sprintf('%02d',$i)?>"<?php if($day==$i):?> selected="selected"<?php endif?>><?php echo sprintf('%02d',$i)?>일</option><?php endfor?>
    </select>

    </TD>
</TR>

'Web 프로그램 > PHP 응용 및 활용' 카테고리의 다른 글

법정공휴일  (0) 2018.11.03
PHP 달력 만들기 소스  (0) 2018.10.30
접속단말 및 IP주소  (0) 2018.06.11
PHP 글자수 줄임 표시  (0) 2018.06.09
PHP to JSP  (0) 2018.04.28
블로그 이미지

Link2Me

,
728x90

접속한 단말을 구분하고 IP주소를 확인하는 코드다.

echo $_SERVER['HTTP_USER_AGENT'].'<br />';

이 한줄로 접속한 단말의 정보를 알 수 있다. 직접 확인해보라.

스마트폰 단말에서 접속이 글자가 너무 작아지는 걸 방지하기 위해서 헤더정보를 포함했다.


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex,nofollow"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<?php
echo $_SERVER['HTTP_USER_AGENT'].'<br />';
if(strpos($_SERVER['HTTP_USER_AGENT'],"iPhone")>0){
    echo '<br />'."접속단말 : 아이폰";
} else if(strpos($_SERVER['HTTP_USER_AGENT'],"Android")>0) {
    echo '<br />'."접속단말 : 안드로이드";
}

$ipAddress = getClientIP();
echo '<br />';
echo '<br />'.$ipAddress;

    function getClientIP() {
        if (isset($_SERVER)) {
            if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]))
                return $_SERVER["HTTP_X_FORWARDED_FOR"];

            if (isset($_SERVER["HTTP_CLIENT_IP"]))
                return $_SERVER["HTTP_CLIENT_IP"];

            return $_SERVER["REMOTE_ADDR"];
        }

        if (getenv('HTTP_X_FORWARDED_FOR'))
            return getenv('HTTP_X_FORWARDED_FOR');

        if (getenv('HTTP_CLIENT_IP'))
            return getenv('HTTP_CLIENT_IP');

        return getenv('REMOTE_ADDR');
    }

?>
</body>
</html>


접속단말이 Android 인 경우 Android 버전 정보를 알고 싶다면 어떻게 하면 될까?

if(strstr($_SERVER['HTTP_USER_AGENT'], 'Android')){
    preg_match('/Android (\d+(?:\.\d+)+)[;)]/', $_SERVER['HTTP_USER_AGENT'], $matches);
    echo $matches[1].'<br />';
}
로 하면 버전 정보를 추출할 수 있다.


'Web 프로그램 > PHP 응용 및 활용' 카테고리의 다른 글

PHP 달력 만들기 소스  (0) 2018.10.30
날짜 선택  (0) 2018.10.26
PHP 글자수 줄임 표시  (0) 2018.06.09
PHP to JSP  (0) 2018.04.28
PHP Form 다중 체크박스 값 전달 및 POST  (0) 2018.04.02
블로그 이미지

Link2Me

,