728x90

통상적으로 쉽고 간단하게 하기 위해 positional placeholders 를 이용한 방법을 사용한다.

$sql = "UPDATE users SET name=?, surname=?, sex=? WHERE id=?";
$params = array($name, $surname, $sex, $id);
$stmt= $pdo->prepare($sql);
$stmt->execute($params);

 

UPDATE query with named placeholders

$data = array('name' => $name,'surname' => $surname,'sex' => $sex,'id' => $id);
$sql = "UPDATE users SET name=:name, surname=:surname, sex=:sex WHERE id=:id";
$stmt= $pdo->prepare($sql);
$stmt->execute($data);

 

 

비밀번호 변경하는 간단 예제이다.

<?php
$idx = 15;
$passwd = "new1234!"// 비밀번호
 
require_once 'path.php';// root 폴더를 기준으로 상대적인 경로 자동 구하기
require_once $g['path_config'].'config.php';
require_once $g['path_class'].'dbconnect.php';
require_once $g['path_class'].'loginClass.php';
$d = new LoginClass;
 
$hash = $d->hashSSHA($passwd);
$encrypted_pw = $hash['encrypted']; // encrypted password
$salt = $hash['salt']; // salt
 
$QKEY = "passwd=?,salt=?";
$params = array($encrypted_pw,$salt,$idx);
$d->getDbUpdate('members',$QKEY,$params,'idx=?');
 
echo '변경완료'
 
?>
 
<?php
class LoginClass {
    // 패스워드 해쉬함수 : 20자 SALT + SHA256 암호화
    function hashSSHA($password) {
        $salt = sha1(rand());
        $salt = substr($salt020);
        $encrypted = base64_encode(hash('sha256'$salt.$passwordtrue) . $salt);
        $hash = array("salt" => $salt"encrypted" => $encrypted);
        return $hash;
    }
 
    function getDbUpdate($table$set$params$where) {
        $sql = "update " . $table . " set " . $set . ($where ? ' where ' . $where : '');
        try {
            $this->db->beginTransaction();
            $stmt = $this->db->prepare($sql);
            $status = $stmt->execute($params);
            $this->db->commit();
            return 1;
        } catch (PDOException $pex) {
            $this->db->rollBack();
            echo "에러 : " . $pex->getMessage();
            return -1
        }
    }
}
?>
 

 

 

기본적인 Insert, Update, Delete, 검색에 대한 샘플이다.

 
<?php
    require_once('dbCon.php');
    $pdo = dbConnect();
    
    //입력처리
    if(isset($_POST['action']) && $_POST['action'== 'insert'){
        try{
            $pdo->beginTransaction();
            $sql = "INSERT INTO member (name, age, email) VALUES(:name, :age, :email)";
            $stmt = $pdo->prepare($sql);
            $stmt->bindValue(':name',$_POST['name'],PDO::PARAM_STR);
            $stmt->bindValue(':age',$_POST['age'],PDO::PARAM_INT);
            $stmt->bindValue(':email'$_POST['email'], PDO::PARAM_STR);
            $stmt->execute();
            $pdo->commit();
            print "데이터 입력 처리 하였습니다.<br/><br/>";
        } catch (PDOException $pex) {
            $pdo->rollBack();
            print "에러 : ".$pex->getMessage();
        }
    }
    
    //수정처리
    if(isset($_POST['action']) && $_POST['action']=='update'){
        //세션 변수를 이용하여 id값을 획득한다.
        $id = $_SESSION['id'];
        try{
            $pdo->beginTransaction();
            $sql = "UPDATE member SET name = :name, age=:age, email = :email WHERE id = :id";
            $stmt = $pdo->prepare($sql);
            $stmt->bindValue(':name'$_POST['name'], PDO::PARAM_STR);
            $stmt->bindValue(':age'$_POST['age'],PDO::PARAM_INT);
            $stmt->bindValue(':email'$_POST['email'], PDO::PARAM_STR);
            $stmt->bindValue(':id',$id,PDO::PARAM_INT);
            
            $stmt->execute();
            $pdo->commit();
            print "데이터를 수정 처리하였습니다.<br/>";
        } catch (PDOException $pex) {
            $pdo->rollBack();
            print "에러 : ".$pex->getMessage();
        }
        // 사용한 세션 변수를 삭제한다.
        unset($_SESSION['id']);
    }
    
    //삭제 처리
    if(isset($_GET['action']) && $_GET['action']=='delete' && $_GET['id'> 0){
        try{
            $pdo->beginTransaction();
            $id = $_GET['id'];
            $sql = "DELETE FROM member WHERE id = :id";
            $stmt = $pdo->prepare($sql);
            $stmt->bindValue(':id'$id, PDO::PARAM_INT);
            $stmt->execute();
            $pdo->commit();
            print "데이터를 삭제 처리하였습니다...<br/><br/>";
        } catch (PDOException $pex) {
            $pdo->rollBack();
            print "에러 : ".$pex->getMessage();
        }
    }
    
    //검색 처리
    try{
        if(isset($_POST['searchWord']) && $_POST['searchWord'!= ""){
            $searchWord = '%'.$_POST['searchWord'].'%';
            $sql = "SELECT * FROM member WHERE name LIKE :name";
            $stmt=$pdo->prepare($sql);
            $stmt->bindValue(':name',$searchWord,PDO::PARAM_STR);
 
            $stmt->execute();
        }else{
            //현재 DB에 있는 회원리스트를 모두 출력한다.
            $sql = "SELECT * FROM member";
            $stmt = $pdo->query($sql);
        }
        
        $cnt = $stmt->rowCount();
    }catch(PDOException $pex){
        print "에러 : ".$pex->getMessage();
    }    
    if($cnt < 1){
        print "검색 결과가 없습니다!!<br/>";
    }
?>

 

728x90
블로그 이미지

Link2Me

,
728x90

코드이그나이터 .htaccess 환경 설정 방법이다.



CodeIgniter 가 설치된 web root 폴더에서 .htaccess 파일을 생성한다.

vi .htaccess

RewriteEngine On
RewriteCond $1 !^(index\.php|assets|images|js|css|uploads|favicon.png)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]


:wq

로 저장하고 나온다.


Apache httpd.conf 파일에서


<Directory "/home/httpd/codeig/www/htdocs">
    AllowOverride all
    Require all granted
</Directory>

로 변경해준다.


https://codeig.abc.com/index.php/welcome

로 해서 동작되던 것을


https://codeig.abc.com/welcome

로 index.php 을 없애도 동작되도록 한다.


htdocs/application/config 폴더에서 config.php 파일 수정사항



728x90
블로그 이미지

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 자료를 가져올 수 있다.

앱 출력 결과




728x90
블로그 이미지

Link2Me

,
728x90

테이블을 JQuery 로 다루는 걸 간략하게 작성해둔다.

보통은 row 단위로 테이블의 마우스 포인트를 처리하고, row 의 값만 추출한다.

만약, 특정한 셀을 눌렀을 때의 값을 추출하거나, 함수 처리를 하고 싶을 때가 있다.

이때에는 기준점이 td 이므로 td 에 클래스명을 부여시 서로 다르게 부여한다.

 

 

위와 같은 테이블의 PHP 소스코드가 아래와 같다고 가정하자.

 

<tr id="<?php echo $R['uid']; ?>">
    <td class="BoardView"><?php echo $no;?></td>
    <td class="BoardView"><?php echo $R['subject'];?></td>
    <td class="BoardView"><?php echo $R['writer'];?></td>
    <td class="Excelpdf"><?php echo $R['regdate'];?></td>
    <td class="BoardView"><?php echo $R['hit'];?></td>
</tr>

 

 

 

관련 jQuery 코드가 아래와 같이 처리한다.

테이블에서 계속 변경되는 테이블의 row 는 클래스로 부여하고, 현재 셀은 $(this) 이고, 상위의 값은 $(this).parent().attr('id') 로 부여한 요소값을 추출한다.

인접한 셀의 값을 가져오기 위해서 $(this).parent().find("td:eq(3)").text() 로 처리한다.

 

$('.BoardView').click(function() {
    var idx = $(this).parent().attr('id');
    var date = $(this).parent().find("td:eq(3)").text();
    uri = "excelpdf.php?do="+idx+"&date="+date;
    window.location.href = uri;
});

 

 

parents() 메소드 : 자신부터 document root 까지 검색을 하기 때문에 검색 결과가 1개 이상일 수 있다는 점
  문서의 root 요소부터 DOM Tree를 탐색하여 각 부모요소들로 임시 집합을 구성하고
  제공된 선택자에 의해 임시 집합에서 추출

closest() 메소드 : 선택된 요소의 최초의 부모 요소를 얻을 수 있다.
  현 시점의 요소에서 시작하여 DOM 트리의 마지막 부분까지 조회한다.
  없거나 하나의 요소를 포함한 jQuery 객체를 반환
  자기 자신부터 찾기 시작하여 부모 요소 탐색을 하다가 해당 아이템에서 탐색을 멈춤

 

var age = $(this).find('[name=age]').val();
// name으로 접근시 $("tag_name[name=name]") 
$("input[name=search_value]")

아래 3개는 모두 동일한 결과를 보여준다.

var idx = $('#FloorForm').find('[name=bidx]').val();
var idx = $('input[name=bidx]',document.FloorForm).val();
var idx = $(document.FloorForm).find('[name=bidx]').val();

<div class='form-group'>
	<form name="FloorForm" id="FloorForm" class="form-inline" action="<?php echo $link_url;?>">
		<input type="hidden" name="bidx" value="<?php echo $bidx;?>" />

		<div class="input-group mb-3">
			<select name="where" class="browser-default custom-select">
				<option value="floor">층</option>
				<option value="all">전체</option>
			</select>
		</div>
		<div class="input-group mb-3">
		  <input type="text" name="keyword" class="form-control" id="FloorSearchKeyword">
		  <div class="input-group-append">
			<button class="btn btn-outline-default" type="button" id="FloorSearch">검색</button>
			<button class="btn btn-outline-default" type="button" id="FloorHome">Home</button>
		  </div>
		</div>
	</form>
</div>

$('#FloorSearchKeyword').on('keypress', function(event){
	var agent = navigator.userAgent.toLowerCase();
	var keycode = (event.keyCode ? event.keyCode : event.which);
	if(keycode == 13){ // 엔터키가 입력될 때까지는 어떤 것도 하지 않는다.
		event.preventDefault(); // 엔터키가 입력되면 현재 이벤트의 기본 동작을 중단한다.
		//event.stopPropagation(); // 현재 이벤트가 상위로 전파되지 않도록 중단한다.
		var where = $('#FloorForm').find('[name=where]').val();
		var keyword = $('#FloorForm').find('[name=keyword]').val();
		FloorSearch(where,keyword);
	}
});

$('#FloorSearch').click(function(e){
	var where = $('#FloorForm').find('[name=where]').val();
	var keyword = $('#FloorForm').find('[name=keyword]').val();
	FloorSearch(where,keyword);
});

function FloorSearch(where,keyword){
	var uri = $('#urlPath').attr('url-path');
	var idx = $('#FloorForm').find('[name=bidx]').val();

	keyword= keyword.replace(/\s/g,""); // 문자열내의 모든 공백 제거
	var regExp = /[\{\}\[\]\/?.,;:|\)*~`!^\-_+<>@\#$%&\\\=\(\'\"]/gi; // 특수문자 제거
	keyword = keyword.replace(regExp,"");
	if(keyword.length == 0){
		alert('검색어를 입력하세요');
		$('input[name=keyword]').focus();
		return false;
	}
	MemberListTable(where,keyword,1,uri,idx);
}

라디오버튼의 value 가져오기
$("#FloorForm").find("[name=chk_confirm]:checked").val();

 

select박스
* 선택된값 가져오기 : $("#FloorForm>[name=cate]>option:selected").val() );
* 값 선택하기 :  $("#FloorForm").find("[name=cate]>option@[value=BLOG]").attr('selected','true');

 

<form id="frm" name="frm">
   <input type="text" name="price" value="100" />
   <input type="text" name="price" value="200" />
   <input type="text" name="price" value="300" />
   <input type="text" name="price" value="400" />
</form>

var Price = $("#frm input[name='price']").eq(2).val();
728x90
블로그 이미지

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를 이용한 인증 처리 로직 수정 보완

728x90
블로그 이미지

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

 

 

728x90
블로그 이미지

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);
}

?>
 


728x90
블로그 이미지

Link2Me

,
728x90

MDB 템플릿을 사용하다가 정보 찾는데 걸리는 시간을 절약하기 위해 적어둔다.

bootstrap4 기반으로 만들어진 템플릿이라 bootstrap4 용일 수도 있다.

 

글자 굵은 글씨

<b class="font-weight-bold">'.$R['jiAddress'].' '.$R['aDong'].$bldNM).'</b>

 

글자 왼쪽 정렬

<td class="text-left"><?php echo $R['content'];?></td>

 

빨간 글씨

<td class="text-danger"><?php echo $R['content'];?></td>

 

<?php if($mtype==3):?><td><?php echo $R['d_regis'];?></td><?php endif;?>

 

<tr>
    <th class="text-left" style='width:80pt'>인입구배선</th>
    <td class="text-left" style='width:85%'>
        <div class="form-check form-check-inline">
          <input type="radio" class="form-check-input" name="wireEnt" id="wireEnt1" value="1" <?php if(!isset($C['wireEnt'])):?>checked<?php elseif($C['wireEnt'] == "1"):?>checked<?php else:?><?php endif?>>
          <label class="form-check-label" for="wireEnt1">O</label>
        </div>
        <div class="form-check form-check-inline">
          <input type="radio" class="form-check-input" name="wireEnt" id="wireEnt2" value="2" <?php if(!isset($C['wireEnt'])):?><?php elseif($C['wireEnt'] == "2"):?>checked<?php else:?><?php endif?>>
          <label class="form-check-label" for="wireEnt2">X</label>
        </div>
        <div class="form-check form-check-inline">
          <input type="radio" class="form-check-input" name="wireEnt" id="wireEnt3" value="3" <?php if(!isset($C['wireEnt'])):?><?php elseif($C['wireEnt'] == "3"):?>checked<?php else:?><?php endif?>>
          <label class="form-check-label" for="wireEnt3">△</label>
        </div>
        <div class="form-check form-check-inline">
          <input type="radio" class="form-check-input" name="wireEnt" id="wireEnt4" value="4" <?php if(!isset($C['wireEnt'])):?><?php elseif($C['wireEnt'] == "4"):?>checked<?php else:?><?php endif?>>
          <label class="form-check-label" for="wireEnt4">해당없음</label>
        </div>
    </td>
</tr>

 

 

 

 

 

 

728x90
블로그 이미지

Link2Me

,
728x90

오랫만에 PHP PDO 코드를 만들다보니 에러가 나와 어디를 수정해야 할지 헷갈린다.

PHP PDO로 구현한 코드에서 500 Error 메시지의 원인을 찾아내고 해결한 후 적어둔다.

 

Ajax 는 PHP B 파일에서 발생하는 에러를 파악하기 어려울 수 있다.

이럴경우에는 절분시험을 하듯이 B 파일에서만 별도로 데이터가 넘어왔다는 가정하에

아래 두줄 추가하고 alert(msg) 해서 메시지 내용을 살펴보고 코드의 문제점을 발견하고 찾아서 해결하면 된다.

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

 

if (!isset($_POST['uid'])) {
    echo "-9";
    exit ;
}

 

에러를 무조건 출력시켜서 메시지를 분석해야 잘못된 부분을 찾아내기 쉽다.

 

 

 

 

 

 

 

코딩할 당시에는 알지만 오래되면 기억이 나지 않기 때문에 내가 나중에 보려고 정리하는 것이므로 댓글 태클은 정중히 사양.......

728x90
블로그 이미지

Link2Me

,
728x90

코드를 수정하다보니 SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data 이런 에러메시지가 나온다.


아무리 찾아도 문제가 없는데 말이다.

변수명을 변경했는데 캐싱된 데이터가 계속 잘못된 정보를 서버로 보내면서 벌어진 현상이다.


크롬 브라우저에서 Disable cache 를 하지 않아서 생긴 현상이다. 윽ㅠㅠㅠㅠㅠㅠ

728x90
블로그 이미지

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 입력체크를 하면 된다.

728x90
블로그 이미지

Link2Me

,
728x90

mysql_query() expects parameter 2 to be resource, boolean given in


DB 데이터 업데이트 작업을 하는데 MySQLi 가 아닌 MySQL 로 하다보니 위와 같은 메시지가 나온다.


이런 메시지가 나오는 것은 MySQL 연결 정보가 제대로 연결되지 않아서다.


$db= mysql_connect("localhost","root","user_password");
mysql_select_db("dbname", $db);

728x90
블로그 이미지

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);
}
 
?> 

 

728x90
블로그 이미지

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);
}

?>


728x90
블로그 이미지

Link2Me

,
728x90

Class 를 만들어서 사용하면 여러모로 편하고 좋다.

본 Class 함수는 KIMSQ RB에서 사용하는 함수를 Class화해서 사용하고 있다.

그만큼 코딩을 편하면서도 깔끔하게 이해하게 해준다.

MDB(Meterial Design for Bootstrap) 든 일반 게시판이든 사용하는데는 다 사용 가능하다. MDB는 템플릿으로 깔끔하게 보여주기 때문에 디자인에 대한 고민을 덜어준다.


<?php

// 파일명 : dbDataClass.php

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

    // DB Query Cutom 함수
    function getDbData($table,$where,$column) {
        global $db;
        $sql ='select '.$column.' from '.$table.($where?' where '.$this->getSqlFilter($where):'');
        //echo $sql; // 디버깅 목적으로 필요할 때가 있다.
        $result = mysqli_query($db,$sql);
        $row = mysqli_fetch_array($result);
        return $row;
    }

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

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

    }

    //DB데이터 레코드 총 개수
    function getDbRows($table,$where){
        global $db;
        $sql = 'select count(*) from '.$table.($where?' where '.$this->getSqlFilter($where):'');
        $result = mysqli_query($db,$sql);
        if($result){
            $rows = mysqli_fetch_row($result);
            return $rows[0] ? $rows[0] : 0;
        } else {
            echo "Failed to connect to MySQL: " . mysqli_connect_error($db);
            exit(); // **this is missing**
        }
    }

    //DB삽입
    function getDbInsert($table,$key,$val){
        global $db;
        $sql ="insert into ".$table." (".$key.")values(".$val.")";
        //echo $sql;
        if(mysqli_query($db,$sql)){
            return 1;
        } else {
            return 0;
        }
    }

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

    //DB삭제
    function getDbDelete($table,$where)    {
        global $db;
        $sql ="delete from ".$table.($where?' where '.$this->getSqlFilter($where):'');
        if(mysqli_query($db,$sql)){
            return 1;
        } else {
            return 0;
        }
    }

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

    // 암호화
    function AES_Encode($plain_text){
        global $key;
        return base64_encode(openssl_encrypt($plain_text, "aes-256-cbc", $key, true, str_repeat(chr(0), 16)));
    }

    // 복호화
    function AES_Decode($base64_text){
        global $key;
        return openssl_decrypt(base64_decode($base64_text), "aes-256-cbc", $key, true, str_repeat(chr(0), 16));
    }

}//end dbClass

?>


728x90
블로그 이미지

Link2Me

,
728x90

Eclipse 에서 PHP 개발 테스트를 하기 위해서 PHP Development Tools 를 설치했다.

구글 검색해서 4.1 버전 이미지를 보면서 설치를 했다.




검색어 php 를 입력하고 Go를 누르면 아래와 같이 PHP Development Tools 최신 버전이 나온다.

현재 그림은 이미 Installed 된 것이라 이렇게 보이지만 설치하지 않았으면 Install 이라고 나온다.


이후에 나온 그림은 캡처를 하지 않아서 게재할 수가 없다.

다른 블로그에 나온 이미지를 참조해도 되고 순서대로 진행하면 된다.

설치를 하고 나면 프로그램 재실행을 해준다.


이후에 PHP 파일에서 APM 과 연결하여 PHP 파일을 직접 실행하는 방법이다.


먼저 Preferences 를 눌러서 아래 화면이 나오면 PHP 항목을 선택한 다음에

Servers 를 선택하고 Default PHP Web Server 경로를 수정해줘야 한다.

APM(Apache + PHP + MySQL) 이 설치된 Autoset9 의 설치경로의 web root 경로(httpd.conf 에서 설정한 경로)를 지정해준다.



이제 PHP Project 를 생성할 때 아래와 같이 1번 항목이 보이게 된다.

2번 항목에는 이미 만들어놓은 PHP 경로를 적어주면 된다.


실제 파일에서 아래와 같이 한번만 실행하면 다음부터는 1번만 누르면 마지막 설정한 걸 실행한다.




사족을 달자면...

맥북 2010 프로에는 윈도우10 설치가 안되어 윈도우 8.1 을 설치해서 사용하고 있는데 Aptana 를 설치하면 에러가 발생하면서 설치가 안되어서 Eclipse Java 설치한 것에 PHP 모듈을 추가해 본 것이다.

여러가지 PHP 툴을 설치하지만 딱 마음에 드는게 별로 없다.

Eclipse PDT 를 사용해 보고 장점이 발견되면 추가로 적어둘려고 한다.


728x90
블로그 이미지

Link2Me

,
728x90

자바 강좌를 들으면서 실습용으로 Eclipse를 설치해서 사용중인데 기본 인코딩 모드가 UTF-8 이 아니었다.

PHP 모듈을 추가 설치하면서 PHP 파일을 읽어오는데 한글이 깨져 보여서 기본 인코딩 모드를 변경했다.



Visual Studio Code 에서 자바 실습하는 걸 해보려고 했지만 영~~ 아니다.

PHP 코드를 정렬하고자 Visual Studio Code 를 실행해서 해봤지만 확장자가 PHP 인것은 제대로 못하는 가 보다.

그래서 Eclipse 에서 PHP 모듈을 추가 설치했다.

728x90
블로그 이미지

Link2Me

,
728x90

파일 삭제 처리하는 로직 구현이다.

<?php
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'].'config.php';
require_once $g['path_config'].'dbconnect.php';
require_once $g['path_class'].'dbDataClass.php';
$d = new DBDataClass;

if(!isset($_GET['idx']) || empty($_GET['idx'])){
    $rs=0;
} else {
    // 등록자 여부 체크
    $R = $d->getUidData('bbs_data',$_GET['idx']);
    if($R['userID'] == $_SESSION['userID'] || (isset($_SESSION['authID']) && ($_SESSION['authID']==1 || $_SESSION['authID']==2))){
        // 등록자 또는 관리자(관리자, 최고관리자) 인 경우에는 삭제 가능
        $rs=$d->getDbDelete('bbs_data', 'uid='.$_GET['idx'].'');
        $d->getDbDelete('bbs_comment', 'parentid='.$_GET['idx'].''); //댓글 같이 삭제됨
    } else {
        $rs = -2;
    }
}
echo $rs;
?>


728x90
블로그 이미지

Link2Me

,
728x90

게시판 기능을 구현하고 있는데, 코딩 구현보다 Layout 기능 익히는 게 더 힘들어서 적어둔다.

기능 구현이 끝나면 수정해야 할 부분(보안 문제 고려사항)

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


error_reporting(0); 로 변경해야 한다.

 

<?php

// 파일명 : bbsView.php
error_reporting(E_ALL);
ini_set("display_errors", 1);

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'; // PC접속은 IP 접속 허용이 된 경우에만 접속 가능
}
require_once $g['path_config'].'config.php';
require_once $g['path_config'].'dbconnect.php';
require_once $g['path_class'].'dbDataClass.php';
require_once $g['path_class'].'bbsClass.php';
$c = new bbsClass();
$d = new DBDataClass();

$bid = isset($_GET['bid']) ? $_GET['bid']: '';
$curPage = isset($_GET['p']) ? $_GET['p'] : 1;

$R = $d->getDbData('bbs_data', 'uid="'.$_GET['uid'].'"', '*');
$html = ($R['html'] == 1) ? 'HTML' : 'TEXT';

 

// 쿠키를 이용한 조회수 중복 방지
if(!empty($R['uid']) && empty($_COOKIE['bbs_data_'.$R['uid']])) {
    if(strcmp($_SESSION['userID'],$R['userID']) !== 0){ // 등록자 본인이 아니면
        $d->getDbUpdate('bbs_data','hit=hit+1','uid='.$R['uid']);
        setcookie('bbs_data_'.$R['uid'], TRUE, time() + (60 * 60 * 24), '/');
    }
}

?>
<table class="table table-bordered table-hover table-sm" cellspacing="0" width="100%">
    <tr>
        <td style="width:70px;">제목</td>
        <td class="text-left"><?php echo $R['subject']?></td>
    </tr>
    <tr>
        <td>내용</td>
        <td class="text-left"><?php echo $c->getContents($R['content'],$html);?></td>
    </tr>
</table>

<?php include_once $g['path_bbs'].'bbsComment.php';?>

 

<div class="table-responsive text-nowrap">
    <div class="float-left info">
        <button class="btn btn-md btn-outline-default m-0 px-3 py-2 z-depth-0 waves-effect" type="button" id="BBSHome">목록</button>
    </div>
    <div class="float-right info">
        <?php if($R['userID'] == $_SESSION['userID'] || (isset($_SESSION['authID']) && $_SESSION['authID']==1 )):?>
        <a href="bbsWrite.php" class="btn btn-md btn-outline-default m-0 px-3 py-2 z-depth-0 waves-effect" id="bbsModify" data-id="<?=$R['uid'];?>" curPage="<?=$curPage;?>">수정</a>
        <button class="btn btn-md btn-outline-default m-0 px-3 py-2 z-depth-0 waves-effect" type="button" id="bbsDelete" data-id="<?=$R['uid'];?>" curPage="<?=$curPage;?>">삭제</button>
        <?php endif;?>
    </div>
</div> 

 

bbsComment.php ==> 댓글 달기 및 댓글 보기

<?php

// 파일명 : bbsComment.php

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

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'].'config.php';
require_once $g['path_config'].'dbconnect.php';
require_once $g['path_class'].'dbDataClass.php';
$d = new DBDataClass();

?>

<div class="form-group">
    <form name="commentForm" class="form-inline">
        <input type="hidden" name="mode" value="new" />
        <input type="hidden" name="parentid" value="<?php echo $_GET['uid'];?>" />
        <input type="hidden" name="userID" value="<?php echo $_SESSION['userID'];?>" />
        <input type="hidden" name="userNM" value="<?php echo $_SESSION['userNM'];?>" />
        <input type="hidden" name="p" value="<?=$curPage;?>" />

        <div class="input-group mb-3" style="width:100%;">
          <input type="text" name="comment" class="form-control" placeholder="댓글을 입력하세요" aria-label="comment"
            aria-describedby="comment_form">
          <div class="input-group-append">
            <button type="button" class="btn btn-md btn-outline-default m-0 px-3 py-2 z-depth-0 waves-effect" id="comment_form">댓글</button>
          </div>
        </div>

    </form>
</div>

<div class="table-responsive text-nowrap">
<table class="table table-hover table-sm" cellspacing="0" width="100%">
    <tbody>
    <?php $COMM = $d->getDbArray('bbs_comment','parentid="'.$_GET['uid'].'"','*','uid DESC',0,1);?>
    <?php while($C = mysqli_fetch_array($COMM)):?>
        <tr id="<?php echo $C['uid'];?>">
            <td class="text-left"><?php echo $C['userID'];?></td>
            <td class="text-left"><?php echo $C['comment'];?></td>
            <td><?php echo substr($C['d_regis'],0,8);?></td>
            <td>
            <button class="btn btn-md m-0 z-depth-0 comment_del" type="button" title='삭제'>&times;</button>
            </td>
        </tr>
    <?php endwhile;?>
    </tbody>
</table>
</div>

<?php
// 파일명 : bbsCommentChk.php
if(!isset($_SESSION)){
    session_start();
}
//echo '<pre>';print_r($_POST);echo '</pre>';
//exit;
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST);
    require_once 'path.php';// root 폴더를 기준으로 상대경로 자동 구하기
    require_once $g['path_config'].'dbconnect.php';
    require_once $g['path_class'].'dbDataClass.php';
    $d = new DBDataClass(); // AES_Decode()

    $comment = trim($comment);
    date_default_timezone_set('Asia/Seoul');

    if($mode == 'new'){
        $d_regis = date('YmdHis');
        $access_ip=$_SERVER['REMOTE_ADDR'];
        $QKEY = "parentid,comment,d_regis,userID,userNM,ip";
        $QVAL = "'$parentid','$comment','$d_regis','$userID','$userNM','$access_ip'";
        $d->getDbInsert('bbs_comment',$QKEY,$QVAL);
        echo 1;
    } else {
        // 등록자 여부 체크
        $R = $d->getUidData('bbs_comment',$uid);
        if($R['userID'] == $_SESSION['userID']){
            $QSET="comment='".$comment."'";
            $QVAL="uid='".$uid."'";

            $d->getDbUpdate('bbs_data',$QSET,$QVAL);
            echo 2;
        } else {
            echo -2;
        }
    }
} else {
    echo -1;
}
?>

<?php
// 파일명 : bbsCommentDelete.php
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'].'config.php';
require_once $g['path_config'].'dbconnect.php';
require_once $g['path_class'].'dbDataClass.php';
$d = new DBDataClass;

if(!isset($_GET['idx']) || empty($_GET['idx'])){
    $rs=0;
} else {
    // 등록자 여부 체크
    $R = $d->getUidData('bbs_comment',$_GET['idx']);
    if($R['userID'] == $_SESSION['userID'] || (isset($_SESSION['authID']) && ($_SESSION['authID']==1 || $_SESSION['authID']==2))){
        // 등록자 또는 관리자(관리자, 최고관리자) 인 경우에는 삭제 가능
        $rs=$d->getDbDelete('bbs_comment', 'uid='.$_GET['idx'].'');
    } else {
        $rs = -2;
    }
}
echo $rs;
?>

 

jQuery 처리 부분은 https://link2me.tistory.com/1665 를 참조하면 된다.

 

728x90
블로그 이미지

Link2Me

,
728x90

게시판에서 등록한 글을 MySQL DB에 저장하는 로직 구현이다.

jQuery 와 연동하여 처리하므로 MySQL DB에 등록되지 전에 값이 제대로 잘 전달되는지 체크하는 걸 시도한다.

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


POST 변수가 문제없이 잘 전달되었으면 이제 관련 코드를 아래와 같이 구현했다.

게시판을 완벽하게 처리하는 것은 아니고 1단에 대한 값만 등록하고, 게시글이 등록되었을 때 관리자에게 메일이 전달되도록 하는 걸 추가했다.


<?php
if(!isset($_SESSION)){
    session_start();
}
//echo '<pre>';print_r($_POST);echo '</pre>';
//exit;
if(isset($_POST) && $_SERVER['REQUEST_METHOD'] == "POST"){
    @extract($_POST);
    require_once 'path.php';// root 폴더를 기준으로 상대경로 자동 구하기
    require_once $g['path_config'].'dbconnect.php';
    require_once $g['path_class'].'dbDataClass.php';
    require_once $g['path_class'].'bbsClass.php';
    $d = new DBDataClass();
    $c = new bbsClass();

    if($mode == 'write'){
        $subject = trim($subject);
        $content = trim($content);
        $html = 0;
        $depth = 1;
        $notice = 0;
        date_default_timezone_set('Asia/Seoul');

        if($uid == 0){
            $d_regis = date('YmdHis');
            $access_ip=$_SERVER['REMOTE_ADDR'];
            $QKEY = "bbsid,subject,content,html,depth,notice,d_regis,userID,userNM,ip";
            $QVAL = "'$bid','$subject','$content',$html,$depth,$notice,'$d_regis','$userID','$userNM','$access_ip'";
            $d->getDbInsert('bbs_data',$QKEY,$QVAL);
            Mail2Admin($subject,$content);
            echo 1;
        } else {
            // 등록자 여부 체크
            $R = $d->getDbData('bbs_data','uid='.$uid,'*');
            if($R['userID'] === $_SESSION['userID']){ // 관리자도 수정은 불가
                $QSET="subject='".$subject."',";
                $QSET.="content='".$content."',";
                $QSET.="html='".$html."'";
                $QVAL="uid='".$uid."'";

                $d->getDbUpdate('bbs_data',$QSET,$QVAL);
                echo 2;
            } else {
                echo -2;
            }
        }
    } else if($mode == 'delete'){
        $d->getDbDelete('bbs_data',"uid='".$uid."'");
        echo 3; // 삭제
    }
} else {
    echo -1;
}

function Mail2Admin($subject,$message){
    global $c;
    $to = "jsk005@naver.com";
    $from = "webmaster@abc.com";
    $nameFrom = "AppMaster";
    $message = $c->getContents($message,'TEXT');

    $mailheaders = "Return-Path: $from\r\n";
    $mailheaders.= "From: $nameFrom <$from>\r\n";
    $mailheaders.= "Content-Type: text/html;charset=utf-8\r\n";
    $mailheaders.= "MIME-Version: 1.0\r\n";

    mail($to, $subject, $message, $mailheaders, $from);
}
?>

function getContents($str,$html){
    if ($html == 'HTML'){
        $str = htmlspecialchars_decode(stripslashes($str));
        $str = str_replace('<A href=','<a target="_blank" href=',$str);
        $str = str_replace('<a href=','<a target="_blank" href=',$str);
        $str = str_replace('<a target="_blank" href="#','<a href="#',$str);
        $str = str_replace(' target="_blank">','>',$str);
        $str = str_replace('< param','<param',$str);
        $str = str_replace("\t",'&nbsp;&nbsp;&nbsp;&nbsp;',$str);
        $str = str_replace('@IFRAME@','iframe',$str);

        $str = str_replace('imgOrignWin(this.src)=""','onclick="imgOrignWin(this.src);"',$str);
        $str = str_replace('imgorignwin(this.src)=""','onclick="imgOrignWin(this.src);"',$str);
        $_atkParam = array(';a=','&a=','?a=','m=admin','system=');
        foreach($_atkParam as $_prm){
            $str = str_replace($_prm,'',$str);
        }
    }
    else {
        $str = str_replace('<','&lt;',$str);
        $str = str_replace('>','&gt;',$str);
        $str = str_replace('&nbsp;','&amp;nbsp;',$str);
        $str = str_replace("\t",'&nbsp;&nbsp;&nbsp;&nbsp;',$str);
        $str = nl2br($str);
    }
    return $str;
}



728x90
블로그 이미지

Link2Me

,