728x90

PHP 배열로 넘겨주는 함수에 따라서 처리를 다르게 해야 동작된다는 걸 확인하고 코드를 다시 적어둔다.


http://link2me.tistory.com/1134 게시글에서 가져오는 함수에서 넘겨주는 값이

문자열로 넘겨줄 경우와 배열로 넘겨줄 경우 각각 상황에 맞게 구현해야 한다.


<?php
require_once 'connect.php'; // db접속 성공
require_once 'statsClass.php'; // 통계 클래스
$b = new statsClass();
$R = $b->extract_YM();
date_default_timezone_set('Asia/Seoul');
if(isset($_GET['ym'])){
    $ym = $_GET['ym'];
} else {
    $ym = date("Ym");
}
$ticks = json_encode($b->maxdate_YM($ym));
$line1 = json_encode($b->dailyCnt_value($ym));
$line2 = json_encode($b->userCnt_value($ym));
?>
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
<meta http-equiv="X-UA Compatible" />
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<!-- http://www.jqplot.com 제공 자바스크립트 include -->
<script type="text/javascript" src="../js/jqplot/jquery.jqplot.js"></script>
<script type="text/javascript" src="../js/jqplot/plugins/jqplot.barRenderer.js"></script>
<script type="text/javascript" src="../js/jqplot/plugins/jqplot.pointLabels.js"></script>
<script type="text/javascript" src="../js/plugins/jqplot.categoryAxisRenderer.js"></script>
<link rel="stylesheet" type="text/css" href="../js/jqplot/jquery.jqplot.css" />
<script type="text/javascript">
$(document).ready(function(){
    var plot1;

    var obj1 = <?php echo $line1; ?>;
    var line1 = $.map(obj1, function(el) { return el });
    var obj2 = <?php echo $line2; ?>;
    var line2 = $.map(obj2, function(el) { return el });
    var ticks = JSON.parse('<?php echo $ticks; ?>');

    renderChart(line1,line2,ticks);

    $('#selectmonth').on('change',function(){
        if(this.value !== ""){
            var optVal=$(this).find(":selected").val();
            //var pageURL = "<?php echo $_SERVER['PHP_SELF'];?>?ym=" + optVal;
            //$(location).attr('href', pageURL);

            var year = optVal.substr(0,4); // 년
            var month = optVal.substr(4,2); // 월
            $.post('stats_db.php',{optVal:optVal},function(msg){
                //alert(msg); // 배열 형태로 넘어오는지 확인 목적
                var jsonObj = $.parseJSON(msg); // JSON 문자열을 JavaScript object 로 반환
                //alert(typeof jsonObj.ticks);
                //alert(jsonObj.data1);
// string 인지 object 인지 확인 목적
                var data1 = $.map(jsonObj.data1, function(el) { return el });
                var data2 = $.map(jsonObj.data2, function(el) { return el });
                //alert(jsonObj.ticks);
                var xAxis = jsonObj.ticks;
                updatePlot(data1,data2,xAxis);
            });
        }
    });

});


function renderChart(line1,line2,xAxis){
    plot1 = $.jqplot('chartDiv', [line1,line2], CreateBarChartOptions(xAxis));
}

function updatePlot(line1,line2,xAxis){
    plot1.destroy();
    plot1 = $.jqplot('chartDiv', [line1,line2], CreateBarChartOptions(xAxis));
}

function CreateBarChartOptions(xAxis) {
    var optionsObj = {
        title: '일자별 접속 통계',
        seriesDefaults:{
            renderer:$.jqplot.BarRenderer, // 막대 그래프
            rendererOptions: { barWidth: 10 }, // bar의 너비 수동으로 설정
            pointLabels: { show: true } // 레이블 값
        },
        axes: {
            xaxis: {
                renderer: $.jqplot.CategoryAxisRenderer,
                ticks: xAxis,
                tickOptions: {
                    formatString: '%d' // 정수형으로 표시
                }
                //label:'일자'
            },
            yaxis:{
                //renderer:$.jqplot.DateAxisRenderer,
                min:0,
                //max:80
            }
        },
        highlighter: { show: false }
    };
    return optionsObj;
}
</script>

</head>
<body>
<div id="chartDiv" style="height:400px;width:1500px; "></div>
<div style="height:300px;width:1490px;margin-top:10px;text-align:right;">
<select name="month" id="selectmonth">
<option value="">년월 선택</option>
<?php
    while ($row = mysql_fetch_array($R)){
        echo "<option value='".$row[0]."' ";
        if($row[0] === $ym) echo "selected='selected'";
        echo ">".$row[0]."</option>\n";
    }
?>
</select>
</div>
</body>
</html>


=== stats_db.php ===

<?php
if(isset($_POST['optVal'])){
    require_once 'connect.php'; // db접속 성공
    require_once 'statsClass.php'; // 통계 클래스
    $b = new statsClass;
    $ym = $_POST['optVal'];
    $data1 = $b->dailyCnt_value($ym); // 배열로 받은 결과
    $data2 = $b->userCnt_value($ym); // 배열로 받은 결과
    $ticks = $b->maxdate_YM($ym);  // 배열로 받은 결과
    $R = array('data1'=>$data1,'data2'=>$data2, 'ticks'=>$ticks);
    echo json_encode($R);
}
?>

블로그 이미지

Link2Me

,
728x90

Array 변수 처리에 대한 이해가 부족하여 기능 구현보다 변환하는데 시간이 휠씬 더 걸리고 있다.

다 기초가 부족한 탓이다. 테스트한 결과를 무조건 기록해둔다.


PHP 함수에서 return json_encode($R); 배열로 반환 결과가

{"1":"36","2":"23","3":"14","4":"7","5":"12","6":"6","7":"5","8":"9","9":"17","10":"7"}

일 경우


자바스크립트에서 배열 변수로 받기 위해서는

var obj1 = JSON.parse('<?php echo $line1; ?>');

var line1 = new Array();

for(var i in obj1){

    line1.push(obj1[i]);

}

로 하면 값만 추출된 배열변수가 만들어진다.

또다른 방법으로 테스트를 했다.

var obj1 = <?php echo $line1; ?>;

var line1 = $.map(obj1, function(el) { return el });

로 해도 동일한 결과가 나온다.



배열 변환 결과가

[0,1,2,3,4,5,6,7,8,9,10]

로 화면 출력될 경우에는

var ticks = JSON.parse('<?php echo json_encode($ticks); ?>');

또는

var ticks = <?php echo '["' . implode('","', $ticks) . '"]' ?>;

둘 중에 하나를 사용하면 배열 변수가 된다.


PHP 배열로 반환된 결과를

<?php

$Line2 = array();
foreach($line2 as $key => $value){
    array_push($Line2,$value);
}

?>

로 값만 다시 배열로 만든다음에

var line2 = <?php echo '["' . implode('","', $Line2) . '"]' ?>;

로 자바스크립트 배열 변수를 만들 수 있다.


테스트한 파일을 그대로 적어둔다.

<?php
require_once 'connect.php'; // db접속 성공
require_once 'statsClass.php'; // 통계 클래스
$b = new statsClass();
$R = $b->extract_YM();
date_default_timezone_set('Asia/Seoul');
if(isset($_GET['ym'])){
    $ym = $_GET['ym'];
} else {
    $ym = date("Ym");
}
$ticks = $b->maxdate_YM($ym);
$line1 = $b->dailyCnt_value($ym);
$line2 = $b->userCnt_value($ym);
//echo $line1.'<br />';
//echo json_encode($line2).'<br />';
//echo json_encode($ticks).'<br />';
$Line2 = array();
foreach($line2 as $key => $value){
    array_push($Line2,$value);
}
?>
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
<meta http-equiv="X-UA Compatible" />
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<!-- http://www.jqplot.com 제공 자바스크립트 include -->
<script type="text/javascript" src="../js/jqplot/jquery.jqplot.js"></script>
<script type="text/javascript" src="../js/jqplot/plugins/jqplot.barRenderer.js"></script>
<script type="text/javascript" src="../js/jqplot/plugins/jqplot.pointLabels.js"></script>
<script type="text/javascript" src="../js/plugins/jqplot.categoryAxisRenderer.js"></script>
<link rel="stylesheet" type="text/css" href="../js/jqplot/jquery.jqplot.css" />
<script type="text/javascript">
$(document).ready(function(){
    var plot1;
    /*
    var obj1 = JSON.parse('<?php echo $line1; ?>');
    var line1 = new Array();
    for(var i in obj1){
        line1.push(obj1[i]);
    }
    */
    var obj1 = <?php echo $line1; ?>;
    var line1 = $.map(obj1, function(el) { return el });

    //var obj2 = JSON.parse('<?php echo json_encode($line2); ?>');
    /*
    var line2 = new Array();
    for(var i in obj2){
        line2.push(obj2[i]);
    }
    */
    var line2 = <?php echo '["' . implode('","', $Line2) . '"]' ?>;

    //var ticks = JSON.parse('<?php echo json_encode($ticks); ?>');
    var ticks = <?php echo '["' . implode('","', $ticks) . '"]' ?>;

    renderChart(line1,line2,ticks);

    $('#selectmonth').on('change',function(){
        if(this.value !== ""){
            var optVal=$(this).find(":selected").val();
            var pageURL = "<?php echo $_SERVER['PHP_SELF'];?>?ym=" + optVal;
            $(location).attr('href', pageURL);
        }
    });

});


function renderChart(line1,line2,xAxis){
    plot1 = $.jqplot('chartDiv', [line1,line2], CreateBarChartOptions(xAxis));
}

function updatePlot(line1,line2,xAxis){
    plot1.destroy();
    plot1 = $.jqplot('chartDiv', [line1,line2], CreateBarChartOptions(xAxis));
}

function CreateBarChartOptions(xAxis) {
    var optionsObj = {
        title: '일자별 접속 통계',
        seriesDefaults:{
            renderer:$.jqplot.BarRenderer, // 막대 그래프
            rendererOptions: { barWidth: 10 }, // bar의 너비 수동으로 설정
            pointLabels: { show: true } // 레이블 값
        },
        axes: {
            xaxis: {
                renderer: $.jqplot.CategoryAxisRenderer,
                ticks: xAxis,
                tickOptions: {
                    formatString: '%d' // 정수형으로 표시
                }
                //label:'일자'
            },
            yaxis:{
                //renderer:$.jqplot.DateAxisRenderer,
                min:0,
                //max:80
            }
        },
        highlighter: { show: false }
    };
    return optionsObj;
}
</script>

</head>
<body>
<div id="chartDiv" style="height:400px;width:1500px; "></div>
<div style="height:300px;width:1490px;margin-top:10px;text-align:right;">
<select name="month" id="selectmonth">
<option value="">년월 선택</option>
<?php
    while ($row = mysql_fetch_array($R)){
        echo "<option value='".$row[0]."' ";
        if($row[0] === $ym) echo "selected='selected'";
        echo ">".$row[0]."</option>\n";
    }
?>
</select>
</div>
</body>
</html>


블로그 이미지

Link2Me

,
728x90

어제 고객사 사이트에 autocomplete 기능을 적용 테스트를 했다.

내가 사용하는 환경인 윈도우10 Explorer 11 에서는 autocomplete 동작이 잘 된다.

하지만 고객사 키맨으로부터 전혀 검색을 할 수가 없어 기존 사용하던 것도 안된다는 민원이 발생해서 환경을 확인해보니 윈도우 7 에 Explorer 버전이라고 나온다. Explorer 세부 버전정보까지는 확인 불가

그래서 결국에

$('#searchValue').autocomplete({
    source: "path/autosearch.php",
    minLength: 1
});

는 주석처리 할 수 밖에 없었다.


// === autosearch.php ====
<?php
require_once "connect.php";

if (isset($_GET['term'])){
    $return_arr = array();

    $keyword = $_GET['term'];
    $sql = "SELECT distinct(name) FROM member WHERE name LIKE '%".$keyword."%'";
    $result = mysql_query($sql);
    while($row = mysql_fetch_assoc($result)){
        array_push($return_arr,$row['name']);
    }

    echo json_encode($return_arr);
}
?>


중복없이 이름 검색이 되도록 하기 위해서 distinct 처리를 했다.

원하는 결과가 잘 나옴에도 불구하고 적용은 할 수가 없었다.


http://jqueryui.com/autocomplete/ 에서 샘플로 나온 것이 아래 스크립트를 포함하고 있어서 이걸로 테스트를 했는데 윈도우 10 Firefox 브라우저에서는 잘 되는걸 확인했다.

<link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" type="text/css" />
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>


일단 접속하는 브라우저의 정확한 정보부터 수집하는 코드를 구현해야 할 거 같다.

지금은 Chrome,Firefox, Explorer 여부만 수집되는데 버전 정보까지 수집되도록 코드를 세분화해야 할 거 같다.

그래야 새로운 코드 적용시 발생하는 민원을 정확하게 감지할 수 있을 거 같다.


http://www.computerhope.com/issues/ch000604.htm 사이트 자료에 Explorer 세팅 정보를 수정하면 동작되는 것 처럼 되어 있기는 하다.


멀티부팅되는 환경을 만들어서 다양한 접속을 해야만 하나보다.

블로그 이미지

Link2Me

,
728x90

PHP 자료를 검색하다가 알게된 사이트를 적어둔다.

주로 구글 검색을 하기 때문에 알게된 사이트가 대부분 외국 사이트가 많다.


http://www.tutorialrepublic.com/


http://www.w3schools.com/


http://phppot.com


http://www.codexworld.com/


http://webclub.tistory.com : CSS 와 Javascript 내용이 좋다.


생활코딩 PHP 동영상 강좌

https://opentutorials.org/index.php/course/62

https://www.inflearn.com/


코딩의 첫걸음

http://tcpschool.com/


생활코딩 node.js 동영상 강좌

https://opentutorials.org/course/2136


위지윅에디터

- 게시판에서 글쓰기시 HTML, 그림 등을 본문에 쉽게 첨가할 수 있게 해주는 스마트에디터다.

- 이미지 첨부하는 방법을 테스트해봐야 한다.

https://www.tinymce.com/



그래프 그리는 챠트

http://canvasjs.com/javascript-charts/


http://www.jqchart.com/



자바스크립트/jQuery 사이트

Dynamic Web Coding  http://www.dyn-web.com/


jQuery UI : https://jqueryui.com/


모던 웹사이트 디자인의 정석

- 이 사이에 가면 책 예제에 나온 샘플 소스 파일을 받을 수 있다.

- UI 디자인 하는 방법을 체계적으로 설명하고 있다.

http://wikibook.co.kr/modern-web-design-book/


https://w3layouts.com/



PHP to ASP

http://www.me-u.com/php-asp/


PHP framework 사이트

1. KIMSQRB : 클릭 몇번만으로 홈페이지 레이아웃, 게시판을 만들어 주는 빌더

   사용자가 많지 않고, 잘 만들어져서 해킹사례가 없는 거 같다.

   RB 1.2.2 버전과 RB 2.0 버전이 있는데 RB 2.0 버전은 개발이 되다가 중단된 상태(?)이며,

   RB2.0은 HTML5 부트스트랩 기반으로 만들어졌다.

   http://www.kimsq.co.kr/

   http://panocafe.tistory.com/

   http://www.kimsq.co.kr/note/wildnote


2. 그누보드

    https://sir.kr/

   코드 보안패치가 끊임없이 올라오는 홈페이지 빌더

   현재 국내에서 가장 사용자층이 많은 PHP 빌더

   개인적으로 제로보드로 홈페이지를 만들었다가 해킹을 두번이나 당하면서 홈페이지 운영을 중단해야 했던 아픈 경험때문에 해킹에 취약한 빌더는 사용하지 않는다.


3. 코드이그나이터

   http://www.codeigniter.com/

   외국에서 만든 프레임웍인데 아직 사용을 못해봤다.

   회사에서 코드 만들때 이걸 많이 사용한다고 해서 이걸 배워보려고 PHP PDO 관련 지식을 습득하기 위해 온라인 유료강의를 신청해서 수강중이다.

  프레임웍을 만들어보려고 시도해봤는데 정말 많은 지식과 경험이 축적되어야만 만들 수 있겠더라.

  난 초보 수준이니까 그냥 잘 만들어진 빌더 기반으로 필요한 것만 추가해서 사용해야....



유용 블로그

https://javafactory.tistory.com/


ㅇ 파비콘(favicon) 만들어주는 사이트

https://www.favicon-generator.org/

  


'자료 구하기 > 정보' 카테고리의 다른 글

오픈소스SW 라이선스 LGPL 바로알기  (0) 2018.04.24
Android 추천 사이트  (0) 2017.04.11
C# 추천 사이트  (0) 2016.01.17
부트스트랩 사이트  (2) 2015.08.24
ICT 산업동향 자료  (0) 2014.08.06
블로그 이미지

Link2Me

,
728x90

현재 실행중인 파일에서 일부 값이 변경되어 그 값을 가지고 변경되어야 할 경우가 있다.


PHP 에서 echo $_SERVER['PHP_SELF']; 로 확인해보면 http://domain/path/filename.php 까지를 추출한다.


jQuery 에서 alert($(location).attr('href')); 로 확인해보면 $(location).attr('href'); 는 뒤에 GET 변수까지를 추출한다.


그래서

var pageURL = $(location).attr('href')+"?ym=" + optVal;

$(location).attr('href', pageURL);

로 하면 잘못된 결과가 나온다.

즉 GET 변수까지를 $(location).attr('href') 로 인식하므로 뒤에 또 덧붙여져 ?ym=201611?ym=201612 이런 식이 되어 버린다.


그래서 PHP 를 같이 활용하여

var pageURL = "<?php echo $_SERVER['PHP_SELF'];?>?ym=" + optVal;

$(location).attr('href', pageURL);

로 코드 구현해서 원하는 결과를 얻었다.


$('#selectmonth').on('change',function(){
    if(this.value !== ""){
        var optVal=$(this).find(":selected").val();
        var pageURL = "<?php echo $_SERVER['PHP_SELF'];?>?ym=" + optVal;
        $(location).attr('href', pageURL);
    }
});


참고사항

$(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


블로그 이미지

Link2Me

,
728x90

일일 통계 데이터를 생성해야 하는데 생성하지 못한 경우 새벽(접속이 없는 시간대)에 crontab 으로 자동으로 DB에 데이터를 저장하는 코드를 추가해서 작업하는게 좋다.


<?php
require_once "connect.php"; // DB 연결
require_once "statsClass.php"; // 통계함수
$a=new statsClass();

echo '일일통계 기록';
echo '<br />';

date_default_timezone_set('Asia/Seoul');

$now_year = date("Y"); // 금년
$now_month = date("m"); // 현재월
$last_day = date("t", mktime(0, 0, 1, $now_month, 1, $now_year)); // 해당월의 마지막 일자 반환

for($i=1;$i<=$last_day;$i++){
    $date = date("Ymd", mktime(0,0,0,date("m"), $i, date("Y")));
    $YM = substr($date,0,6);
    $day = substr($date,6,2);

    echo $date.'<br />';
    // DB에 정보 기록하도록 하는 코드 추가
}

echo "Work done";
exit;
?>

블로그 이미지

Link2Me

,
728x90

Java 와 C#이 어떻게 다른지 설명이 잘된 글이 있어서 가져왔다.


출처 : http://www.elex.pe.kr/entry/Java-cf-C-Sharp

프로그램 구조

Java

package hello;


public class HelloWorld {
   public static void main(String[] args) {
      String name = "Java";

      // 매개변수를 확인
      if (args.length == 1)
         name = args[0];

      System.out.println("Hello, " + name + "!");
    }
}

C#

using System; 

namespace Hello {
   public class HelloWorld {
      public static void Main(string[] args) {
         string name = "C#";

         // 매개변수를 확인
         if (args.Length == 1)
            name = args[0];

         Console.WriteLine("Hello, " + name + "!");
      }
   }
}

Java 소스 파일의 확장자는 *.java이고, C#은 *.cs이다.

Java는 클래스마다 별도의 파일을 작성해야 하고 클래스명과 파일명이 일치해야 하지만, C#에서는 하나 이상의 최상위 클래스를 작성할 수 있고 파일명에 대한 제한도 없다.

Java

package harding.compsci.graphics;










// 단일 클래스를 임포트
import harding.compsci.graphics.Rectangle;
// 여러 클래스를 임포트
import harding.compsci.graphics.*; 

C#

namespace Harding.Compsci.Graphics {
  ...
}
또는
namespace Harding {
  namespace Compsci {
    namespace Graphics {
      ...
    }
  }
}
// 단일 클래스를 임포트
using Rectangle = Harding.CompSci.Graphics.Rectangle;
// 여러 클래스를 임포트
using Harding.Compsci.Graphics;

Java는 소스 코드의 첫 줄에 package를 선언하지만, C#에서는 namespace 키워드를 사용해서 블록으로 묶는다. C#에서는 하나의 소스 코드 파일에 여러 개의 네임스페이스를 포함시는 것도 가능하다.

Java의 import 키워드 대신, C#에서는 using 키워드를 사용한다. using 키워드를 namespace 블록 내부에 사용할 수도 있다. using 키워드를 사용해서 별칭을 지정할 수도 있다.

주석

Java

// 한 줄 주석
/* 여러 줄
    주석  */
/** 자바독 문서화 주석 */

C#

// 한 줄 주석
/* 여러 줄
    주석  */
/// 한 줄 XML 주석
/** 여러 줄 XML 주석 */

자료형

Java

원시 자료형
boolean
byte
char
short, int, long
float, double


참조 자료형
Object   (다른 모든 클래스들의 부모 클래스)
String
arrays, classes, interfaces

형 변환
// 정수를 문자열로 
int x = 123; 
String y = Integer.toString(x);  // y is "123"
// 문자열을 정수로
y = "456"; 
x = Integer.parseInt(y);   // x is 456
// 부동소수를 정수로
double z = 3.5; 
x = (int) z;   // x는 3  (소수부는 잘림)

C#

값 타입
bool
byte, sbyte
char
short, ushort, int, uint, long, ulong
float, double, decimal
structures, enumerations

참조 자료형
object    ( 다른 모든 클래스들의 부모 클래스)
string
arrays, classes, interfaces, delegates

형 변환
// 정수를 문자열로 
int x = 123; 
String y = x.ToString();  // y is "123"
// 문자열을 정수로
y = "456"; 
x = int.Parse(y);   // 또는 x = Convert.ToInt32(y);
// 부동소수를 정수로
double z = 3.5; 
x = (int) z;   // x는 3  (소수부는 잘림)

Java에서 지원되는 원시 자료형과 더불어, C#에서는 부호 없는(unsigned) 자료형과 128비트 부동 소수 형식(decimal)을 추가로 지원한다.

Java에서는 원시 자료형이 존재하고 각각의 래퍼 클래스가 존재하지만, C#에서 모든 원시 자료형은 System 네임스페이스의 객체이며 각각 별칭이 존재한다.

Java의 boolean은 C#에서 bool이다.

상수

Java

// 생성자에서 초기화 될 수 있음
final double PI = 3.14;

C#

const double PI = 3.14;

// const 또는 변수에 지정할 수 있음. 생성자에서 초기화 될 수 있음.
readonly int MAX_HEIGHT = 9;

Java에서는 final 키워드를, C#에서는 const와 readonly 키워드를 사용한다.

const 키워드를 사용하면 런타임시에 값을 변경할 수 없지만, readonly 키워드를 지정하면 런타임시에 단 한번 값을 지정할 수 있다.

열거형

Java

enum Action {Start, Stop, Rewind, Forward};
// 특수한 형태의 클래스이다. 
enum Status {
  Flunk(50), Pass(70), Excel(90);
  private final int value;
  Status(int value) { this.value = value; }
  public int value() { return value; } 
};
Action a = Action.Stop;
if (a != Action.Start)
  System.out.println(a);      // Prints "Stop"
Status s = Status.Pass;
System.out.println(s.value());      // Prints "70"

C#

enum Action {Start, Stop, Rewind, Forward};
enum Status {Flunk = 50, Pass = 70, Excel = 90};






Action a = Action.Stop;
if (a != Action.Start)
  Console.WriteLine(a);             // Prints "Stop"
Status s = Status.Pass;
Console.WriteLine((int) s);       // Prints "70"

Java 1.5 이상에서 enum을 지원한다.

C# 3.0 이상에서는 확장메서드를 통해서 enum 타입에 메서드를 정의할 수 있다.

연산자

Java

비교
==  <  >  <=  >=  !=

산술
+  -  *  /
%  (mod)
/   (integer division if both operands are ints)
Math.Pow(x, y)

할당
=  +=  -=  *=  /=   %=   &=  |=  ^=  <<=  >>=  
>>>= ++ -- 비트 & | ^ ~ << >> >>> 논리 && || & | ^ ! 문자열 결합 +

C#

비교
==  <  >  <=  >=  !=

산술
+  -  *  /
%  (mod)
/   (integer division if both operands are ints)
Math.Pow(x, y)

할당
=  +=  -=  *=  /=   %=  &=  |=  ^=  <<=  >>=  ++  --


비트
&  |  ^   ~  <<  >>

논리
&&  ||  &  |   ^   !

문자열 결합
+

연산자 오버로딩
public static ComplexNumber operator+(ComplexNumber a, ComplexNumber b) { ...

Java의 >>> 연산자는 C#에서 사용할 수 없다. 이는 부호없는 자료형이 지원되기 때문이다.

C#의 checked, unchecked 키워드를 사용해서 오버플로우를 검사할 수 있다.

C#에서는 연산자 오버로딩을 위해 operator 키워드를 지원한다.

연산자 오버로딩은 static 메서드로 선언하고 메서드 이름 대신에 operator 키워드와 연산자 심볼을 붙인다.

조건문

Java

greeting = age < 20 ? "What's up?" : "Hello";

if (x < y) 
  System.out.println("greater");

if (x != 100) {    
  x *= 5; 
  y *= 2; 
} 
else 
  z *= 6;

int selection = 2;
switch (selection) { // byte, short, int, char, enum
  case 1: x++;   // break가 없으면 다음으로 넘어간다
  case 2: y++;   break; 
  case 3: z++;   break; 
  default: other++;
}

C#

greeting = age < 20 ? "What's up?" : "Hello";

if (x < y)  
  Console.WriteLine("greater");

if (x != 100) {    
  x *= 5; 
  y *= 2; 
} 
else 
  z *= 6;

string color = "red";
switch (color) {    //자료형 제한이 없다.
  case "red":    r++;    break;  // break 꼭 필요
  case "blue":   b++;   break; 
  case "green": g++;   break; 
  default: other++;     break; 
}

Java 7이후부터 switch문에 문자열을 사용할 수 있다.

Java와 달리 C#에서는 case문 다음에 반드시 break문이 존재해야 한다.

반복문

Java

while (i < 10) 
  i++;

for (i = 2; i <= 10; i += 2) 
  System.out.println(i);

do 
  i++; 
while (i < 10);

for (int i : numArray)  // foreach construct  
  sum += i;

import java.util.ArrayList;
ArrayList<Object> list = new ArrayList<Object>();
list.add(10); 
list.add("Bisons");
list.add(2.3);    
for (Object o : list)
  System.out.println(o);

C#

while (i < 10) 
  i++;

for (i = 2; i <= 10; i += 2) 
  Console.WriteLine(i);

do 
  i++; 
while (i < 10);

foreach (int i in numArray)  
  sum += i;
 
using System.Collections;
ArrayList list = new ArrayList();
list.Add(10);
list.Add("Bisons");
list.Add(2.3);
foreach (Object o in list)
  Console.WriteLine(o);

배열

Java

int nums[] = {1, 2, 3};   
     또는   int[] nums = {1, 2, 3};

for (int i = 0; i < nums.length; i++)
  System.out.println(nums[i]);

String names[] = new String[5];
names[0] = "David";

float twoD[][] = new float[rows][cols];
twoD[2][0] = 4.5;

int[][] jagged = new int[5][]; 
jagged[0] = new int[5]; 
jagged[1] = new int[2]; 
jagged[2] = new int[3]; 
jagged[0][4] = 5;

C#

int[] nums = {1, 2, 3};


for (int i = 0; i < nums.Length; i++)
  Console.WriteLine(nums[i]);

string[] names = new string[5];
names[0] = "David";

float[,] twoD = new float[rows, cols];
twoD[2,0] = 4.5f;

int[][] jagged = new int[3][] {
    new int[5], new int[2], new int[3] }; 
jagged[0][4] = 5;

Java와 달리 C#에서는 배열을 나타내는 대괄호 []는 반드시 자료형 다음에 와야 한다.

배열의 초기화 시에도, Java와 달리 C#에서는 배열의 크기와 초기값의 수가 일치해야 한다.

C#에서는 Jagged 배열 외에 다차원 배열을 추가로 지원한다.

메서드

Java

// 값을 반환
int Add(int x, int y) { 
   return x + y; 
}

int sum = Add(2, 3);
// 결과값을 반환하지 않음
void PrintSum(int x, int y) { 
   System.out.println(x + y); 
}
PrintSum(2, 3); 

// 값에 의한 전달
void TestFunc(int x, Point p) {
   x++; 
   p.x++;       // 객체 값 변경
   p = null;    // 객체 참조를 제거 
}
class Point { 
   public int x, y; 
}
Point p = new Point(); 
p.x = 2; 
int a = 1; 
TestFunc(a, p);
System.out.println(a + " " + p.x + " " + (p == null) );  
// 1 3 false // 임의의 갯수의 매개변수 int Sum(int ... nums) { int sum = 0; for (int i : nums) sum += i; return sum; } int total = Sum(4, 3, 2, 1); // returns 10

C#

// 값을 반환
int Add(int x, int y) { 
   return x + y; 
}

int sum = Add(2, 3);
// 결과값을 반환하지 않음
void PrintSum(int x, int y) { 
   Console.WriteLine(x + y); 
}
PrintSum(2, 3); 

// 값에 의한 전달, ref, out
void TestFunc(int x, ref int y, out int z, Point p1, ref Point p2) { 
   x++;  y++;  z = 5; 
   p1.x++;       // 객체 값 변경     
   p1 = null;    // 객체 참조를 제거 
   p2 = null;   // 객체 참조를 제거 
}
class Point { 
   public int x, y; 
}
Point p1 = new Point(); 
Point p2 = new Point(); 
p1.x = 2; 
int a = 1, b = 1, c;   // out은 초기화 필요 없음
TestFunc(a, ref b, out c, p1, ref p2); 
Console.WriteLine("{0} {1} {2} {3} {4}", 
   a, b, c, p1.x, p2 == null);   // 1 2 5 3 True

// 임의의 갯수의 매개변수
int Sum(params int[] nums) {
  int sum = 0;
  foreach (int i in nums)
    sum += i;
  return sum;
}
int total = Sum(4, 3, 2, 1);   // returns 10

C#에서는 값 형식의 데이터를 참조 형식으로 매개변수를 전달하기 위해서 ref, out 키워드를 지원한다.

ref의 경우 사용하기 전에 반드시 초기화 되어 있어야 하고, out의 경우 메서드 내에서 사용하기 전에 값을 할당해야 한다.

임의의 갯수의 매개변수를 전달 받으려는 경우, Java는 ...을, C#은 params 키워드를 사용한다.

문자열

Java

// 결합
String school = "Harding "; 
school = school + "University";   // school is "Harding University"

// 비교
String mascot = "Bisons"; 
if (mascot == "Bisons")    // 틀려!
if (mascot.equals("Bisons"))   // true
if (mascot.equalsIgnoreCase("BISONS"))   // true
if (mascot.compareTo("Bisons") == 0)   // true
System.out.println(mascot.substring(2, 5));   // Prints "son"

// 날짜
java.util.Calendar c 
  = new java.util.GregorianCalendar(1973, 10, 12);
String s 
  = String.format("My birthday: %1$tb %1$te, %1$tY", c);

// 조작가능한 문자열 
StringBuffer buffer = new StringBuffer("two "); 
buffer.append("three "); 
buffer.insert(0, "one "); 
buffer.replace(4, 7, "TWO"); 
System.out.println(buffer);     // Prints "one TWO three"

String path = "\\\\FileShare\\Directory\\file.txt";

C#

// 결합
string school = "Harding "; 
school = school + "University";   // school is "Harding University"

// 비교
string mascot = "Bisons"; 
if (mascot == "Bisons")    // true
if (mascot.Equals("Bisons"))   // true
if (mascot.ToUpper().Equals("BISONS"))   // true
if (mascot.CompareTo("Bisons") == 0)    // true
Console.WriteLine(mascot.Substring(2, 3));    // Prints "son"

// 날짜
DateTime dt 
  = new DateTime(1973, 10, 12);
string s 
  = "My birthday: " + dt.ToString("MMM dd, yyyy");

// 조작가능한 문자열 
System.Text.StringBuilder buffer = 
new System.Text.StringBuilder("two "); buffer.Append("three "); buffer.Insert(0, "one "); buffer.Replace("two", "TWO"); Console.WriteLine(buffer); // Prints "one TWO three" string path = @"\\FileShare\Directory\file.txt";

문자열 비교시에, Java는 equals() 메서드를 사용하지만, C#에서는 == 또는 != 연산자를 사용할 수 있다.

C#에서는 변수에 할당되는 문자열 앞에 @을 붙여서 이스케잎 문자를 효율적으로 처리할 수 있다.

예외처리

Java

// 메서드에서 예외를 던질 수 있도록 선언되어야 함
Exception ex 
  = new Exception("Something is really wrong."); 
throw ex;  

try {
  y = 0; 
  x = 10 / y;
} catch (Exception ex) {
  System.out.println(ex.getMessage()); 
} finally {
  // Code that always gets executed
}

C#

Exception up 
  = new Exception("Something is really wrong."); 
throw up;  // ha ha

try {
  y = 0; 
  x = 10 / y;
} catch (Exception ex) { // 매개변수가 없어도 됨
  Console.WriteLine(ex.Message); 
} finally {
  // Code that always gets executed
}

C#의 catch 블록에서 매개변수를 생략할 수도 있다.

C#에서는 throws 키워드가 없다.

클래스 / 인터페이스

Java

접근 키워드
public
private
protected
static



// 상속
class FootballGame extends Competition {
  ...
}

// 인터페이스
interface IAlarmClock {
  ...
}

// 인터페이스의 상속
interface IAlarmClock extends IClock {
  ...
}

// 인터페이스 구현
class WristWatch implements IAlarmClock, ITimer {
   ...
}

C#

접근 키워드
public
private
internal
protected
protected internal
static

// 상속
class FootballGame : Competition {
  ...
}

// 인터페이스
interface IAlarmClock {
  ...
}

// 인터페이스의 상속
interface IAlarmClock : IClock {
  ...
}

// 인터페이스 구현
class WristWatch : IAlarmClock, ITimer {
   ...
}

Java의 기본 접근 제한자는 동일 패키지 내에서 접근 가능인 반면, C#에서는 private이다.

C#의 internal 키워드는 현재 어셈블리 내에서만 접근 가능하도록 지정하는 것이며, 어셈블리는 Java의 Jar파일과 유사한 개념이다.

Java에서 클래스가 더이상 상속 될 수 없도록 지정하는 final 키워드 대신, C#에서는 sealed 키워드를 사용한다.

Java에서 상속과 구현을 나타내는 키워드인 extends와 implements 대신, C#에서는 :을 사용한다.

Java의 super 키워드 대신, C#에서는 base 키워드를 사용한다.

Java와 달리, C#에서는 오버라이드 될 메서드에는 virtual 키워드를 오버라이드 하는 메서드에는 override 키워드를 사용한다.

C#에서는 인덱서를 지원하므로 이를 이용하면 클래스나 구조체를 배열처럼 다룰 수 있다.

객체

Java

SuperHero hero = new SuperHero();
hero.setName("SpamMan"); 
hero.setPowerLevel(3); 

hero.Defend("Laura Jones");
SuperHero.Rest();  // 정적 메서드 호출
SuperHero hero2 = hero;   // 동일한 객체를 참조

hero2.setName("WormWoman"); 
System.out.println(hero.getName()); 

hero = null;   // Free the object
if (hero == null)
  hero = new SuperHero();
Object obj = new SuperHero(); 
System.out.println("object's type: " + obj.getClass().toString()); 
if (obj instanceof SuperHero) 
  System.out.println("Is a SuperHero object.");

C#

SuperHero hero = new SuperHero(); 
hero.Name = "SpamMan"; 
hero.PowerLevel = 3;

hero.Defend("Laura Jones");
SuperHero.Rest();   // 정적 메서드 호출
SuperHero hero2 = hero;   // 동일한 객체를 참조
 
hero2.Name = "WormWoman"; 
Console.WriteLine(hero.Name);  

hero = null ;   // Free the object
if (hero == null)
  hero = new SuperHero();
Object obj = new SuperHero(); 
Console.WriteLine("object's type: " + obj.GetType().ToString()); 
if (obj is SuperHero) 
  Console.WriteLine("Is a SuperHero object.");

생성자 / 파괴자

Java

class SuperHero {
  private int mPowerLevel;

  public SuperHero() {
    mPowerLevel = 0;
  }

  public SuperHero(int powerLevel) {
    this.mPowerLevel= powerLevel;
  }

  // 파괴자는 없음
  protected void finalize() throws Throwable { 
    super.finalize();   // 항상 부모 요소를 호출
  }
}

C#

class SuperHero {
  private int mPowerLevel;

  public SuperHero() {
     mPowerLevel = 0;
  }

  public SuperHero(int powerLevel) {
    this.mPowerLevel= powerLevel; 
  }

  ~SuperHero() {
    // Destructor code to free unmanaged resources.
    // Implicitly creates a Finalize method.
  }
}

Java에서는 finalize() 메서드를 사용해서 가비지 컬렉터에 의해 인스턴스가 정리되기 직전에 실행될 메서드를 지정하는 반면, C#에서는 매개변수 없는 생성자와 유사한 형식으로 지정하며 이름 앞에 물결 표시(~)를 붙인다.

속성

Java

private int mSize;

public int getSize() { return mSize; } 
public void setSize(int value) {
  if (value < 0) 
    mSize = 0; 
  else 
    mSize = value; 
}


int s = shoe.getSize();
shoe.setSize(s+1);

C#

private int mSize;

public int Size { 
  get { return mSize; } 
  set { 
    if (value < 0) 
      mSize = 0; 
    else 
      mSize = value; 
  } 
}

shoe.Size++;

C#에서는 private 멤버 변수의 getter와 setter 메서드를 처리하는 get, set 키워드를 지원한다.

구조체

Java

x

C#

x

x

프로그램 구조

Java

 

C#

struct StudentRecord {
  public string name;
  public float gpa;

  public StudentRecord(string name, float gpa) {
    this.name = name;
    this.gpa = gpa;
  }
}

StudentRecord stu = new StudentRecord("Bob", 3.5f);
StudentRecord stu2 = stu;  

stu2.name = "Sue";
Console.WriteLine(stu.name);    // Prints "Bob"
Console.WriteLine(stu2.name);   // Prints "Sue"

C#에서는 클래스와 유사한 구조체라는 자료형을 지원한다. 단, 구조체는 상속이 불가능하고, 참조형 데이터가 아니다.

이벤트

Java

 

C#

window.ClickedEvent += MyEventHandler;

Java의 경우 이벤트를 수신할 클래스에서 Listener를 구현한 후 이벤트를 발생시키는 객체에 등록(register)하지만, C#에서 이벤트는 이벤트를 발생시키는 객체의 멤버이므로 이벤트 핸들러 메서드를 추가하기만 하면 된다.

C#에서는 이벤트 핸들러 메서드를 위해 delegate 키워드를 제공한다. 딜리게이트는 함수 포인터와 유사한 개념이다.

콘솔 입출력

Java

java.io.DataInput in 
= new java.io.DataInputStream(System.in);
System.out.print("What is your name? ");
String name = in.readLine();

System.out.print("How old are you? ");
int age = Integer.parseInt(in.readLine());
System.out.println(name + " is " + age + " years old.");
int c = System.in.read();   // Read single char
System.out.println(c);      // Prints 65 if user enters "A"

// The studio costs $499.00 for 3 months.
System.out.printf("The %s costs $%.2f for %d months.%n", "studio", 499.0, 3);

// Today is 06/25/04
System.out.printf("Today is %tD\n", new java.util.Date());

C#

Console.Write("What's your name? ");
string name = Console.ReadLine();



Console.Write("How old are you? ");
int age = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("{0} is {1} years old.", name, age);
// 또는
Console.WriteLine(name + " is " + age + " years old.");
int c = Console.Read(); // Read single char Console.WriteLine(c); // Prints 65 if user enters "A" // The studio costs $499.00 for 3 months. Console.WriteLine("The {0} costs {1:C} for {2} months.\n",
"studio", 499.0, 3); // Today is 06/25/2004 Console.WriteLine("Today is " + DateTime.Now.ToShortDateString());

파일 입출력

Java

import java.io.*;

// Character stream writing
FileWriter writer 
  = new FileWriter("c:\\myfile.txt");
writer.write("Out to file.\n");
writer.close();

// Character stream reading
FileReader reader 
  = new FileReader("c:\\myfile.txt");
BufferedReader br = new BufferedReader(reader);
String line = br.readLine(); 
while (line != null) {
  System.out.println(line); 
  line = br.readLine(); 
} 
reader.close();

// Binary stream writing
FileOutputStream out 
  = new FileOutputStream("c:\\myfile.dat");
out.write("Text data".getBytes());
out.write(123);
out.close();

// Binary stream reading
FileInputStream in 
  = new FileInputStream("c:\\myfile.dat");
byte buff[] = new byte[9];
in.read(buff, 0, 9);   // Read first 9 bytes into buff
String s = new String(buff);
int num = in.read();   // Next is 123
in.close();

C#

using System.IO;

// Character stream writing
StreamWriter writer 
  = File.CreateText("c:\\myfile.txt"); 
writer.WriteLine("Out to file."); 
writer.Close();

// Character stream reading
StreamReader reader 
  = File.OpenText("c:\\myfile.txt"); 
string line = reader.ReadLine(); 
while (line != null) {
  Console.WriteLine(line); 
  line = reader.ReadLine(); 
} 
reader.Close();



// Binary stream writing
BinaryWriter out 
  = new BinaryWriter(File.OpenWrite("c:\\myfile.dat")); 
out.Write("Text data"); 
out.Write(123); 
out.Close();

// Binary stream reading
BinaryReader in 
  = new BinaryReader(File.OpenRead("c:\\myfile.dat")); 
string s = in.ReadString(); 
int num = in.ReadInt32(); 
in.Close();

C#에는 이 외에 인덱서, unsafe, fixed 등이 더 있음.

참고 자료:

http://www.harding.edu/fmccown/java_csharp_comparison.html

http://msdn.microsoft.com/en-us/library/ms228602(v=vs.90)

 


'C# > 문법 및 기능' 카테고리의 다른 글

C# 구조체(Struct)  (0) 2019.08.14
C# 접근 제한자(Access Modifier)  (0) 2019.08.13
C# NameValueCollection  (0) 2016.03.20
C# Dictionary 와 comboBox 연결  (0) 2016.02.08
C# Directory (폴더) 생성 및 삭제  (0) 2016.01.16
블로그 이미지

Link2Me

,
728x90

Tree 형태의 JSON 을 만드는 방법으로 easyUI jQuery 를 사용하는 방법을 테스트 했다.

 

id: "1",
name: "loreim ipsum",
data: {},
children: [{
    id: "2",
    name: "lorem ipsum1",
    data: {},
    children: [{
        id: "3",
        name: "lorem ipsum2",
        data: {},
        children: [{


tree 형태의 JSON을 만드는 방법은

http://stackoverflow.com/questions/4328515/convert-php-array-to-json-tree

에 나온 걸 참조하면 된다.



Convert PHP array to JSON tree

=== treeSQLtoJSON.php ===

<?php
include_once "connect.php";
$sql = "SELECT * FROM treeview_items";
$res = mysqli_query($db, $sql);
while($row = mysqli_fetch_assoc($res)){
    $data[] = $row;
}

$node = array();
// Build array of item references:
foreach($data as $key => &$item) {
   $node[$item['id']] = &$item;
   // Children array:
   $node[$item['id']]['children'] = array();
   // Empty data class (so that json_encode adds "data: {}" )
   $node[$item['id']]['data'] = new StdClass();
}

// Set items as children of the relevant parent item.
foreach($data as $key => &$item)
   if($item['parent_id'] && isset($node[$item['parent_id']]))
      $node [$item['parent_id']]['children'][] = &$item;

// Remove items that were added to parents elsewhere:
foreach($data as $key => &$item) {
   if($item['parent_id'] && isset($node[$item['parent_id']]))
      unset($data[$key]);
}

$json = json_encode($data);
echo $json;
?>

=== treeview.php ===

<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<title>Basic Tree - jQuery EasyUI Demo</title>
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
<meta http-equiv="X-UA Compatible"/>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css">
<link rel="stylesheet" href="js/easyui/themes/default/easyui.css">
<link rel="stylesheet" href="js/easyui/themes/icon.css">
<link rel="stylesheet" href="js/easyui/demo.css">

<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/easyui/jquery.easyui.min.js"></script>
<script type="text/javascript">
$(function(){
    $('#tt').tree({
        url: 'treeSQLtoJSON.php',
        onClick: function(node){
            //alert(node.link);
            $('.content').html(node.link);
        }
    });
});
</script>

</head>
<body>
<div style="margin:20px 0;"></div>
<div class="container-fluid"><!--container-fluid 클래스 선택자는 전체 화면을 사용할 때 사용 -->
  <div class="container"><!--container 클래스 선택자는 최대 넓이가 1170px -->
    <div class="col-md-2 sidenav">
      <!--사이드바 내용-->
        <div class="easyui-panel" style="padding:5px">
            <ul id="tt"></ul>
        </div>
    </div>
    <div class="col-md-10">
        <div class="content">
          <!--본문 내용-->
          본문내용
        </div>
    </div>
  </div>
</div>
</body>
</html>


코드가 훨씬 심플해졌다.


이제 http://www.jeasyui.com/demo/main/index.php 사이트 데모를 가지고 만들어보기가 훨씬 수월해졌다.


블로그 이미지

Link2Me

,
728x90

Treeview 를 만들기 위해서 이것 저것 테스트 해보느라고 고생 좀 하고 있다.

easytree.js 는 node.id 얻는 방법을 몰라서 포기를 했다.

그래서 검색해서 easyUI tree 를 찾아냈다.

http://www.jeasyui.com/documentation/index.php# 에 설명이 잘 나와 있다.

easyUI jQuery 는 잘 활용하면 홈페이지가 확 달라질 거 같다.


중요 포인트는 MySQL DB 자료를 JSON Data 로 만드는 방법을 알아야 하더라.

좀 복잡한 것을 만들 줄 알아야 하는데 아직 그 부분까지는 이해를 못했다.


=== treeSQLtoJSON.php ===

<?php
include_once "connect.php";
$sql = "SELECT * FROM treeview_items";
$res = mysqli_query($db, $sql);
while($row = mysqli_fetch_assoc($res)){
    $menu[] = $row;
}

// while 하나로 처리해야 하는데 Class 처리 목적 분리 코딩
$result = array();
foreach ($menu as $row){
    array_push($result,
    array('id'=>$row['id'],
          'parentId'=>$row['parent_id'],
          'name'=>$row['text'],
          'link'=>$row['link']
    ));
}

echo json_encode($result);
?>


JSON Data 만드는 법을 알고 나면 http://www.jeasyui.com/tutorial/tree/tree6.php 에서 내용을 읽어보고 데모 파일을 받아서 수정해서 사용하면 된다.

블로그 이미지

Link2Me

,
728x90

Treeview 를 검색해서 테스트 하다보니 JSON 만드는 방법을 알아야 원하는 결과로 만들어 낼 수 있는 거 같다.


<?php
include_once "connect.php";
require_once 'treeClass.php'; // Tree 클래스
$t = new treeClass();
$sql = "SELECT * FROM treeview_items";
$result = mysqli_query($db, $sql);
while($row = mysqli_fetch_assoc($result)){
    $menu[] = $row;
}

?>


여기까지는 일반적인 형태로 배열화를 하는 방법이다.

만들어진 배열을 가지고 foreach 문을 이용하여 다시 재가공을 해야 한다.


$rows   = array();
$i=0;
foreach ($menu as $r) {
    $rows[$i]['first_name'] = $r->first_name;
    $rows[$i]['last_name'] = $r->last_name;
    $rows[$i]['phone'] = $r->phone;
    $rows[$i]['email'] = $r->email;

    $i++;
}

//keys total & rows is required on jEasyUI
$result = array('total'=>$menu['count'],'rows'=>$rows);
echo json_encode($result);



Android JSON 포멧으로 만드는 가장 일반적인 형태


<?php

include_once "connect.php";

$sql = "SELECT * FROM address";
$res = mysqli_query($db,$sql); 
$result = array(); 
while($row = mysqli_fetch_array($res)){ 
    array_push($result,
    array('id'=>$row[0],'name'=>$row[1],'address'=>$row[2]
    )); 


$json = json_encode(array("result"=>$result)); 

?>


여기서

    array_push($result,
    array('id'=>$row[0],'name'=>$row[1],'address'=>$row[2]
    )); 

부분을

$result['result'][] = $row;

로 하는게 더 편할 수 있다.

'Web 프로그램 > JSON, 파싱 다루기' 카테고리의 다른 글

Parse JSON with PHP (JSON 파싱)  (2) 2017.11.27
PHP Array 활용 JSON  (0) 2017.05.11
[PHP Parsing] Snoopy로 로또번호 추출하기  (0) 2016.08.01
XML 데이터 생성 처리  (0) 2016.06.06
PHP 와 XML 연동처리  (0) 2016.06.04
블로그 이미지

Link2Me

,
728x90


JQuery 기반 Autocompete 구현을 해보기로 하고 검색해서 개념을 잡고 테스트했다.

jQuery 를 모를 때는 엄두도 낼 수 없었는데 jQuery 에 대한 기본 개념을 조금 이해하고 다양한 플러그인(plugin)들을 테스트 해보고 있다.


http://www.bewebdeveloper.com/tutorial-about-autocomplete-using-php-mysql-and-jquery 에서 제공한 소스코드를 받아서 윈도우 AutoSet9 에서 설치하였다.

ajax_refresh.php 코드는 내가 사용하는 방식의 코드가 아니라서 수정했다.

나머지 파일은 약간 수정했다.



=== ajax_refresh.php ===

<?php
include_once 'connect.php';

$keyword = $_POST['keyword'];
$sql = "SELECT * FROM country WHERE country_name LIKE '%".$keyword."%' ORDER BY uid ASC LIMIT 0, 10";
$result = mysqli_query($db, $sql);
while($row = mysqli_fetch_assoc($result)){
    $list[] = $row;
}

foreach ($list as $rs) {
    // put in bold the written text
    $country_name = str_replace($_POST['keyword'], '<b>'.$_POST['keyword'].'</b>', $rs['country_name']);
    // add new option
    echo '<li onclick="set_item(\''.str_replace("'", "\'", $rs['country_name']).'\')">'.$country_name.'</li>';
}
?>


=== autocomplete.js ===

function autocomplet() {
    var min_length = 0; // min caracters to display the autocomplete
    var keyword = $('#uid').val();
    if (keyword.length >= min_length) {
        $.ajax({
            url: 'ajax_refresh.php',
            type: 'POST',
            data: {keyword:keyword},
            success:function(data){
                $('#country_list_id').show();
                $('#country_list_id').html(data);
            }
        });
    } else {
        $('#country_list_id').hide();
    }
}

// set_item : this function will be executed when we select an item
function set_item(item) {
    // change input value
    $('#uid').val(item);  // 실제 DB와 연동하여 값을 넘겨줘서 검색해야 하는 부분
    // hide proposition list
    $('#country_list_id').hide();
}


파일은 원 사이트에서 받아도 되고 첨부한 파일을 받아서 DB 관련 부분을 수정해서 테스트 해봐도 된다.

본 첨부파일에는 dbconnect.php 파일도 같이 포함되어 있고, DB 스키마를 내가 사용하는 uid로 수정한 것도 포함되어 있다. 즉 받아서 DB에 테이블 생성하고 경로만 지정해주면 바로 동작이 가능하다.

mysqli 기반으로 테스트 한 것이므로 mysql 를 사용하는 환경이라면 약간 수정해야 한다.


autocomplete_for_php.zip


이 정도로도 개념 이해는 도움은 많이 되는데 다른 것도 검색해서 테스트해보고 기록해 두려고 한다.

문제점 : 한글 자동완성 검색 안됨


한글검색되는 코드 (추천)

구글링을 해보니 코드가 유사하게 몇개의 사이트에서 검색된다. 이용하기는 이 코드가 훨씬 편할 거 같기는 하다.

원  소스 사이트는 https://jqueryui.com/autocomplete/ 다. 여기서 데모 실행부터 해보면 된다.

이 사이트에 가면 유용한 기능이 많다. 기능 적용이 매우 단순하다.

아래 코드 연결된 버전 정보로 해도 되지만 jqueryui.com 사이트에 적용된 최신버전으로 적용해도 된다.


사용법

1. jquery-ui.min.css, jquery-ui.min.js 링크 추가 또는 파일 다운로드 받아서 폴더 경로 추가

2. <input type='text' name='country' value='' id='auto'> input 에 ID 추가하거나 Class 추가

3. jQuery 코드

$('#auto').autocomplete({ 

source: "autosearch.php", // 타이핑시 보여질 내용

minLength: 1

});

4. PHP 코드 구현(autosearch.php)

<?php
require_once 'sessionChk.php'; // 세션 체크
require_once 'dbconnect.php';

if (isset($_GET['term'])){
    $return_arr = array();

    $keyword = $_GET['term'];
    $sql = "SELECT distinct(userNM) FROM members WHERE userNM LIKE '%".$keyword."%'";
    $result = mysqli_query($db,$sql);
    while($row = mysqli_fetch_assoc($result)){
        array_push($return_arr,$row['userNM']);
    }
    echo json_encode($return_arr);
}
?>



autocomplete-master.zip


<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Demo</title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/minified/jquery-ui.min.css" type="text/css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script><!-- 최신버전으로 구해서-->
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.1/jquery-ui.min.js"></script>   
<script type="text/javascript">
$(function() {
    //autocomplete
    $(".auto").autocomplete({
        source: "autosearch.php",
        minLength: 1
    });               
});
</script></head>
<body>
    <form action='' method='post'>
        <p><label>Country:</label><input type='text' name='country' value='' class='auto'></p>
    </form>
</body>
</html>


=== autosearch.php ===

이 부분 코드는 내가 사용하는 방식으로 수정했다.

<?php
include_once 'connect.php';

if (isset($_GET['term'])){
    $return_arr = array();

    $keyword = $_GET['term'];
    $sql = "SELECT country_name FROM country WHERE country_name LIKE '%".$keyword."%'";
    $result = mysqli_query($db, $sql);
    while($row = mysqli_fetch_assoc($result)){
        $return_arr[] =  $row['country_name'];
    }
   
    echo json_encode($return_arr);
}
?>


여기서 검색어 결과가 너무 많이 나오는 것이 싫다면 LIMIT 를 사용해서 제한하면 된다.

$sql = "SELECT distinct(country_name) FROM country WHERE country_name LIKE '%".$keyword."%' LIMIT 10";

검색할 내용이 너무 많다면 별도로 검색한 결과를 별도 테이블로 작성해서 그 검색결과를 자동완성 검색어로 불러들려도 된다. 이 경우에는 별도로 코딩이 좀 필요하다.

블로그 이미지

Link2Me

,
728x90

jsTree 는 MIT 에서 공개한 jquery plugin 으로 HTML 또는 JSON 데이터를 Tree 형식으로 화면에 출력해주는 라이브러리이다.

https://www.jstree.com/ 에서 jquery plugin 설명을 참조한다.

여기서 다루는 jstree.js 는 include 해보니 jstree.min.js 와 약간 다른지 tree 아이콘 모양이 달라서 jstree.min.js 를 사용했다.


본 자료는 구글링을 통해서 얻은 지식으로 기존 자료에 부족한 사항을 추가했다.

기본적인 설명은 http://phpflow.com/php/dynamic-tree-with-jstree-php-and-mysql/ 사이트에 잘 나와있다.

관리자가 메뉴를 추가/수정/삭제하는 기능도 이 사이트에 잘 나와 있다.

다만 아쉬웠던 것은 Treeview 에서 아이템을 클릭하면 해당 ITEM에 연결된 link 를 다른 <div>에 뿌려주는 것이 되어야 Treeview 의 의미가 있으므로 이 부분 처리를 하려고 열심히 검색하고 찾았는데 ....

포기하고 생각을 변경하여 시도를 한 끝에 원하는 결과를 얻었다.

이 과정에서 고수의 도움을 받았는데 알고 보면 생각의 전환만 했어도 쉽게 해결할 수 있었던 사항이다.


=== 테이블 구조 ===

CREATE TABLE IF NOT EXISTS `treeview_items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` varchar(11) DEFAULT NULL,
  `name` varchar(200) NOT NULL,
  `text` varchar(200) NOT NULL,
  `link` varchar(200) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=15 ;


INSERT INTO `treeview_items` (`id`, `parent_id`, `name`, `text`, `link`) VALUES
(1, '0', 'MySQL', 'MySQL', '#'),
(2, '0', 'Java', 'Java', '#'),
(3, '0', 'PHP', 'PHP', '#'),
(4, '3', '투토리얼', '투토리얼', 'http://link2me.tistory.com'),
(5, '3', 'PHP Script', 'Script', '#'),
(6, '5', '메일', '메일', '#'),
(7, '2', 'Java Tutorial', 'Tutorial', '#'),
(8, '2', 'Java Resources', 'Resources', '#'),
(9, '1', 'MySQL Tutorial', 'Tutorial', '#'),
(10, '5', '로그인', '로그인', 'http://www.naver.com'),
(11, '3', 'PHP Resources', 'Resources', '#'),
(12, '10', 'Login1', 'Login1', ''),
(13, '10', 'Login2', 'Login2', ''),
(14, '3', '추가노드', '추가노드', '');


=== tree.php ===

<!DOCTYPE html>
<head>
<meta charset=UTF-8" />
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
<meta http-equiv="X-UA Compatible" control="IE=edge,chrome=1" />
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css">
<link rel="stylesheet" href="js/jstree/style.min.css">
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="js/jstree/jstree.min.js"></script>

<script type="text/javascript">
$(document).ready(function(){
    $('#tree-container').jstree({
        'plugins': ["wholerow"],
        'core' : {
            'data' : {
                "url" : "tree_getdb.php",
                "dataType" : "json"
            }
        }
    }).on("changed.jstree", function (e, data) {
        if(data.selected.length) {
            var id = data.instance.get_node(data.selected[0]).id;
            $.post('tree_link_result.php', {id: id}, function(data){
                //alert(data);
                $('.content').html(data);
            });
        }
    });

});
</script>
</head>
<body>
<div class="container-fluid"><!--container-fluid 클래스 선택자는 전체 화면을 사용할 때 사용 -->
  <div class="container"><!--container 클래스 선택자는 최대 넓이가 1170px -->
    <div class="col-md-2">
      <!--사이드바 내용-->
        <div id="tree-container"></div>
    </div>
    <div class="col-md-10">
        <div class="content">
          <!--본문 내용-->
          본문내용
        </div>
    </div>
  </div>
</div>

</body>
</html>


=== tree_link_result.php ===

<?php
$id=$_POST['id'];
if(isset($id) && !empty($id)){
    include_once "connect.php";
    $sql = "SELECT * FROM treeview_items where id='{$id}'";
    $result = mysqli_query($db, $sql);
    if($row=mysqli_fetch_array($result)){
        echo $row['link'];
    }
}
?>


=== on("changed.jstree", function (e, data) { 부분을 아래와 같이 수정해도 된다.

    }).bind("select_node.jstree", function (e, data) {
        var id = data.node.id;
        $.post('tree_link_result.php', {id: id}, function(data){
            //alert(data);
            if(data == '#') return '';
            $('.content').html(data);
        });


나머지 자료는 phpflow.com 과 인터넷에서 구해서 위에 나온 부분만 수정해서 사용하면 문제없이 처리될 것이다.


구글링해서 구해 테스트한 jstree 소스만 첨부한다.

jstree.zip


블로그 이미지

Link2Me

,
728x90

PHP 폴더내 파일 개수를 구하는 함수를 만들어보자.


검색해보니

function dirs_chk($dir){
 $dirs=count(scandir($dir)); 
 echo $dirs;
}
$dir = 'uploads/';
echo dirs_chk($dir);

로 하면 파일 개수를 구할 수 있다고 해서 테스트를 해보니 이건 sub 폴더까지 검색하는데 문제는 . 과 .. 까지 카운트를 한다. 그래서 원하는 개수를 정확하게 구할 수가 없다.


http://www.webmadang.net/develop/develop.do?action=read&boardid=1003&page=1&seq=65

에 있는 걸로 테스트를 했더니 제대로 나오는데 경고 메시지가 출력된다.


원하는 사항은 특정 폴더내에서 특정 확장자를 가진 파일의 개수를 반환하고자 한다.

그래서 경고메시지 나오는 부분을 수정했고 특정 확장자만 검사하도록 코드를 추가했다.


<?php
$doc_root = $_SERVER["DOCUMENT_ROOT"]; // Web서버 root directory
$dir=$doc_root.'/fileupload/uploads/';
$dir_count = 0;
$file_count = 0;
$valid_formats = array("jpg", "png", "gif");

// 디렉토리에 있는 파일과 디렉토리의 갯수 구하기
$result = opendir($dir); //opendir 함수를 이용해서 디렉토리의 핸들을 얻어옴
// readdir함수로 지정 디렉토리에 있는 디렉토리와 파일들의 이름을 배열로 읽어들임
while($file = readdir($result)) {
    if($file === "."|| $file === "..") continue; // file명이 ".", ".." 이면 무시함
    $getExt = pathinfo($file, PATHINFO_EXTENSION); // 파일의 확장자를 구함

    if(empty($getExt)){
        $dir_count++; // 파일에 확장자가 없으면 디렉토리로 판단하여 dir_count를 증가시킴
    } else {
        if(in_array($getExt, $valid_formats)){
            $file_count++; // 검사조건에 맞는 파일이 있으면 카운트
        }
    }
}

echo"디렉토리 갯수 : ".$dir_count."<br>";
echo"파일의 갯수 : ".$file_count;
?>


이제 다른 곳에서 사용하기 위해서 함수화를 해보자.


// 지정 디렉토리내의 지정 파일 개수 구하기

function getFilesCount_CurDir($dir){
    $dir_count = 0;
    $file_count = 0;
    $valid_formats = array("jpg", "png", "gif"); // 그림 확장자 지정
   
    // 디렉토리에 있는 파일과 디렉토리의 갯수 구하기
    $result = opendir($dir); //opendir 함수를 이용해서 디렉토리의 핸들을 얻어옴
    // readdir함수를 이용해서 디렉토리에 있는 디렉토리와 파일들의 이름을 배열로 읽어들임
    while($file = readdir($result)) {
        if($file === "."|| $file === "..") continue; // file명이 ".", ".." 이면 무시함
        $getExt = pathinfo($file, PATHINFO_EXTENSION); // 파일의 확장자를 구함

        if(!empty($getExt)){
            if(in_array($getExt, $valid_formats)){
                $file_count++; // 검사조건에 맞는 파일이 있으면 카운트
            }
        }
    }
    return $file_count;
}


블로그 이미지

Link2Me

,
728x90

jQuery ajax 를 사용하지 않는 jQuery 를 http://link2me.tistory.com/1142 에서 다루었다.


=== fileupload.js ===

$(document).ready(function() {
    $('#form').submit(function(){
        var
upfiles_cnt = $("input:file", this)[0].files.length;
        if(
upfiles_cnt == 0){
            alert('선택한 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }
    });
});

ajax 방식을 사용한 jQuery 를 구현해보자.

파일 업로드 현황을 progress bar 로 구현하려고 구글링을 하면서 개념 이해 및 테스트 중이다.

ajax 로 파일 전송시 현재 업로드한 파일 숫자가 0 인지 체크 로직을 추가하여 처리하도록 구현했다.

구글링을 해서 이 방법 저 방법 테스트를 해보니 formData 부분에서 에러가 발생하더라.


=== fileupload.js ===

$(document).ready(function() {

    $('#form').submit(function(e){
        //disable the default form submission
        e.preventDefault();

        //grab all form data <== 필요에 따라 코드 수정해서 사용해야 함.
        var form = $('form')[0];
        var formData = new FormData(form);


        var upfiles_cnt = $("input:file", this)[0].files.length;
        if(upfiles_cnt == 0){
            alert('선택한 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }


        $.ajax({
            url: "fileupload.php",
            data: formData,
            cache: false,
            contentType: false,
            processData: false,
            type: 'POST',
            dataType: "json",
            success: function (data) {
                $('.status').html(data + ' Files uploaded!').fadeIn();
            },
            error: function(){
                alert("error in ajax form submission");
            }
        });

        return false;
    });

});



Upload Progress bar 검색해보면 대부분 아래 코드와 유사한 것이 검색된다.

그런데 이코드를 수정해서 Upload 파일 갯수가 0이면 진행이 안되게 하려고 테스트 하니 잘 안된다.


=== fileupload.js ===
$(document).ready(function() {

    $('form').ajaxForm({
        /* set data type json */
        dataType:  'json',

        /* reset before submitting */
        beforeSend: function() {
            status.fadeOut();
            bar.width('0%');
            percent.html('0%');
        },

        /* progress bar call back*/
        uploadProgress: function(event, position, total, percentComplete) {
            var pVel = percentComplete + '%';
            bar.width(pVel);
            percent.html(pVel);
        },

        /* complete call back */
        complete: function(data) {
            status.html(data.responseJSON.count + ' Files uploaded!').fadeIn();
        }
    });
});



http://phppot.com/jquery/jquery-progress-bar-for-php-ajax-file-upload/ 사이트를 발견하고 이걸 참조하여 구현했더니 원하는 결과가 나온다.


아래 코드는 에러 없이 정상 동작한다.

//grab all form data
var form = $('form')[0];
var formData = new FormData(form);


그런데 파일 전송시

<input type="hidden" name="uid" value="">

<input type="file" id="file" name="file" multiple />

와 같이 이미지 파일 외에 uid 값까지 같이 전송되도록 하려니까 잘 전송이 안된다.


var formData = new FormData();
var files = $('#file')[0].files[0];
formData.append('file',files);
formData.append('uid',idx);

와 같이 해주고 나서 정상적으로 전송이 된다.


=== fileupload.js ===
$(document).ready(function() {

    $('#form').submit(function(e){
        //disable the actual submit of the form.
        e.preventDefault();
       
        //grab all form data
        var form = $('form')[0];
        var formData = new FormData(form);

        var upfiles_cnt = $("input:file", this)[0].files.length;
        if(upfiles_cnt == 0){
            alert('선택한 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }

        $(this).ajaxSubmit({
            // set data type json
            dataType:  'json',

            // reset before submitting
            beforeSend: function() {
                status.fadeOut();
                bar.width('0%');
                percent.html('0%');
            },

            // progress bar call back
            uploadProgress: function(event, position, total, percentComplete) {
                var pVel = percentComplete + '%';
                bar.width(pVel);
                percent.html(pVel);
            },

            complete: function(data) {
                status.html(data.responseJSON.count + ' Files uploaded!').fadeIn();
            },
            resetForm: true
        });
        return false;
    });
});



progress bar 가 나오는 ajax 방법으로 구현해보려고 시도하면서 검색/테스트 많이 했다.

나와 같은 jQuery 초보자를 위해서 고생하지 말라고 테스트한 파일을 첨부합니다.


fileupload_ajax.zip



도움되셨다면 공감 눌러주시거나 00 00 한번 해주시길

블로그 이미지

Link2Me

,
728x90

문자열 비교 strcmp

strcmp(string1,string2);


결과값

0 : 두 문자열이 같다.

<0 : string1 is less than string2

>0 : string1 is greater than string2


<?php
$mailing = $row['mailing'] = 1; // DB에서 읽어온 값이라 가정
if(!strcmp($mailing,"1")) {
  $mailing = "가입";
} else if(!strcmp($mailing,"2")) {
  $mailing = "완료";
} else if(!strcmp($mailing,"3")) {
  $mailing = "추가";
} else {
  $mailing = "거부";
}
echo $mailing;
?>


strcmp 를 잘못 사용하면 원하지 않는 결과가 나올 수 있음에 유의하자.

if(0 == NULL){
    echo "True";
} else {
    echo "False";
}

결과는 True 를 반환한다.


if(0 === NULL){
    echo "True";
} else {
    echo "False";
}

결과는 False 를 반환한다.

PHP에서 조건문을 느슨하게 비교하면 원하지 않는 결과가 나올 수 있다.


strcmp는 string(문자열)을 비교하라고 되어 있다.

그런데 문자열 대신 배열을 넣고 비교하면 어떤 결과가 나올까?


$a = Array("a");
$b = 'password';

if (!strcmp($a, $b)){
  echo "Strings are same !";
} else {
  echo "Strings are different";
}

결과

Warning: strcmp() expects parameter 1 to be string, array given in C:\AutoSet9\public_html\11.php on line 5
Strings are same !

보시는 바와 같이 $a 와 $b는 다음에도 불구하고 경고 메시지는 나오지만 결과는 동일하다고 출력한다.


$a = Array("a");
$b = 'password';

if (strcmp($a, $b) === 0){
  echo "Strings are same !";
} else {
  echo "Strings are different";
}

와 같이 해주면 경고메시지는 출력하지만 결과는 다르다고 출력한다.

Warning: strcmp() expects parameter 1 to be string, array given in C:\AutoSet9\public_html\11.php on line 5
Strings are different


하나더 살펴보자.

육안으로 확인하면 두개의 문자열은 서로 다르다. 하지만 결과는 느슨비교를 해서 True를 반환한다.

$something = 0;
echo ('password' == $something) ? 'True' : 'False';


따라서 === 비교를 해주어야 한다.

$something = 0;
echo ('password' === $something) ? 'True' : 'False';


$something = 0;
echo ('1' == $something) ? 'True' : 'False';
이 경우에는 같은 정수를 비교하므로 == 를 사용해도 False 를 반환한다.

문자열과 숫자를 비교시 느슨비교를 하면 엉뚱한 결과가 나옴을 확인할 수 있다.


<?php
$val = 20;
if($val === '20'){
    echo '결과는 동일하다';
} else {
    echo '$val은 정수형, "20"은 문자열형이다.';
    echo '<br />결과는 다르다.';
}
?>


Don't use == in PHP. It will not do what you expect.

Even if you are comparing strings to strings, PHP will implicitly cast them to floats and do a numerical comparison if they appear numerical.

느슨한 비교를 하면 원하지 않은 결과가 나올 수 있음에 유의하자!


블로그 이미지

Link2Me

,
728x90

파일 업로드 관련으로 Javascript 와 jQuery 를 검색하고 필요한 것을 추가/수정해서 작성했다.

파일 중복 체크를 안하려고 파일명을 rename 처리했다.

$rename = md5(uniqid($tmpname)) .round(microtime(true)).'.'.$fileExt;


파일 테스트 환경 : Windows10 AutoSet9, Linux CentOS 6.5


테스트에 사용한 첨부파일

fileupload-01.zip



=== fileform.php ===

<!DOCTYPE html>
<html>
<head>
<title>Multiple File Upload with PHP</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="css/pure-min.css">
<link rel="stylesheet" type="text/css" href="css/fileupload.css">
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<!-- javascript dependencies -->
<script type="text/javascript" src="js/jquery.form.min.js"></script>
<!-- main script -->
<script type="text/javascript" src="js/fileupload.js"></script>
<script type="text/javascript">
    function viewFileList() {
        var input = document.getElementById("files");
        var ul = document.getElementById("fileList");
        while (ul.hasChildNodes()) {
            ul.removeChild(ul.firstChild);
        }
        for (var i = 0; i < input.files.length; i++) {
            var li = document.createElement("li");
            li.innerHTML = input.files[i].name;
            ul.appendChild(li);
        }
        if(!ul.hasChildNodes()) {
            var li = document.createElement("li");
            li.innerHTML = 'No Files Selected';
            ul.appendChild(li);
        }
    }
</script>
</head>
<body>
<div class="container">
    <div class="status"></div>
    <form id="form" action="fileupload.php" method="post" enctype="multipart/form-data" >
        <input type="file" id="files" name="files[]" multiple="multiple" onChange="viewFileList();" />
        <input type="submit" value="Upload" class="pure-button" />
    </form>
    <ul id="fileList"><li>No Files Selected</li></ul>
    <div class="progress">
        <div class="bar"></div>
        <div class="percent">0%</div>
    </div>

</div><!-- end .container -->

</body>
</html>


=== fileupload.js ===

$(document).ready(function() {
    $('#form').submit(function(){
        var numFiles = $("input:file", this)[0].files.length;
        if(numFiles == 0){
            alert('선택된 파일이 없습니다');
            return false; // form을 전송시키지 않고 반환
        }
    });
});


=== fileupload.php ===

<?php
// Edit upload location here
$valid_formats = array("jpg", "png", "gif", "bmp");
$max_file_size = 1024*100; //100 kb
$upload_path='uploads/';
$count = 0;
if(isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST"){
    foreach ($_FILES['files']['name'] as $i => $name) {
        if ($_FILES['files']['error'][$i] == 4) { // 파일이 전송되지 않았습니다
            continue;
        }
        if ($_FILES['files']['error'][$i] == 0) { // 오류 없이 파일 업로드 성공
            if ($_FILES['files']['size'][$i] > $max_file_size) {
                $message[] = "$name is too large!.";
                continue;
            }elseif( ! in_array(pathinfo($name, PATHINFO_EXTENSION), $valid_formats) ){
                $message[] = "$name 은 허용된 파일 포멧이 아닙니다";
                continue;
            }else{ // 에러가 없으면
                $tmpname = $_FILES['files']['tmp_name'][$i];
                $realname = $_FILES['files']['name'][$i];
                $filesize = $_FILES['files']['size'][$i];
                $fileExt = getExt($realname);
                $rename = md5(uniqid($tmpname)) .round(microtime(true)).'.'.$fileExt;
                $uploadFile = $upload_path . $rename;
                if(move_uploaded_file($tmpname, $uploadFile)){
                    @chmod($readFile,0606);

                    // DB 테이블에 저장하는 루틴은 여기에 추가하면 된다.

                    $count++; // 업로드 성공한 파일 숫자
                }
            }
        }
    }
}

echo $count;
?>

<script type="text/javascript">
var count ='<?php echo $count;?>';
alert('업로드 성공 파일수 : ' + count );
setTimeout(function() {
    window.location.replace("fileform.php");
}, 1000);
</script>

<?php
// 확장자 추출 함수
function getExt($filename){
    $ext = substr(strrchr($filename,"."),1);
    $ext = strtolower($ext);
    return $ext;
}
?>



파일 업로드 / 다운로드 취약점
- 업로드 기능에서 파일 사이즈의 제한을 주지 않을 경우
- 파일 타입의 체크가 없는 경우
- 파일이 업로드 되는 경로가 외부에서 직접적으로 접근 가능하거나 실행 권한을 가지게 되는 경우


파일 업로드할 때 @chmod($readFile,0606); 를 하는 이유를 좀 더 알고자 한다면

http://www.macinstruct.com/node/415 에 나오는 그림을 보면 도움된다.

업로드라 함은 파일을 서버에 쓰는(write)하는 것이다.

그러므로 파일을 read(4) + write(2) 권한만 부여하면 된다. 파일을 실행할 수 있게 하면 보안상에 문제가 될 수도 있다. 그래서 업로드한 파일을 읽기와 쓰기 권한만 부여했다.


보안을 위해서 몇가지 더 권고하는 걸 적어둔다.

- 업로드한 파일을 외부에서 접근할 수 없는 경로에 저장한다.

  즉 Web 서버 URL 밖에다가 저장하도록 하는 것이 좋다.

- 업로드한 파일에 대한 웹서버의 실행권한을 제거하고 저장한다.

- 업로드한 파일의 저장 경로와 파일명을 외부에서 알 수 없도록 한다.

  실제 저장되는 파일명은 난수를 이용해 유추 불가능하도록 생성하여 외부로부터 직접적인 접근이 불가능하게 구현한다.

  업로드한 파일을 위한 전용 디렉토리를 생성하여 실행권한을 제거한다.


참고

파일 업로드에 대한 개념 설명이 잘된 URL

http://blog.habonyphp.com/entry/php-POST-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C#.WHWm81z3TFA


블로그 이미지

Link2Me

,
728x90

jQuery 팝업창에서 부모창으로 값을 전달해야 할 때 사용하는 방법이다.


=== 부모창 ===

<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script language='javascript'>
$(document).ready(function() {
    $('#pay').submit(function() {
        window.open('', 'payviewer', 'width=400,height=400,resizeable,scrollbars');
        this.action = 'popup.php';
        this.method = 'POST';
        this.target = 'payviewer';
    });
});
</script>

<form id="pay" >
    <input type="hidden" name="var" value="POST DATA SENT">
    <input type="text" name="name" id="name" value="홍길동">
    <input type="submit" value="결제하기">
</form>


=== 자식창 : popup.php ===

<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script language='javascript'>
$(document).ready(function() {
    $('#payreturn').submit(function() {
        var name = $("input[name='name']").val(); // 현재 폼의 입력값
        $("input[name='name']",opener.document).val(name); // 값 전달 방식 1
        //$(opener.document).find("#name").val(name); // 값 전달 방식 2

        //$("#name",opener.document).val(name); // 값 전달방식 3
        window.self.close(); // 현재 팝업 닫기
    });
});
</script>

<p><?php echo($_POST['var']); ?></p>
<form id="payreturn" >
    <input type="text" name="name" value="<?php echo($_POST['name']); ?>">
    <input type="submit" value="확인">
</form>


위 샘플코드의 파일

popup.zip



$("input[name='name']",opener.document).val(name);는 부모창의 id를 지정하지 않았어도 값을 변경할 수 있다.

$(opener.document).find("#name").val(name); 는 부모창의 id를 직접 찾아서 값을 변경한다.


jQuery 자식 팝업 창에서 부모창 컨트롤
$(opener.document).find("#Form").attr("action","index.do").submit();

// 팝업창에서 부모창 함수 호출

opener.location.href="javascript:fun();"; //일반적인 방법

$(opener.location).attr("href","javascript:부모스크립트함수명();"); //jQuery 이용
$(opener.location).attr("href","javascript:fun();"); //jQuery 이용


// 부모창의 필드값 가져오기

1. 일반적인 방법
var parentValue = opener.document.getElementById("parentId").value;
2. jQuery를 이용한 방법
$("#parentId", opener.document).val();
3. find를 이용한 방법
$(opener.document).find("#parentId").val();


//팝업창에서 부모창 새로고침(새로고침 의사 표현을 묻는 창이 뜸)
window.opener.parent.location.reload();
window.opener.document.location.reload();


// 작은 윈도우 창을 열어서(window.open) 특정 작업을 처리한 후 부모창(opener)을 refresh하는 방법

// window.opener.location.reload(); 에서 window는 생략 가능

<script>
opener.location.reload();
window.close();
</script>


//팝업창 자신 페이지 새로고침
document.location.reload();

//팝업창 닫기
window.self.close();


// 부모창의 URL을 대체시킨다.

opener.location.replace("URL정보");


// 전체 창에서 새 페이지 열기

top.location.href="abc.php";


// 연 창의 URL 이동

opener.location.href="abc.php";


<script type="text/javascript">
  alert("회원가입을 하시겠습니까?")
  location.href= "member.php"
</script>


블로그 이미지

Link2Me

,
728x90

form 데이터를 window 팝업창으로 값을 전달하여 open 해야 할 필요가 있을 때 사용하는 방법이다.


<form action="popup.php" method="post" target="payviewer" onsubmit="window.open('popup.php', 'payviewer', 'width=200, height=200,resizeable,scrollbars');">
    <input type="hidden" name="var" value="POST DATA SENT">
    <input type="submit" value="결제하기" >
</form>


=== popup.php ===

<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Receiver popup</title>
</head>
<body>
<p><?php echo($_POST['var']); ?></p>
</body>
</html>


위와 같은 방법을 jQuery 로 전달하는 방법이다.

<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<script language='javascript'>
$(document).ready(function() {
    $('#pay').submit(function() {
        window.open('', 'payviewer', 'width=200,height=200,resizeable,scrollbars');
        this.target = 'payviewer';
    });
});
</script>

<form id="pay" action="popup.php" method="post" >
    <input type="hidden" name="var" value="POST DATA SENT">
    <input type="submit" value="결제하기">
</form>


이걸 더 수정해보자.

바로 위 코드와 아래 코드가 어떻게 다른지 확인이 될 것이다.

정보를 어떻게 전달하는지를 알 수 있다.


<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<script language='javascript'>
$(document).ready(function() {
    $('#pay').submit(function() {
        window.open('', 'payviewer', 'width=200,height=200,resizeable,scrollbars');
        this.action = 'popup.php';
        this.method = 'POST';
        this.target = 'payviewer';
    });
});
</script>

<form id="pay" >
    <input type="hidden" name="var" value="POST DATA SENT">
    <input type="submit" value="결제하기">
</form>




블로그 이미지

Link2Me

,
728x90

화면(page)을 주기적으로 자동 갱신해야 하는 경우가 있다.

아래 코드는 real time update 보다는 일정한 주기로 업데이트 처리하도록 했다.

갱신 주기를 짧게 하면 실시간 업데이트가 된다.

서버에서 데이터를 가져와야 하는 경우에 너무 빠른 갱신 주기는 부하를 야기할 수 있으므로 주의가 필요할 수도 있다.

구글링을 해서 실제 데이타가 맞는지 확인하면 맞지 않은 경우도 있다.

그래서 반드시 샘플 데이터를 만들고 직접 테스트를 해보고 동작 여부를 확인하고 코드를 적어둔다.


<!DOCTYPE html>
<head>
<meta charset=UTF-8" />
<meta name="robots" content="noindex,nofollow"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>
<meta http-equiv="X-UA Compatible" control="IE=edge,chrome=1" />
<link rel="stylesheet" type="text/css" href="css/table.css" />
<script type="text/javascript" src="//code.jquery.com/jquery.min.js"></script>
<!-- 자동 갱신 스크립트 include -->
<script>
var timerID;

$(document).ready(function () {
    $('#execute').on('click',function(e){
        e.preventDefault();
        updateData();
    });
    $('#stop').on('click',function(e){
        e.preventDefault();
        clearTimeout(timerID); // 타이머 중지
        $('#showtime').html('');
    });   

});

function updateData(){
    $.ajax({
      url: "getserver.php",
      type:"post",
      cache : false,
      success: function(data){ // getserver.php 파일에서 echo 결과값이 data 임
       $('#showtime').html(data);
      }
    });
    timerID = setTimeout("updateData()", 2000); // 2초 단위로 갱신 처리
}
</script>

</head>

<body>
<p>time : <span id="
showtime"></span></p>
<input type="button" id="execute" value="실행" />
<input type="button" id="stop" value="중지" />
</body>
</html>


==== getserver.php ===
<?php
$time = date("H:m:s");
echo $time;
?>


ajax 는 비동기 Javascript 와 XML를 말한다.

ajax 를 사용하면 페이지 이동 없이 전체 HTML 이 아닌, XML 이나 JSON형식으로 구성된 새로운 데이터를 XMLHttpRequest 객체를 통해 받아온다.

블로그 이미지

Link2Me

,
728x90

MySQL 에서 정규식을 접목하여 검색하면 OR 검색조건 작성이 심플해진다.


<?php
$sql="select * from test where eng regexp '가|나|다|라'";
// 정규식을 접목한 or 검색
$s1="가";
$s2="나";
$s3="다";
$s4="라";
$sql = "select * from test where eng regexp '".$s1."|".$s2."|".$s3."|".$s4."' ";
echo $sql;
?>


select * from test where eng regexp 'do?'; // ?는 마지막 글자가 0 또는 1개 일치 : d 또는 do가 일치
select * from test where name regexp '^..$'; // 시작부터 2글자로 끝나는 이름을 찾아라.

select * from test where eng regexp '^I'; // 첫글자가 I로 시작되는 문장을 찾아라

select * from test where eng regexp '^I\''; // 첫글자가 I'로 시작되는 문장을 찾아라


SELECT * FROM test WHERE col1 REGEXP '^[0-9]+$'; // 숫자로만 된 것을 찾아라

SELECT * FROM test WHERE col1 REGEXP '^[[:digit:]]+$'; // 숫자로만 된 것을 찾아라


SELECT * FROM test WHERE col1 NOT REGEXP '^[0-9]+$'; // 숫자로만 된 것을 제외하고 찾아라

SELECT * FROM test WHERE length(col1) > 0 and col1 NOT REGEXP '^[0-9]+$'; // 숫자 제외하고 찾아라


SELECT * FROM test WHERE col1 REGEXP '[0-9]+'; // 숫자와 문자를 포함하는 것을 찾아라






'SQL' 카테고리의 다른 글

Toad for MySQL - Database Diagram  (0) 2017.06.02
[강좌] 한방에 개념잡는 SQL 조인  (0) 2017.02.26
MySQL 컬럼 순서 바꾸기  (0) 2016.12.10
[Oracle] PL/SQL  (0) 2016.11.24
[MySQL] 테이블 스키마 설계 고려사항  (0) 2016.11.19
블로그 이미지

Link2Me

,