[SSL] [letsencrypt] [certbot] 와일드카드 인증서 발급하기

1. 환경 
ubuntu 20.x 
nginx

2. 설치 
apt-get install letsencrypt -y 

3. 인증서 발급 
; example.com 도메인에 대해 와일드카드 인증서를 발급받는다.
certbot certonly --manual -d *.example.com -d example.com --preferred-challenges dns 
; 메일주소 입력 
; 동의 Y
; 동의 Y ... 
; TXT 삽입문구 : DNS 설정에 추가 
; TXT 삽입문구 : DNS 설정에 추가 (TXT가 2개임) 
; 잠시 시간 대기 후 Enter [이때 Enter 치기 전에 네임서버에서 DNS 정보를 변경해야 함]
; 발급 완료 
; 발급위치 : /etc/letsencrypt/live/ 

4. 인증서 설치
; 가상호스트별로 된 설정파일에 SSL 설정을 추가한다. 
vim /etc/nginx/site-enabled/www.example.com

server {
        listen 80;
        listen [::]:80;

        # SSL configuration
        #
        listen 443 ssl;
        listen [::]:443 ssl;

        ssl_certificate         /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key     /etc/letsencrypt/live/example.com/privkey.pem;

5. nginx 재시작
service nginx restart
; 실행이 안되면 웹로그 등을 열어본다.


[javascript] [aniView] 애니매이션 구현하기

// URL :
https://jjcosgrove.github.io/jquery-aniview/

// 라이브러리 삽입
< script src="https://unpkg.com/jquery-aniview/dist/jquery.aniview.js">< / script >

// 또는 CORS 대응코드
< script src="https://unpkg.com/jquery-aniview@1.0.3/dist/jquery.aniview.js" integrity="sha384-uvboBeyPkVGldyoicVJST1JEAbxI2W0lG2fFOyGvahZrC4jWiv0vmryxw9NXIEn6" crossorigin="anonymous">< /script >

// 실행
$('.aniview').AniView();

// 옵션과 함께 실행
var options = {
animateClass: 'animated',
animateThreshold: 100,
scrollPollInterval: 50
}
$('.aniview').AniView(options);

// 태그에 적용하기 (v3)
< div class="aniview" data-av-animation="slideInRight">< /div>

// 태그에 적용하기 (v4)
< div class="aniview" data-av-animation="animate__jackInTheBox">< /div>

[javascript] [aos] 애니매이션 효과 적용하기

// 라이브러리 삽입
< link rel="stylesheet" href="https://unpkg.com/aos@next/dist/aos.css" />
< script src="https://unpkg.com/aos@next/dist/aos.js">< /script>

// 실행
AOS.init();

/* 위쪽으로 페이드 효과 */
< div data-aos="fade-up">< /div>

/* 아래쪽으로 페이드 효과 */
< div data-aos="fade-down">< /div>

/* 오른쪽으로 페이드 효과 */
< div data-aos="fade-right">< /div>

/* 왼쪽으로 페이드 효과 */
< div data-aos="fade-left">< /div>

/* 왼쪽으로 플립 효과 */
< div data-aos="flip-left">< /div>

/* 오른쪽으로 플립 효과 */
< div data-aos="flip-right">< /div>

/* 위쪽으로 플립 효과 */
< div data-aos="flip-up">< /div>

/* 아래쪽으로 플립 효과 */
< div data-aos="flip-down">< /div>

/* 줌 효과 */
< div data-aos="zoom-in">< /div>

[엑셀] 표시형식에 조건문 넣기

셀의 값은 다음과 같다.
0
1
2
3
0
0

원하는 것 : 값이 1 이상인 경우에 "day 1"로 표시될 것.

표시형식 넣기 : 
사용자지정 표시형식에서

[>0]"day" ##;

여러 조건의 순차적 지정도 가능하다.

[>=90]"수";[>=80]"우";"기타";

[jquery-ui] [bootstrap] datepicker와 input-group 사이의 z-index 문제

.input-group과 date-picker 사이에 z-index 이슈가 있음
date-picker가 input-group보다 아래에 위치하는 문제.
해결책은 .ui-datepicker에 z-index를 지정하면 된다.
	$('.input-date').datepicker({
        beforeShow: function(){
            setTimeout(function(){
                $('.ui-datepicker').css('z-index', 100);
            }, 0);
        }
    });

[CSS] 개발중에 알림, 오류, 디버그 등을 표출하는 디자인

.todo { position:relative; border:1px solid #8e2225; background:#fcf1f1; padding:10px 10px 5px 15px; font-size:13px; line-height:18px; font-family:'Arial','맑은고딕'; margin:25px 0 15px; }
.todo::before { position:absolute; display:block; content:'TODO'; top:-12px; left:5px; background:#8e2225; z-index:2; color:#fff; font-size:12px; line-height:18px; padding:0 6px; }
오늘의 할일은 ......

[CSS] <li>의 marker와 텍스트 간격 조절하기

<ul>
    <li>리스트 : 현재의 SQL문에 조건 추가 (상태처리값에 따른 구분 필요함)</li>
    <li>삭제 : 개별삭제, 선택삭제, 전체삭제</li>
    <li>견적요청 작성 : 페이지 이동 UI</li>
</ul>

<style>
    ul { padding-left:15px; list-style-position:outside; }
    li { list-style-type:disc; padding-left:-5px; }
</style>
padding-left:-5px; 이 li의 marker와 텍스트 사이의 간격을 줄여준다. 
단 이때 list-style-position:outside; 로 디자인되어야 한다.

[PHP] 정규식으로 태그 추출하기

그누보드 스킨을 수정하다가 생성한 코드
# iframe 태그를 추출한다.
//preg_match_all("/(<(iframe+)[^>]*>)(.*?)(<\/\\2>)/", $wr_content, $matches);
preg_match_all("/(<(iframe+)([^>]*)>)(.*?)(<\/(iframe)>)/", $wr_content, $matches);

if(is_array($matches[3]) == true && count($matches[3]) > 0) {
	// 태그가 있음
} else {
	// 태그가 없음
}

# 추출한 결과를 확인
print_r2($matches);

[PHP] 유니코드 한글 단어를 첫글자(초성)를 기준으로 가, 나, 다, ... 분류로 나누기

# 한글단어의 초성을 기준으로 가,나,다로 구분한다. [사용처 : 단어사전 등의 색인 검색]
if( ! function_exists('check_unicode_ord')) {

    # 단어의 초성을 기준으로 가/나/다 구분하는 함수
    function check_unicode_ord($string) {
        $h = unicode_ord($string);
        if($h >= 44032 && $h <= 45207) return "가";
        if($h >= 45208 && $h <= 45795) return "나";
        if($h >= 45796 && $h <= 46971) return "다";
        if($h >= 46972 && $h <= 47559) return "라";
        if($h >= 47560 && $h <= 48147) return "마";
        if($h >= 48148 && $h <= 49323) return "바";
        if($h >= 49324 && $h <= 50499) return "사";
        if($h >= 50500 && $h <= 51087) return "아";
        if($h >= 51088 && $h <= 52263) return "자";
        if($h >= 52264 && $h <= 52851) return "차";
        if($h >= 52852 && $h <= 53439) return "카";
        if($h >= 53440 && $h <= 54027) return "타";
        if($h >= 54028 && $h <= 54615) return "파";
        if($h >= 54616 && $h <= 55203) return "하";
        return "기타";
    }

    function unicode_ord($string) {
        $h = ord($string{0});
        if ($h <= 0x7F) {
            return $h;
        } else if ($h < 0xC2) {
            return false;
        } else if ($h <= 0xDF) {
            return ($h & 0x1F) << 6 | (ord($string{1}) & 0x3F);
        } else if ($h <= 0xEF) {
            return ($h & 0x0F) << 12 | (ord($string{1}) & 0x3F) << 6 | (ord($string{2}) & 0x3F);
        } else if ($h <= 0xF4) {
            return ($h & 0x0F) << 18 | (ord($string{1}) & 0x3F) << 12 | (ord($string{2}) & 0x3F) << 6 | (ord($string{3}) & 0x3F);
        } else {
            return false;
        }
    }

}
사용방법
$kr_key = check_unicode_ord($string);
// '도라지' => '다'
// '백화점' => '바'

[css] [css selector] :nth-child 사용하기

<style type="text/css">
ul.test li { display:block; width:40px; height:40px; float:left; margin:0 15px 15px 0; }
ul.test li:nth-child(1) { background:#ff0; } /* 지정한 1개만 */
ul.test li:nth-child(3n+1) { border:1px solid #f00; } /* 규칙적으로 (3개마다) */
ul.test li:nth-child(-n+5) { color:blue; font-weight:bold; } /* 앞에서부터 계산(~ 5) */
ul.test li:nth-child(n+17) { color:red; font-weight:bold; } /* 뒤에서부터 계산(18 ~) */
ul.test li:nth-child(n+11):nth-child(-n+15) { background:#6ff; } /* 범위로 계산(11 ~ 15) */
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

:nth-child(odd) 홀수

:nth-child(even) 짝수

:nth-last-child() 뒤에서부터 계산한다.

[php] [mysql] SET 타입과 비트연산 사용하기

mysql의 SET 타입은 여러개의 값을 한번에 가질 수 있는 데이터 타입이다.

예를 들어 [관심분야 : A, B, C, D, E, F, ...] 가 있을 때 (복수선택 가능)
각각을 개별 칼럼에 저장하는 것보다는
하나의 칼럼에 합쳐서 저장하는 것이 검색기능에서 월등히 좋다.

DB에 저장할 경우에는 정수값을 할당하거나 텍스트 'A,C,E' 를 할당할 수 있다.
A = 1
A, B = 1 + 2 = 3
A, B, C = 1 + 2 + 4 = 7

이 값들은 결국 2의 제곱수 즉 bit 값이 된다.

SQL 질의문 예시 : 단순히 질의하는 경우

SELECT col_set FROM tbl_name;
// col_set = "A,B,C"; (문자열)

SELECT col_set+0 AS col_dec FROM tbl_name;
// col_dec = 7; (십진수)

SQL 질의문 예시 : 비트연산으로 조건검색을 하는 경우

SELECT * FROM tbl_name WHERE col_set & 1 > 0; // A를 포함한 경우
SELECT * FROM tbl_name WHERE col_set & 2 > 0; // B를 포함한 경우
SELECT * FROM tbl_name WHERE col_set & 4 > 0; // C를 포함한 경우
SELECT * FROM tbl_name WHERE col_set & 7 > 0; // A+B+C를 포함한 경우

PHP에서 사용하는 경우

if( (7 & 1) > 0 ) // 결과 true
if( (7 & 2) > 0 ) // 결과 true
if( (7 & 8) > 0 ) // 결과 false

* 주의 : 비트연산(&)을 반드시 괄호로 감싸줘야 함


관심분야 선택 기능을 위한 변수 생성

$col_array = array(
    1 => 'A',
    2 => 'B',
    4 => 'C',
    8 => 'D',
    16 => 'E',
    .... (2의 제곱수로 증가함)
);

# 관심분야를 선택하는 화면
foreach($col_array as $key=>$val) {
    if( ($db_value_dec & $key) > 0 ) {
        // 선택된 상태임
    }
}





[swiper] 슬라이드에 이미지 및 텍스트 올리기


<div id="banner" class="swiper-container">
    <ul class="swiper-wrapper">
        <li class="swiper-slide" data-left="0"><img src="/images/main/visual01.jpg" alt=""></li>
        <li class="swiper-slide" data-left="0"><img src="/images/main/visual01.jpg" alt=""></li>
        <li class="swiper-slide" data-left="0"><img src="/images/main/visual01.jpg" alt=""></li>
    </ul>
    <div class="swiper-pagination"></div>
</div>

$(document).ready(function(){
    //initialize swiper when document ready
    var mySwiper = new Swiper ('.swiper-container', {
        effect: 'fade',
        fadeEffect: { crossFade:false, },
        speed: 2500,
        autoplay: true,
        loop: true,
        navigation: {
            nextEl: '.swiper-button-next',
            prevEl: '.swiper-button-prev',
        },
        pagination: {
            el: '.swiper-container .swiper-pagination',
            clickable: true,
        },
    });
});

/* 슬라이드 가로크기에 반응. 이미지를 자르고, 슬라이드의 중앙에 위치시킴 */
.swiper-slide { position:relative; width:100%; height:592px; overflow:hidden; }
.swiper-slide img { position:relative; display:block; width:1920px; height:592px; left:50%; margin-left:-960px; transform:scale(1.2,1.2); transition:all 0.5s; max-width:2000px; }
.swiper-slide.swiper-slide-active img { transform:scale(1.0,1.0); transition:all 1s; }

슬라이드가 1920px보다 작은 경우에는 이미지를 슬라이드의 가로 중앙에 위치시킨다. left:50%; margin-left:-960px;

이미지를 1.2배 확대한 크기로 생성하고,
슬라이드가 active 상태인 경우만 원본 크기로 변경시킨다.
transform:scale(1.2,1.2); transition:all 0.5s;
transform:scale(1.0,1.0); transition:all 1s;

[jquery] 부모창의 엘리먼트에 접근하기

프레임(iframe)인 경우
$("#id", parent.document).val(text); // 2가지 모두 가능함
window.parent.$("#id").val(text);

팝업인 경우
$("#id", opner.document).val(text);
window.opner.$("#id").val(text);

[PHP] 디렉토리가 존재하는지, 쓰기권한이 있는지 미리 검사

1. 디렉토리가 있는지 검사한다.

2. 디렉토리에 쓰기권한이 있는지 검사한다.

$dir = "/home/www/dir/upload";
if(is_dir($dir)==false) {
    echo "디렉토리가 존재하지 않습니다."; exit;
}
if(is_writable($dir)==false) {
    echo "디렉토리에 쓰기권한이 없습니다."; exit
}

인스타 모음.link

인스타 보물창고 모음.link

https://instagram.com/rh_ab/
https://instagram.com/dorosiwa
https://instagram.com/blank9_yerim
https://instagram.com/cxxsomi
https://instagram.com/still_need
https://instagram.com/woohye0n
https://instagram.com/zennyrt
https://instagram.com/inkyung97
https://instagram.com/pyoappl
https://instagram.com/_bitnara_
https://instagram.com/22carats
https://instagram.com/luckymizili
https://instagram.com/xxmintmintyxx
https://instagram.com/aevely____
https://instagram.com/sm._.me
https://instagram.com/candyseul
https://instagram.com/lovelyjoohee
https://instagram.com/163_9cm
https://instagram.com/ji_m._.o
https://instagram.com/seojin_ban
https://instagram.com/mandoo.unnie
https://instagram.com/luv_laboum
https://instagram.com/lloveeely
https://instagram.com/aloha_hey.ju
https://instagram.com/dg8dg
https://instagram.com/helenwoooo
https://instagram.com/yul_______mom
https://instagram.com/ohttomom
https://instagram.com/pkjy1003
https://instagram.com/kamangeyes
https://instagram.com/sojuphoto
https://instagram.com/___angevivi
https://instagram.com/sophiemudd
https://instagram.com/yi_seul_2
https://instagram.com/cxxsomi
https://instagram.com/dohee0713
https://instagram.com/hyo0ni
https://instagram.com/xxmintmintyxx
https://instagram.com/hello__rina
https://instagram.com/saint_2005
https://instagram.com/dg8dg
https://instagram.com/kairos.foto
https://instagram.com/nabiang_com
https://www.instagram.com/mochi___pp/
https://www.instagram.com/ryusemmm_/
https://www.instagram.com/kyungin_c/
https://www.instagram.com/_hotbin/
https://www.instagram.com/_97.3.29/
https://www.instagram.com/juy3050/
https://www.instagram.com/e__seo__e/

[CSS] 연속된 div, li 등에 테두리 보이기 (border 겹치기 문제를 해결)

box-shadow: h-offset(오른쪽) v-offset(아래쪽) blur spread color;
box-shadow:1px 0 0 0 #aaaaaa; [오른쪽 1px 효과)
box-shadow:0 1px 0 0 #aaaaaa; [아래쪽 1px 효과)
inset 값이 주어진 경우는 안쪽, 즉 반대가 된다.
box-shadow:1px 0 0 0 #aaaaaa inset; [왼쪽 1px 효과)
box-shadow:0 1px 0 0 #aaaaaa inset; [윗쪽 1px 효과)


<style type="text/css">
#block-wrap { width:600px; }
#block-wrap * { box-sizing:border-box; }
ul.menu { margin:0; padding:0; }
ul.menu li { list-style:none; float:left; box-shadow:1px 0 0 0 #aaa, 0 1px 0 0 #aaa, 1px 0 0 0 #aaa inset, 0 1px 0 0 #aaa inset, 1px 1px 0 0 #aaa; }
ul.menu li.on { background:#1772a8; }
ul.menu li a { display:block; padding:10px 30px; text-decoration:none; color:#000000; }
ul.menu li.on a { color:#ffffff; }
</style>

<div id="block-wrap">
    <ul class="menu">
        <li><a href="#">전체 보기</a></li>
        <li class="on"><a href="#" class="on">대한민국</a></li>
        <li><a href="#">미국</a></li>
        <li><a href="#">중국</a></li>
        <li><a href="#">일본</a></li>
        <li><a href="#">러시아</a></li>
        <li><a href="#">대한민국</a></li>
        <li><a href="#">미국</a></li>
        <li><a href="#">중국</a></li>
        <li><a href="#">일본</a></li>
        <li><a href="#">러시아</a></li>
        <li><a href="#">대한민국</a></li>
        <li><a href="#">미국</a></li>
        <li><a href="#">중국</a></li>
        <li><a href="#">일본</a></li>
        <li><a href="#">러시아</a></li>
    </ul>
</div>

추가 li에 background 색상을 지정하면 top과 left에 boder 효과가 사라진다.
이 경우는 li에 padding:1px 0 0 1px 주면 해결

[jQuery][CSS] 간단한 모달Modal 열기


<div id="js-intro">
    <div class="inner">모달창</div>
</div>

#js-intro { display:none; position:absolute; z-index:99998; top:0; left:0; background:rgba(0,0,0,0.5); text-align:center; }
#js-intro .inner { display:none; position:relative; z-index:99999; width:400px; height:200px; margin:0 auto; text-align:center; }

$(document).ready(function(){
    $("#js-intro").appendTo("body");
    //화면의 높이와 너비를 구한다.
    var maskHeight = $(document).height();
    var maskWidth = $(window).width();
    var winHeight = $(window).height(); // inner 위치설정용

    //마스크의 높이와 너비를 화면 것으로 만들어 전체 화면을 채운다.
    $('#js-intro').css({'width':maskWidth, 'height':maskHeight});

    //애니메이션 효과 - 천천히 나타남
    $('#js-intro').fadeIn(800, function(){
        $('#js-intro .inner').fadeIn(1000).css({'top':(winHeight/2)+'px', 'transform':'translateY(-50%)'});
    });

    // 닫기
    $("#js-intro .inner").click(function(){
        $('#js-intro').hide();
    });
});
모달창 : 클릭하면 닫힙니다.

[CSS] 세로 가운데 정렬 Vertical-align:center


<div id="box">
    <div id="text">가운데 정렬</div>
</div>

#box { width:400px; height:300px; background:#f0e0e0; }
#text { position:relative; top:50%; transform:translateY(-50%); text-align:center; }
가운데 정렬

[jQuery] [swiper] 스와이프 이미지 슬라이드


<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.3.3/css/swiper.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.3.3/js/swiper.min.js"></script>

    <div class="swiper-container">

        <ul class="swiper-wrapper">

            <li class="swiper-slide" style="background:url(/images/main/visual01.jpg) center center / cover no-repeat;" data-left="0"></li>
            <li class="swiper-slide" style="background:url(/images/main/visual03.jpg) center center / cover no-repeat;" data-left="1"></li>
            <li class="swiper-slide" style="background:url(/images/main/visual02.jpg) center center / cover no-repeat;" data-left="0"></li>
            <li class="swiper-slide" style="background:url(/images/main/visual04.jpg) center center / cover no-repeat;" data-left="1"></li>
            <li class="swiper-slide" style="background:url(/images/main/visual05.jpg) center center / cover no-repeat;" data-left="1"></li>
        </ul>

        <div class="swiper-pagination"></div>
        <!-- navigation buttons -->
        <div class="swiper-button-prev"></div>
        <div class="swiper-button-next"></div>

    </div>

    $(document).ready(function(){
        //initialize swiper when document ready
        var mySwiper = new Swiper ('.swiper-container', {
            // Optional parameters
            //direction: 'vertical',
            effect: 'fade',
            speed: 2500,
            crossEffect: { crossFade: true },
            autoplay: true,
            loop: true,
            navigation: {
                nextEl: '.swiper-button-next',
                prevEl: '.swiper-button-prev',
            },
            pagination: {
                el: '.swiper-container .swiper-pagination',
                clickable: true,
            },
            on: {
                init: function(){
                    //console.log("slide init");
                    //console.log(this.$wrapperEl[0]);
                    var slide = $(this.$wrapperEl[0]).find(".swiper-slide-active");
                    var bg = slide.data("left");
                    if(bg=="1") {
                        $("header").addClass("bg-white");
                    } else {
                        $("header").removeClass("bg-white");
                    }
                },
            },
        });

        mySwiper.on('slideChange', function(){
            //console.log("slide change");
            //console.log(mySwiper.realIndex);
            var r_idx = mySwiper.activeIndex;
            var slide = mySwiper.slides[r_idx];
            //console.log(mySwiper.$wrapperEl);
            //console.log($(slide));
            var bg = $(slide).data("left");
            //console.log("r_idx=" + r_idx + ", bg=" + bg + ", src=" + $(slide).css("background"));
            if(bg=="1") {
                $("header").addClass("bg-white");
            } else {
                $("header").removeClass("bg-white");
            }
        });
    });

단순히 슬라이드를 동작시키려면 아래와 같이 하면 된다.

    $(document).ready(function(){
        var mySwiper = new Swiper ('.swiper-container', {
            // Optional parameters
            //direction: 'vertical',
            effect: 'fade',
            speed: 2500,
            crossEffect: { crossFade: true },
            autoplay: true,
            loop: true,
            navigation: {
                nextEl: '.swiper-button-next',
                prevEl: '.swiper-button-prev',
            },
            pagination: {
                el: '.swiper-container .swiper-pagination',
                clickable: true,
            },
        });

    });

[mysql] INSERT NOT EXISTS 중복 방지 삽입

`hash` 칼럼이 중복된 경우 INSERT 하지 않는다.

INSERT INTO `data_test` (`name`, `hash`) 
SELECT * FROM (SELECT 'aaa','1') AS `TMP`
WHERE NOT EXISTS (
    SELECT `hash` FROM `data_test` WHERE `hash`='1'
) LIMIT 1

[SSL] [letsencrypt] [certbot] 와일드카드 인증서 발급하기

1. 환경   ubuntu 20.x  nginx 2. 설치   apt-get install letsencrypt -y  3. 인증서 발급   ; example.com 도메인에 대해 와일드카드 인증서를 발급받는다. certbot certonly --ma...