<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>coding_wizard.log</title>
        <link>https://velog.io/</link>
        <description>여러분들 삶에 한 획을 더하고 싶습니다. </description>
        <lastBuildDate>Tue, 27 Dec 2022 02:43:58 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>coding_wizard.log</title>
            <url>https://velog.velcdn.com/images/coding_wizard/profile/86ee7773-7795-48df-87d0-e6e5aa014cfc/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. coding_wizard.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/coding_wizard" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Java Spring Bulld Error - Gradle Repository]]></title>
            <link>https://velog.io/@coding_wizard/Java-Spring-Bulld-Error-Gradle-Repository</link>
            <guid>https://velog.io/@coding_wizard/Java-Spring-Bulld-Error-Gradle-Repository</guid>
            <pubDate>Tue, 27 Dec 2022 02:43:58 GMT</pubDate>
            <description><![CDATA[<p>원문 : <a href="https://ssons.tistory.com/61">https://ssons.tistory.com/61</a></p>
<p>build.gradle 설정 중 </p>
<pre><code class="language-yaml">repositories {
   mavenCentral();
}</code></pre>
<p>해당 부분에서 제대로 불러오지 못하는 경우가 있다.
이를 jcenter()로 교체해주면 정상적으로 동작!</p>
<pre><code class="language-yaml">repositories {
   jcenter();
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[김영한의 JPA 기본편 중 에러 해결편]]></title>
            <link>https://velog.io/@coding_wizard/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-JPA-%EA%B8%B0%EB%B3%B8%ED%8E%B8-%EC%A4%91-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%ED%8E%B8</link>
            <guid>https://velog.io/@coding_wizard/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-JPA-%EA%B8%B0%EB%B3%B8%ED%8E%B8-%EC%A4%91-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%ED%8E%B8</guid>
            <pubDate>Thu, 20 Oct 2022 17:58:47 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.h2database.com/">https://www.h2database.com/</a></p>
<p>만약 Gradle을 쓰고 싶다면 우선 스프링 없는 환경에서 하자! 
동일한 설정을 하는 방법이 너무 복잡하다. 기본편이 끝나고 활용편에선 Gradle을 쓰기 때문에 우선은 기본 자바에서 사용해 보자.</p>
<p><strong>persistence-unit name 설정 문제</strong>
<a href="https://www.inflearn.com/questions/15318">https://www.inflearn.com/questions/15318</a></p>
<blockquote>
<p><strong>[김영한]</strong>
안녕하세요 성건희님^^</p>
<p>다음 스프링 메뉴얼을 보시면</p>
</blockquote>
<p><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-use-traditional-persistence-xml">https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-use-traditional-persistence-xml</a></p>
<blockquote>
</blockquote>
<p>LocalEntityManagerFactoryBean을 새로 등록해야 하는데요^^; 복잡합니다.</p>
<blockquote>
</blockquote>
<p>우선 순수하게 스프링이 없는 환경에서 JPA를 한번 경험해보면, 스프링과 통합시에 JPA가 더 명확하게 이해가되실꺼에요^^!</p>
<hr>
<h2 id="h2-데이터-베이스-실행-오류-발생시">H2 데이터 베이스 실행 오류 발생시</h2>
<p>출처 : <a href="https://www.inflearn.com/course/ORM-JPA-Basic/unit/21684">https://www.inflearn.com/course/ORM-JPA-Basic/unit/21684</a>
처음 H2 데이터베이스를 실행했을 때 아래와 같은 오류가 발생하면 데이터베이스 파일을 생성하면 됩니다.
Database &quot;<del>/test&quot; not found, and IFEXISTS=true, so we cant auto-create it [90146-199]
데이터베이스 파일 생성 방법
<img src="https://velog.velcdn.com/images/coding_wizard/post/c725f906-b079-4d55-b9ab-39e9ad96239d/image.png" alt="">
위 이미지 처럼 JDBC URL에 jdbc:h2:</del>/test</p>
<p>라고 적어주시고 한번만 연결을 해주시면 데이터베이스 파일이 생성되면서 연결됩니다.</p>
<p>그리고 이후에는 jdbc:h2:tcp://localhost/~/test 로 접속해주세요.</p>
<p>(이미지 처럼 파일에 직접 접근하는 방식은 파일에 락이 걸려서 여러곳에서 접속을 못하는 문제가 있습니다.)</p>
<p>자 이렇게 해서 김영한님이 알려주신 방법대로 해도 되지 않는 사람들이 있을 것이다.
보통은 Windows 환경에서 그런경우가 많은데 생각보다 많은 사람들이 아래와 같은 방법으로 해결이 되고 있다.
<img src="https://velog.velcdn.com/images/coding_wizard/post/e4efa4ed-e724-44bd-8510-4709b7e8bd45/image.png" alt=""></p>
<blockquote>
<ol>
<li>윈도우 시스템 트레이 아이콘을 클릭하여 나온 창에서 동일하게 시도하는 것이다.</li>
</ol>
</blockquote>
<p>이게 뭔가 싶겠지만 가장 해결율이 높은 방식이다..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Error Gradle Script ‘/Home/Runner/Work/*/Gradlew’ Is Not Executable 문제 해결하기]]></title>
            <link>https://velog.io/@coding_wizard/Error-Gradle-Script-HomeRunnerWorkGradlew-Is-Not-Executable-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@coding_wizard/Error-Gradle-Script-HomeRunnerWorkGradlew-Is-Not-Executable-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 29 Aug 2022 05:50:18 GMT</pubDate>
            <description><![CDATA[<h2 id="github-actions-에러문">Github Actions 에러문</h2>
<blockquote>
<p>Error Gradle Script ‘/Home/Runner/Work/*/Gradlew’ Is Not Executable</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/coding_wizard/post/ae210728-f632-40e4-976e-f1d3eb21062c/image.png" alt=""></p>
<p>Github Action 파이프라인을 실행하려고 할 때 위 오류가 발생합니다.</p>
<h2 id="solution-1-preferred">Solution 1 (Preferred)</h2>
<blockquote>
<p>git update-index --chmod=+x gradlew</p>
</blockquote>
<p>VS 코드 또는 명령 프롬프트에서 chmod 명령을 실행하세요 
그 다음 소스 제어의 변경 사항을 확인하고 Github Action 파이프라인을 다시 실행해보세요!</p>
<h2 id="solution-2-대안">Solution 2 (대안)</h2>
<p>어떤 이유로든 소스 제어에 대해 변경할 수 없는 경우 추가 단계를 추가하여 파이프라인에서 직접 변경할 수 있습니다.</p>
<blockquote>
<pre><code class="language-yaml"></code></pre>
</blockquote>
<ul>
<li>name: Run chmod to make gradlew executable
run: chmod +x ./gradlew<pre><code></code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[개발 블로그의 난립, 그 속에서의 방황]]></title>
            <link>https://velog.io/@coding_wizard/%EA%B0%9C%EB%B0%9C-%EB%B8%94%EB%A1%9C%EA%B7%B8%EC%9D%98-%EB%82%9C%EB%A6%BD-%EA%B7%B8-%EC%86%8D%EC%97%90%EC%84%9C%EC%9D%98-%EB%B0%A9%ED%99%A9</link>
            <guid>https://velog.io/@coding_wizard/%EA%B0%9C%EB%B0%9C-%EB%B8%94%EB%A1%9C%EA%B7%B8%EC%9D%98-%EB%82%9C%EB%A6%BD-%EA%B7%B8-%EC%86%8D%EC%97%90%EC%84%9C%EC%9D%98-%EB%B0%A9%ED%99%A9</guid>
            <pubDate>Tue, 12 Jul 2022 02:23:51 GMT</pubDate>
            <description><![CDATA[<h3 id="오염되는-정보의-바다-선순환에서-악경화로">오염되는 정보의 바다. 선순환에서 악경화로</h3>
<p>입사 시 github 주소 뿐만 아니라 개발 블로그 주소를 적는 것이 일반화되어가고 개발자 구직 플랫폼에서 마저 블로그 주소를 적을 수 있도록 하고 있다. (선택) 그러다보니 중고등학교에서 조차 개발 블로그를 권장하고 그것이 입시의 스펙으로 설명하고 있으며 학부생과 현업자 할거 없이 모두에게 커다란 숙제가 되어 버린 것 같다.</p>
<p>정보의 바다를 만들고 그속에서 지속적인 정보 교류가 일어나는 것은 너무나도 좋은 일이다. 하지만, 이 바다는 너무나 현실적이여서 태평양의 문제와 똑같이 바다 쓰레기들이 넘쳐나고 있는게 실정이다. 정확하지 않은 내용들을 확인없이 그럴싸 하게 정리해서 포스팅하고 그것을 누군가 보고 또다시 재생산되는 기계적인 과정이 반복되고 있는 것이다. 중요한건 내용물을 채우고 블로그가 빵빵해 보이게 하는게 우선이 되고 있는 지금의 모습을 보며 우리는 또다시 길을 잃는다. 인터넷에서의 악순환은 경화를 의미하는 것이 아니라 악이 순환 될 뿐이다.</p>
<h3 id="선순환에서-악순환으로의-환승">선순환에서 악순환으로의 환승</h3>
<p>과거 진입장벽이 낮을 수록 부정확한 정보와 코드들이 난립하는 경향을 보이곤 했다. 민감한 이야기지만 많은 사람들이 공감하는게 제이쿼리이지 않을까? 지금도 여러 동작에 대해 제이쿼리로 검색해 보면 신기하고도 특이한 코드들을 많이 만나 볼 수 있으니 말이다. 물론 제이쿼리는 JS에 대한 깊은 이해 없이도 손쉽게 만들 수 있다는 장점으로 많은 사랑을 받았기 때문에 모르고 쓰는 경우가 더 많았다. 모르고도 쓸 수 있다는건 그만큼 강력했다는 말이니 이에 대해 곡해 하지 않았으면 좋겠다. 진입 장벽이 낮다는 것은 그만큼 적은 이해로 시작이 가능하다는 것이다. 그만큼 저품질 정보를 양산하고 확산되기 쉽다. </p>
<p>현재 수많은 프레임워크들이 나오며 많은 껍질들이 생기고 있다. 속깊은 이야기 까지 알지 못하더라도 우리는 아주 손쉽게 많은 작업들을 할 수 있다. 이것이 우리가 추구하고자 했던 방향이였기 때문에 결코 틀리지 않다. 하지만 IT의 트렌디함이 문제다. 매일의 git commit으로 풍성하게 자란 잔디를 만들고, 수많은 분야의 정보 기재하며 포스팅 개수 높이는 것이 열정의 척도가 되어버린 지금, 우리는 올바른 방향으로 나아가고 있을까? 한 번쯤 의문이 든다. 마음이 앞서는 내게 어머님이 한 마디 해주셨던 말이 있다. </p>
<blockquote>
<p>*<em>&#39;물이 끓기도 전에 넘친다&#39; *</em></p>
</blockquote>
<p>과정과 결과가 역행하고 주객이 전도될 때 항상 속이 비게 된다. </p>
<p>잘못된 정보의 확산으로 학습자는 잘못된 정보를 접하기 쉽고 잘못된 지식으로 무분별한 정보들을 학습하며 나도 모르게 악순환의 확산자로 활동할 수 있다. 무엇의 문제 일까? 곰곰히 생각해보면 참 쉽지 않은 문제 이구나 라는 것이 느껴진다. 과정은 결과로 입증해야하고 결과를 평가하는 사회 구조상 정량 평가 기준에 신경쓰는 우리가 세균이 될 수는 없다. 우리는 모두 백혈구다. 사회는 더욱 빠르게 요구하고 이제는 우리의 SNS 활동 마저 평가 지표가 되었다. </p>
<blockquote>
<p>검사 받기 위한 &#39;제출용 일기장&#39;을 언제까지 써야 하는 걸까? </p>
</blockquote>
<p>나만의 이야기를 일기장에 쓰고 싶지만 검사용 일기장에 지쳐가고 있다. 염증 가득한 선순환 속에 우리는 모두 염증을 느낀다. </p>
<p>바다 위를 표류하는 나는, 바다 쓰레기와 다를까?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹에이전시 CEO 출신의 개발자 첫 직장 구하기]]></title>
            <link>https://velog.io/@coding_wizard/%EC%9B%B9%EC%97%90%EC%9D%B4%EC%A0%84%EC%8B%9C-CEO-%EC%B6%9C%EC%8B%A0%EC%9D%98-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%B2%AB-%EC%A7%81%EC%9E%A5-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@coding_wizard/%EC%9B%B9%EC%97%90%EC%9D%B4%EC%A0%84%EC%8B%9C-CEO-%EC%B6%9C%EC%8B%A0%EC%9D%98-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%B2%AB-%EC%A7%81%EC%9E%A5-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 02 Jul 2022 10:45:06 GMT</pubDate>
            <description><![CDATA[<h2 id="우리는-어떤-거미인가">우리는 어떤 거미인가?</h2>
<p>2019년부터 2022년 까지 웹에이전시 대표이자 선임개발자로 3년간 근무하였습니다. 
프로젝트 메니지먼트와 PHP를 활용한 웹사이트 개발이 주요 업무였죠. 그 외에도 세무, 회계, HR, 직원 교육, 마케팅, 클라이언트 미팅 부터 프로젝트 전반에 걸친 사항들에 대해 소통하고 알아야 했습니다. 나무보다 숲을 봐야하는 업무는 개인의 성장과는 반대로 개발자로서의 성장을 더디게 만들었습니다. </p>
<p>회사는 거미줄형 인재를 그리 선호하지만은 않습니다. 이것저것 안다는 것은 반대로 무엇 하나 제대로 하지 못한다는 것이 될 수 있으니까요. 큰 회사일 수록 &#39;하나&#39;를 &#39;확실히&#39; 전문적으로 하기를 원할 겁니다. 각 포지션에 맞는 책임감 넘치는 좋은 직원이 있을 테니까요. 2010년도 중후반 &#39;통섭&#39;과 &#39;융복합&#39;이라는 키워드가 한창 떠올랐습니다. 이제는 그것이 당연시 되어 오히려 &#39;통섭&#39;이라는 단어를 잘 사용하지 않는 것 같습니다. 한가지를 확실히 하는 &#39;사다리형&#39; 인재와 두루두루 널리 아는 &#39;거미줄(web)&#39;형 인재 중 후자를 선호한다는 말에 공감하면서도 이를 절대 착각해서는 안되는 점이 있습니다. 거미줄에 거미가 없으면 아무 의미가 없다는 점입니다. 결국 나의 전문성을 기반으로 다른 것 까지 연결되어 이해하고 생각할 수 있는 능력. 그것이 현대 사회의 보편적 인재상이 아닌가 싶습니다. </p>
<p>저는 경험이 많습니다. 생각보다 많은 지식도 가지고 있습니다. 살다보니 &#39;그걸 어디다 쓰냐&#39;라는 지식과 경험들은 모두 기회가 되어 돌아왔습니다. 지식과 경험은 기회를 붙잡는 거미줄과 같습니다. 넓으면 넓을 수록 더 많은 기회를 포착할 수 있게 됩니다. 기회라는건 운입니다. 확률적인 부분이 강하죠. 그래서 저는 이 확률을 높이는데 많은 시간을 투자했습니다. 기회가 많아지고 그 기회를 바탕으로 경험이 많아지고 그러한 궤적이 또다시 기회가 되어 돌아오는 이 사회의 선순환을 경험할 수 있었습니다. 이렇게 즐거운 일이 어디있겠습니까? </p>
<p>하지만, 기회는 그저 던져질 뿐입니다. 그 기회를 잡는건 온전히 개인의 역량이고 거미의 몫이죠. 
우리가 게임을 하다보면 시간의 변화에 따라 달라지는게 있습니다. 바로 &#39;난이도&#39;입니다. 성장의 시간이 주어진 만큼 사회는 우리를 기대하게 되고 이 기대감을 충족하지 못할 때 우리는 실망감을 안겨주게되고 이 기대감만큼이 바로 사회에서 요구하는 요구치가 되게 됩니다. 이것이 우리가 객관적인 평가를 통해 과거에 머물러 있지는 않은지 되돌아봐야하는 이유입니다. </p>
<br>

<h2 id="회사가-바라는-나">회사가 바라는 &#39;나&#39;</h2>
<p>첫 면접에서 첫 직장을 구하게 되었습니다. 제 인생에서 이보다 더 의미있는 일이 있을까요 
반대로 정량평가가 힘든 저를 높이 평가해준 것에 감사하면서도 어떠한 기대감이 있을지 참 많은 고민을 하게 됩니다. 앞으로 실제 출근까지 한달도 채 남지 않았습니다. 이 기간동안 무엇을 채워 가야할지 고민스럽습니다.</p>
<blockquote>
<ol>
<li>면접 당시 명확히 설명하지 못했던 부분들에 대한 학습</li>
<li>Java Spring 패스트캠퍼스 강의 완강</li>
<li>1,2번에 나온 지식 체득</li>
<li>디자인패턴</li>
<li>SOLID 원칙 (객체 지향 설계)</li>
<li>Git과 Git Flow</li>
</ol>
</blockquote>
<p>사람을 중시하고 감정을 존중하는 것은 약속드릴 수 있으나 실무 스킬에 아쉬움이 남습니다. 이런 점들을 최대한 줄이고 회사를 다니며 성장 할 수 있을 것이라는 인식은 꼭 심어드리고 싶습니다. </p>
<p>마지막으로 회사에 대한 이해입니다. 회사의 전사적 목표와 지향점 그리고 지금까지 걸어온 궤적에 대해 알아보며 회사에 대한 이해를 높이려 합니다. &#39;주어진일만 하는건 쉽다&#39; 말하시는 분들이 계시지만 주어진 일을 파악하고 성공적으로 끝맺음 짓는 능력은 정말 대단한 것 입니다. 업무를 함에 있어 제가 가장 뿌듯해 할 때는 <strong>예상한 결과물 보다 더 높은 수준의 결과물을 만들어 낼 때</strong> 입니다. 열심히 성장해서 저의 성장과 기여가 회사의 성장이 될 수 있도록 최선을 다해 보겠습니다. 이러한 성장 지표가 제 커리어 그 자체가 될 수 있도록.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] 배열(array)을 데이터베이스에 저장하는 방법]]></title>
            <link>https://velog.io/@coding_wizard/PHP-%EB%B0%B0%EC%97%B4array%EC%9D%84-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@coding_wizard/PHP-%EB%B0%B0%EC%97%B4array%EC%9D%84-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sat, 25 Jun 2022 11:51:28 GMT</pubDate>
            <description><![CDATA[<p>PHP 배열을 데이터베이스에 저장하는 방법으로는 아래 세가지가 자주 이용됩니다.</p>
<h2 id="1-implode를-사용한-값-분할-방법">1) <a href="https://www.php.net/manual/en/function.implode.php">implode</a>를 사용한 값 분할 방법</h2>
<blockquote>
<pre><code class="language-php">$arrayString = implode(&quot;,&quot;, $myArray);</code></pre>
</blockquote>
<pre><code>
저장 후 **explode**를 이용해 다시 변환할 수 있습니다.

하지만 이 방법은 $MyArray 안에  **&quot;,&quot;**값이 존재할 경우 예상치 못한 결과가 발생될 수 있습니다.

&lt;br&gt;

## 2) [json_encode](http://php.net/manual/en/function.json-encode.php)을 이용한 JSON 인코딩 방법
&gt;````php
$arrayString = json_encode($myArray);</code></pre><p><strong>json_decode</strong>을 이용해 배열을 다시 디코딩 할 수 있고, 앞서 사용한 implode 방법보다 훨씬 안전합니다. </p>
<p>특히 JSON으로 데이터를 주고 받는 경우가 많기 때문에 많이 사용되는 방식입니다.</p>
<br>


<h2 id="3-배열-직렬화">3) 배열 직렬화</h2>
<blockquote>
<pre><code class="language-php">$arrayString = serialize($myArray);</code></pre>
</blockquote>
<p>````</p>
<p>문자열을 다시 배열로 변환하려면 <strong>unerialize</strong>을 사용하면 됩니다.</p>
<p>PHP 배열을 저장하는 매우 간편한 방법이지만 JSON과 달리 PHP로만 읽을 수 있다는 점이 단점입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[wordpress] 상위페이지에 따른 하위페이지 템플릿 불러오기]]></title>
            <link>https://velog.io/@coding_wizard/wordpress-%EC%83%81%EC%9C%84%ED%8E%98%EC%9D%B4%EC%A7%80%EC%97%90-%EB%94%B0%EB%A5%B8-%ED%95%98%EC%9C%84%ED%8E%98%EC%9D%B4%EC%A7%80-%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0</link>
            <guid>https://velog.io/@coding_wizard/wordpress-%EC%83%81%EC%9C%84%ED%8E%98%EC%9D%B4%EC%A7%80%EC%97%90-%EB%94%B0%EB%A5%B8-%ED%95%98%EC%9C%84%ED%8E%98%EC%9D%B4%EC%A7%80-%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0</guid>
            <pubDate>Sat, 25 Jun 2022 11:33:53 GMT</pubDate>
            <description><![CDATA[<p>Wordpress의 Custom Theme를 만들다 보면 몇몇 답답함들이 있다.</p>
<p>그 중 하나는 page-{slug}.php와 같이 페이지에 대한 테마 파일을 연결할 때 항상 최상위 디렉토리에 존재해야 한다는 점이다. 하위 디렉토리에 존재하게 될 경우 Wordpress는 자동으로 찾아주지 못하기 때문에 이를 위해 여러가지를 조합해 특별힌 function을 만들어 사용하기도 한다. 하지만.. 이 마저도 각각의 맹점들을 가지고 있어 특별히 권장되는 사항은 아니다. </p>
<p>페이지에 대해 상위 페이지를 줄경우 domain.co.kr/parent/child/와 같이 URL을 설정할 수 있다.
그럼에도 슬러그는 child이기에 wordpress는 최상위 디렉토리에서 page-child.php를 찾게 된다. </p>
<p>이때 우리가 원하는 것은 theme_name/parent/page-child.php 파일로 연결하는 것이고 이에 대한 방법을 본 페이지를 통해 기술하고자 한다. 이는 필자가 가장 오랫동안 답답함을 느껴온 장벽이였고 내 손에서 탄생한 수많은 프로젝트들의 오점이였기 때문이다. </p>
<p><br><br></p>
<hr>
<p>어투가 바뀌었지만 신경쓰지 않아 주셨으면 합니다. 
우선 워드프레스의 템플릿 파일 탐색 순서에 대한 이해가 필요합니다.</p>
<h2 id="템플릿-계층-구조-내의-페이지-템플릿">템플릿 계층 구조 내의 페이지 템플릿</h2>
<p>클라이언트가 웹 사이트를 탐색하면 WordPress는 해당 페이지를 렌더링하는 데 사용할 템플릿을 선택합니다. WordPress는 다음 순서로 템플릿 파일을 찾습니다.</p>
<blockquote>
<ol>
<li><strong>Page Template</strong> —  페이지에 사용자 지정 템플릿이 할당된 경우 WordPress는 해당 파일을 찾아 찾은 경우 이를 사용합니다.</li>
<li><strong>page-{slug}.php</strong> —  사용자 지정 템플릿이 할당되지 않은 경우 WordPress는 페이지의 슬러그가 포함된 특수 템플릿을 찾아 사용합니다.</li>
<li><strong>page-{id}.php</strong> —  페이지의 슬러그를 포함하는 특수 템플릿을 찾을 수 없는 경우 WordPress는 페이지 ID로 명명된 특수 템플릿을 찾아 사용합니다.</li>
<li><strong>page.php</strong> —  페이지의 ID를 포함하는 특수 템플릿을 찾을 수 없는 경우 WordPress는 테마의 기본 페이지 템플릿을 찾아 사용합니다.</li>
<li><strong>singular.php</strong> — page.php를 찾을 수 없으면 워드프레스는 게시물 유형에 관계없이 단일 게시물에 사용된 테마의 템플릿을 찾아 사용합니다.</li>
<li><strong>index.php</strong> —  특정 페이지 템플릿이 지정되거나 발견되지 않으면 WordPress는 기본적으로 테마의 인덱스 파일을 사용하여 페이지를 렌더링합니다.</li>
</ol>
</blockquote>
<br>

<h2 id="실제-코드">실제 코드</h2>
<pre><code class="language-php">/**
 * 상위 페이지가 있는 페이지에 접속시 theme/{상위페이지 Post_name}/page-{$}.php 파일을 사용할 수 있도록 한다
 * page_template 필터를 이용해 어떤 파일을 선택할지 locate_template 함수를 사용한다.
 * URL : https://domain.co.kr/상위 페이지/하위페이지/
 */
function child_templates($template) {
    global $post;

    if ($post-&gt;post_parent) {
        // get top level parent page
        $parent = get_post(
           reset(array_reverse(get_post_ancestors($post-&gt;ID)))
        );

        $child_template = locate_template(
            [
                urldecode($parent-&gt;post_name) . &#39;/page-&#39; . urldecode($post-&gt;post_name) . &#39;.php&#39;,
                urldecode($parent-&gt;post_name) . &#39;/page-&#39; . $post-&gt;ID . &#39;.php&#39;,
                urldecode($parent-&gt;post_name) . &#39;/page.php&#39;,
            ]
        );

        if ($child_template) return $child_template;
    }
    return $template;
}
add_filter(&#39;page_template&#39;, &#39;child_templates&#39;);</code></pre>
<blockquote>
<ol>
<li>page-{slug}.php 파일에 대한 존재 유무를 확인하는 것 보다 해당 페이지에 템플릿이 존재하는 지에 대한 여부를 확인하는 것이 우선순위가 더 높습니다.  이때 &#39;page_template&#39;가 발생하므로 filter를 통해 이를 매칭시켜줄 것 입니다.</li>
<li>현재 불러오는 Page에 상위 페이지가 존재하는 경우 상위페이지의 이름을 가져와 디렉토리 명으로 사용합니다.
<span style="color:#8CB8AA">**    =&gt; 상위페이지 이름은 URL 인코딩이 되어 있으므로 디코딩해줍니다. (한글과 같은 문자를 사용할 수 있기 때문**)</span></li>
<li>해당 디렉토리 밑에 있는 page-{slug}.php, page-{id}.php, page.php 파일을 탐색해 존재하면 매칭시켜줍니다.</li>
</ol>
</blockquote>
<h4 id="참고">참고)</h4>
<ul>
<li>WP_post에서 &#39;post_name&#39;은 테이블에서 고유한 값으로 Slug로 사용됩니다. 제목과 혼동하여서는 안됩니다. </li>
</ul>
<hr>
<h3 id="locate_template-stringarray-template_names-bool-load--false-bool-require_once--true-array-args--array-">locate_template( string|array $template_names, bool $load = false, bool $require_once = true, array $args = array() )</h3>
<p><a href="https://developer.wordpress.org/reference/functions/locate_template/">https://developer.wordpress.org/reference/functions/locate_template/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[C#] GDI+ 계단현상 제거]]></title>
            <link>https://velog.io/@coding_wizard/C-GDI-%EA%B3%84%EB%8B%A8%ED%98%84%EC%83%81-%EC%A0%9C%EA%B1%B0</link>
            <guid>https://velog.io/@coding_wizard/C-GDI-%EA%B3%84%EB%8B%A8%ED%98%84%EC%83%81-%EC%A0%9C%EA%B1%B0</guid>
            <pubDate>Sat, 25 Jun 2022 11:26:29 GMT</pubDate>
            <description><![CDATA[  <center>
    <img src="https://velog.velcdn.com/images/coding_wizard/post/4885376b-dde0-4286-b75c-5dc497e68292/image.png" />
    [계단 현상이 발생하는 모습]
  </center>  


<p>C#에서 원을 그리거나 대각선을 그어보면 비트맵 특유의 계단현상이 나타나 깔끔하지 못합니다.</p>
<p>이를 해결할 수 있는 쉬운 방법은 두가지 입니다.</p>
<blockquote>
<p>Graphics의 SmoothingMode를 AntiAlias 혹은 HighQuality로 지정해 주는 것입니다.</p>
</blockquote>
<p>AntiAlias는 말그대로 안티에이징을 하는 것이고 HighQuality는 PC의 최고 퀄리티를 지향하는 것입니다.
둘다 PC에 부하를 주는 것이기는 하나 원론적인 이야기 이고 매우 많은 GDI가 있지 않은 이상 괜찮습니다</p>
<p>일반적으로 게임 옵션에 계단현상제거 혹은 안티에이징이라는 옵션이 있는 이유가 바로 이것입니다.</p>
<blockquote>
<p>e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;</p>
</blockquote>
<blockquote>
<pre><code class="language-c">myGraphics.SmoothingMode = SmoothingMode.AntiAlias;
myGraphics.DrawLine(myPen, 0, 0, 12, 8);</code></pre>
</blockquote>
<p>```</p>
<center>
    <img src="https://velog.velcdn.com/images/coding_wizard/post/2fc0c12a-ec2e-48a9-9712-e3564be7fb30/image.png" />
[안티에이징 이후 모습]
</center>]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] 에러 리포팅(Error Reporting)]]></title>
            <link>https://velog.io/@coding_wizard/PHP-%EC%97%90%EB%9F%AC-%EB%A6%AC%ED%8F%AC%ED%8C%85Error-Reporting</link>
            <guid>https://velog.io/@coding_wizard/PHP-%EC%97%90%EB%9F%AC-%EB%A6%AC%ED%8F%AC%ED%8C%85Error-Reporting</guid>
            <pubDate>Sat, 25 Jun 2022 07:36:10 GMT</pubDate>
            <description><![CDATA[<p>오류 보고를 사용하면 PHP 보안에 두 가지 측면이 있습니다. 하나는 보안 강화에 도움이 되고 다른 하나는 해가 됩니다.</p>
<p>기본 해킹 공격에는 시스템에 부적절한 데이터를 제공하고 반환되는 오류의 종류와 컨텍스트를 확인하여 시스템을 프로파일링하는 작업이 포함됩니다. 이를 통해 크래커는 서버에 대한 정보를 수집하여 약점 포착할 수 있습니다. 예를 들어 공격자가 이전 양식 제출을 기반으로 페이지에 대한 정보를 수집한 경우 변수를 재정의하거나 수정하려고 할 수 있습니다.</p>
<p>php.ini 파일에 display_errors설정이 디폴트로 Off되어 있는데 켜놓는 경우들도 있습니다.</p>
<blockquote>
<pre><code class="language-php">// php.ini 설정 수정 방법
ini_set(&#39;display_errors&#39;, &#39;On&#39;);</code></pre>
</blockquote>
<pre><code>

&lt;br&gt;

### 예제 #1 사용자 정의 HTML 페이지로 변수 공격하기

&gt; ```php
&lt;form method=&quot;post&quot; action=&quot;attacktarget?username=badfoo&amp;password=badfoo&quot;&gt;
  &lt;input type=&quot;hidden&quot; name=&quot;username&quot; 값=&quot;badfoo&quot; /&gt;
  &lt;input type=&quot;hidden&quot; name=&quot;password&quot; 값=&quot;badfoo&quot; /&gt;
&lt;/form&gt;</code></pre><p>일반적으로 반환되는 PHP 오류는 실패한 함수나 파일, 실패한 PHP 파일, 오류가 발생한 줄 번호 등을 나타내는 스크립트를 디버그하려는 개발자에게 매우 유용할 수 있습니다. 이것은 악용될 수 있는 모든 정보입니다. PHP 개발자가 <a href="http://docs.php.net/manual/en/function.show-source.php">show_source()</a>, <a href="http://docs.php.net/manual/en/function.highlight-string.php">Highlight_string()</a> 또는 <a href="http://docs.php.net/manual/en/function.highlight-file.php">Highlight_file()</a>을 사용하는 것은 드문 일이 아닙니다. 디버깅 수단으로 사용되지만 라이브 사이트에서는 숨겨진 변수, 확인되지 않은 구문 및 기타 위험한 정보가 노출될 수 있습니다. 특히 위험한 것은 내장 디버깅 핸들러가 있는 알려진 소스의 코드를 실행하거나 일반적인 디버깅 기술을 사용하는 것입니다. 공격자가 사용 중인 일반적인 기술을 결정할 수 있는 경우 다양한 공통 디버깅 문자열을 전송하여 페이지에 무차별 대입을 시도할 수 있습니다.</p>
<br>

<h3 id="예제-2-일반적인-디버깅-변수-활용">예제 #2 일반적인 디버깅 변수 활용</h3>
<blockquote>
<pre><code class="language-php"></code></pre>
</blockquote>
<form method="post" action="attacktarget?errors=Y&amp;showerrors=1&amp;debug=1">
  <input type="hidden" name="errors" value="Y" />
  <input type="hidden" name="showerrors" value="1" />
  <input type="hidden" name="debug" value="1" />
</form>
```

<p>오류 처리 방법에 관계없이 시스템에서 오류를 조사하는 기능은 공격자에게 더 많은 정보를 제공하도록 합니다.</p>
<p>예를 들어, 일반적인 PHP 오류의 바로 그 스타일은 시스템이 PHP를 실행하고 있음을 나타냅니다. 공격자가 .html 페이지를 보고 있고 백엔드(시스템의 알려진 약점을 찾기 위해)를 조사하려는 경우 잘못된 데이터를 제공하여 시스템이 PHP로 구축되었음을 결정할 수 있습니다. </p>
<p>기능 오류는 시스템이 특정 데이터베이스 엔진을 실행 중인지 여부를 나타내거나 웹 페이지 또는 프로그래밍 또는 설계 방식에 대한 단서를 제공할 수 있습니다. 이를 통해 열린 데이터베이스 포트에 대한 심층 조사 또는 웹 페이지의 특정 버그 또는 약점을 찾을 수 있습니다. 예를 들어, 다양한 잘못된 데이터를 제공함으로써 공격자는 스크립트의 인증 순서(줄 번호 오류에서)를 결정할 수 있을 뿐만 아니라 스크립트의 다른 위치에서 악용될 수 있는 익스플로잇을 조사할 수 있습니다.</p>
<p>파일 시스템 또는 일반 PHP 오류는 웹 서버에 있는 권한과 웹 서버에 있는 파일의 구조 및 구성을 나타낼 수 있습니다. 개발자가 작성한 오류 코드는 이 문제를 악화시켜 이전에 &quot;숨겨진&quot; 정보를 쉽게 악용할 수 있습니다.</p>
<p>이 문제에 대한 세 가지 주요 솔루션이 있습니다. 첫 번째는 모든 기능을 면밀히 조사하고 대부분의 오류를 보상하려고 시도하는 것입니다. 두 번째는 실행 중인 코드에 대한 오류 보고를 완전히 비활성화하는 것입니다. 세 번째는 PHP의 사용자 정의 오류 처리 기능을 사용하여 고유한 오류 처리기를 만드는 것입니다. 보안 정책에 따라 세 가지 모두를 상황에 적용할 수 있습니다.</p>
<p>이 문제를 미리 잡는 한 가지 방법은 PHP의 자체 <a href="http://docs.php.net/manual/en/function.error-reporting.php">error_reporting()</a> 을 사용하여 코드를 보호하고 위험할 수 있는 변수 사용을 찾는 데 도움이 됩니다. 를 사용하여 배포하기 전에 코드를 테스트 E_ALL하면 변수가 다른 방식으로 감염되거나 수정될 수 있는 영역을 빠르게 찾을 수 있습니다. 배포할 준비가 되면 <a href="http://docs.php.net/manual/en/function.error-reporting.php">error_reporting()</a> 을 0으로 설정하여 오류 보고를 완전히 비활성화하거나 php.ini 옵션 을 사용하여 오류 표시를 꺼서 display_errors코드를 조사하지 않도록 해야 합니다. 후자를 선택하면 error_logini 지시문을 사용하여 로그 파일의 경로도 정의하고 켜야 log_errors합니다.</p>
<br>

<h2 id="에러-리포팅을-하지-않도록-설정하는-방법">에러 리포팅을 하지 않도록 설정하는 방법</h2>
<blockquote>
<ol>
<li>ini_set(&#39;display_errors&#39;, &#39;Off&#39;);</li>
<li>error_reporting(0);</li>
<li>set_error_handler(function () {});</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP]System program execution]]></title>
            <link>https://velog.io/@coding_wizard/PHPSystem-program-execution</link>
            <guid>https://velog.io/@coding_wizard/PHPSystem-program-execution</guid>
            <pubDate>Sat, 25 Jun 2022 07:32:09 GMT</pubDate>
            <description><![CDATA[<h2 id="escapeshellargstring-arg-string">escapeshellarg(string $arg): string</h2>
<p> 문자열 주위에 작은 따옴표를 추가하고 기존의 작은 따옴표를 인용/이스케이프하여 문자열을 쉘 함수에 직접 전달하고 단일 안전한 인수로 처리할 수 있도록 합니다. 이 함수는 사용자 입력에서 오는 쉘 함수에 대한 개별 인수를 이스케이프하는 데 사용해야 합니다.</p>
<p>Windows에서 <strong>escapeshellarg()</strong> 는 대신 백분율 기호, 느낌표(지연 변수 대체) 및 큰따옴표를 공백으로 바꾸고 문자열 주위에 큰따옴표를 추가합니다. 또한 연속된 백슬래시( )의 각 줄은 하나의 추가 백슬래시로 이스케이프됩니다.</p>
<blockquote>
<pre><code class="language-php">system(&#39;ls &#39;.escapeshellarg($dir));</code></pre>
</blockquote>
<pre><code>
&lt;br&gt;

## escapeshellcmd(string $command): string
임의의 명령을 실행하도록 쉘 명령을 속이는 데 사용할 수 있는 문자열의 모든 문자를 이스케이프합니다. 이 함수는 이 데이터가 exec() 또는 system() 함수 또는 백틱 연산자로 전달되기 전에 사용자 입력에서 오는 모든 데이터가 이스케이프되었는지 확인하는 데 사용해야 합니다.

&lt;span style=&quot;color:#EF1037&quot;&gt;※ **escapeshellcmd()** 는 전체 명령 문자열에 사용해야 하며 여전히 공격자가 임의의 수의 인수를 전달할 수 있습니다. 단일 인수를 이스케이프하려면 escapeshellarg() 를 대신 사용해야 합니다.   &lt;/span&gt;


### 예제 #1. escapeshellcmd() 예제

```php
$command = &#39;./configure &#39;.$_POST[&#39;configure_options&#39;];
$escaped_command = escapeshellcmd($command);
system($escaped_command);</code></pre><blockquote>
<p>프로세스 핸들링에는 단방향과 양방향으로 나뉘게 됩니다.
<strong>popen()</strong>은 단방향 핸들링이 가능하고 <strong>proc_open()</strong>은 양방향 핸들링에 사용됩니다.</p>
</blockquote>
<p><br><br></p>
<h2 id="popenstring-command-string-mode-resourcefalse">popen(string $command, string $mode): resource|false</h2>
<p>command에서 제공한 명령을 분기하여 실행되는 프로세스에 대한 파이프를 엽니다.</p>
<br>

<h2 id="pcloseresource-handle-int">pclose(resource $handle): int</h2>
<p>popen() 에 의해 열린 파이프에 대한 파일 포인터를 닫습니다 .</p>
<pre><code class="language-php">$handle = popen(&#39;/bin/ls&#39;, &#39;r&#39;);
pclose($handle);</code></pre>
<h2 id="proc_open">proc_open()</h2>
<pre><code class="language-php">proc_open(
    array|string $command,
    array $descriptor_spec,
    array &amp;$pipes,
    ?string $cwd = null,
    ?array $env_vars = null,
    ?array $options = null
): resource|false</code></pre>
<p><strong>proc_open()</strong> 은 popen() 과 유사 하지만 프로그램 실행에 대해 훨씬 더 높은 수준의 제어를 제공합니다.</p>
<h3 id="예-1">예 #1</h3>
<pre><code class="language-php">$descriptorspec = array(
   0 =&gt; array(&quot;pipe&quot;, &quot;r&quot;),  // stdin은 자식이 읽을 파이프입니다.
   1 =&gt; array(&quot;pipe&quot;, &quot;w&quot;),  // stdout은 자식이 쓸 파이프입니다.
   2 =&gt; array(&quot;file&quot;, &quot;/tmp/error-output.txt&quot;, &quot;a&quot;) // stderr은 쓸 파일입니다.
);

$cwd = &#39;/tmp&#39;;
$env = array(&#39;some_option&#39; =&gt; &#39;aeiou&#39;);

$process = proc_open(&#39;php&#39;, $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {
    // $pipes는 다음과 같이 보입니다:
    // 0 =&gt; 자식 stdin에 연결된 쓰기 가능한 핸들
    // 1 =&gt; 자식 stdout에 연결된 읽기 가능한 핸들
    // 모든 오류 출력은 /tmp/error-output.txt에 추가됩니다.

    fwrite($pipes[0], &#39;&lt;?php print_r($_ENV); ?&gt;&#39;);
    fclose($pipes[0]);

    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    // 호출하기 전에 파이프를 닫는 것이 중요합니다.
    // 교착 상태를 피하기 위해 proc_close
    $return_value = proc_close($process);

    echo &quot;command returned $return_value\n&quot;;
}

/* 실행결과
Array
(
    [some_option] =&gt; aeiou
    [PWD] =&gt; /tmp
    [SHLVL] =&gt; 1
    [_] =&gt; /usr/local/bin/php
)
command returned 0
*/</code></pre>
<h2 id="proc_closeresource-process-int">proc_close(resource $process): int</h2>
<p><a href="http://docs.php.net/manual/en/function.proc-open.php">proc_open()</a> 에 의해 열린 프로세스에서만 작동한다는 점을 제외하면 pclose() 와 유사합니다. <a href="http://docs.php.net/manual/en/function.pclose.php">proc_close()</a> 는 프로세스가 종료될 때까지 기다렸다가 종료 코드를 반환합니다. 교착 상태를 피하기 위해 이 함수가 호출될 때 해당 프로세스에 대한 열린 파이프가 닫힙니다. 파이프가 열려 있는 동안 자식 프로세스가 종료되지 않을 수 있습니다.</p>
<p><br><br><br><br></p>
<hr>
<h1 id="system-program-execution">System program execution</h1>
<p><a href="http://docs.php.net/manual/en/exec.constants.php">미리 정의된 상수</a></p>
<p><a href="http://docs.php.net/manual/en/ref.exec.php">프로그램 실행 기능</a></p>
<ul>
<li>escapeshellarg — 셸 인수로 사용할 문자열을 이스케이프 처리합니다.</li>
<li>escapeshellcmd — 이스케이프 셸 메타 문자</li>
<li>proc_get_status — proc_open에 의해 열린 프로세스에 대한 정보 가져오기</li>
<li>proc_nice — 현재 프로세스의 우선 순위 변경</li>
<li>proc_open — 명령을 실행하고 입출력을 위한 파일 포인터 열기</li>
<li>proc_close — proc_open에 의해 열린 프로세스를 닫고 해당 프로세스의 종료 코드를 반환합니다.</li>
<li>proc_terminate — proc_open에 의해 열린 프로세스를 종료합니다.</li>
<li>exec — 외부 프로그램 실행</li>
<li>shell_exec — 셸을 통해 명령을 실행하고 전체 출력을 문자열로 반환</li>
<li>system — 외부 프로그램을 실행하고 출력을 표시합니다.</li>
<li>passthru — 외부 프로그램을 실행하고 원시 출력을 표시합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] MySQLi]]></title>
            <link>https://velog.io/@coding_wizard/PHP-MySQLi</link>
            <guid>https://velog.io/@coding_wizard/PHP-MySQLi</guid>
            <pubDate>Sat, 25 Jun 2022 07:11:20 GMT</pubDate>
            <description><![CDATA[<p>PHP에는 <strong>mysql</strong>과 <strong>mysqli</strong>가 있습니다.</p>
<p>mysql은 오래전 사용되었고 현재에는 mysql을 개선한 mysqli가 있으므로 <strong>mysqli를 사용하시는게 좋습니다.</strong></p>
<blockquote>
</blockquote>
<ul>
<li><strong>mysqli_prepare()</strong> - 실행을 위해 SQL 문을 준비합니다.</li>
<li><strong>mysqli_stmt_result_metadata()</strong> - 준비된 명령문에서 결과 세트 메타데이터를 반환합니다.</li>
<li><strong>mysqli_stmt_fetch()</strong> - 준비된 명령문에서 바인딩된 변수로 결과를 가져옵니다.</li>
<li><strong>mysqli_fetch_array()</strong> - 결과 세트의 다음 행을 연관, 숫자 배열 또는 둘 다로 가져옵니다.</li>
<li><strong>mysqli_stmt_store_result()</strong> - 결과 세트를 내부 버퍼에 저장</li>
</ul>
<br>


<h2 id="mysql-서버에-대한-새-연결-열기">MySQL 서버에 대한 새 연결 열기</h2>
<blockquote>
<ul>
<li>mysqli::__construct</li>
</ul>
</blockquote>
<ul>
<li>mysqli::connect</li>
<li>mysqli_connect</li>
</ul>
<h3 id="객체지향-style">객체지향 style</h3>
<pre><code class="language-php">public mysqli::__construct(
    string $hostname = ini_get(&quot;mysqli.default_host&quot;),
    string $username = ini_get(&quot;mysqli.default_user&quot;),
    string $password = ini_get(&quot;mysqli.default_pw&quot;),
    string $database = &quot;&quot;,
    int $port = ini_get(&quot;mysqli.default_port&quot;),
    string $socket = ini_get(&quot;mysqli.default_socket&quot;)
)</code></pre>
<pre><code class="language-php">public mysqli::connect(
    string $hostname = ini_get(&quot;mysqli.default_host&quot;),
    string $username = ini_get(&quot;mysqli.default_user&quot;),
    string $password = ini_get(&quot;mysqli.default_pw&quot;),
    string $database = &quot;&quot;,
    int $port = ini_get(&quot;mysqli.default_port&quot;),
    string $socket = ini_get(&quot;mysqli.default_socket&quot;)
): void</code></pre>
<h3 id="절차지향-style">절차지향 style</h3>
<pre><code class="language-php">mysqli_connect(
    string $hostname = ini_get(&quot;mysqli.default_host&quot;),
    string $username = ini_get(&quot;mysqli.default_user&quot;),
    string $password = ini_get(&quot;mysqli.default_pw&quot;),
    string $database = &quot;&quot;,
    int $port = ini_get(&quot;mysqli.default_port&quot;),
    string $socket = ini_get(&quot;mysqli.default_socket&quot;)
): mysqli|false</code></pre>
<br>
데이터베이스에 대한 쿼리를 수행합니다. 

<blockquote>
<ul>
<li><a href="http://docs.php.net/manual/en/mysqli.query.php">mysqli::query</a></li>
</ul>
</blockquote>
<ul>
<li><a href="http://docs.php.net/manual/en/mysqli.query.php">mysqli_query</a></li>
</ul>
<blockquote>
</blockquote>
<pre><code class="language-php">public mysqli::query(string $query, int $result_mode = MYSQLI_STORE_RESULT): mysqli_result|bool</code></pre>
<blockquote>
</blockquote>
<pre><code class="language-php">mysqli_query(mysqli $mysql, string $query, int $result_mode = MYSQLI_STORE_RESULT): mysqli_result|bool</code></pre>
<p><span style="color:#EF1037">※ 쿼리에 변수 입력이 포함된 경우 <strong><a href="http://docs.php.net/manual/en/mysqli.quickstart.prepared-statements.php">매개변수화된 준비된 명령문</a></strong> 을 대신 사용해야 합니다. 또는 데이터 형식이 적절해야 하며 모든 문자열은 <strong><a href="(http://docs.php.net/manual/en/mysqli.real-escape-string.php)">mysqli_real_escape_string()</a></strong> 함수를 사용하여 이스케이프되어야 합니다. 데이터베이스 관련 함수를 사용할 때는 언제나 SQL injection에 주의하여야 합니다.</span></p>
<br>

<h3 id="객체지향-스타일">객체지향 스타일</h3>
<pre><code class="language-php">mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli(&quot;localhost&quot;, &quot;my_user&quot;, &quot;my_password&quot;, &quot;world&quot;);

/* Create table doesn&#39;t return a resultset */
$mysqli-&gt;query(&quot;CREATE TEMPORARY TABLE myCity LIKE City&quot;);
printf(&quot;Table myCity successfully created.\n&quot;);

/* Select queries return a resultset */
$result = $mysqli-&gt;query(&quot;SELECT Name FROM City LIMIT 10&quot;);
printf(&quot;Select returned %d rows.\n&quot;, $result-&gt;num_rows);

$result = $mysqli-&gt;query(&quot;SELECT * FROM City&quot;, MYSQLI_USE_RESULT);

$mysqli-&gt;query(&quot;SET @a:=&#39;this will not work&#39;&quot;);</code></pre>
<h3 id="절차적-스타일">절차적 스타일</h3>
<pre><code class="language-php">mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = mysqli_connect(&quot;localhost&quot;, &quot;my_user&quot;, &quot;my_password&quot;, &quot;world&quot;);

/* Create table doesn&#39;t return a resultset */
mysqli_query($link, &quot;CREATE TEMPORARY TABLE myCity LIKE City&quot;);
printf(&quot;Table myCity successfully created.\n&quot;);

/* Select queries return a resultset */
$result = mysqli_query($link, &quot;SELECT Name FROM City LIMIT 10&quot;);
printf(&quot;Select returned %d rows.\n&quot;, mysqli_num_rows($result));

/* If we have to retrieve large amount of data we use MYSQLI_USE_RESULT */
$result = mysqli_query($link, &quot;SELECT * FROM City&quot;, MYSQLI_USE_RESULT);

mysqli_query($link, &quot;SET @a:=&#39;this will not work&#39;&quot;);</code></pre>
<h2 id="실행을-위한-sql-문-준비">실행을 위한 SQL 문 준비</h2>
<blockquote>
<ul>
<li>mysqli::preparde</li>
</ul>
</blockquote>
<ul>
<li>mysqli_prepare</li>
</ul>
<blockquote>
<pre><code class="language-php">public mysqli::prepare(string $query): mysqli_stmt|false</code></pre>
</blockquote>
<pre><code>```php
mysqli_prepare(mysqli $mysql, string $query): mysqli_stmt|false</code></pre><p>SQL 쿼리를 준비하고 명령문에 대한 추가 작업에 사용할 명령문 핸들을 반환합니다. 쿼리는 단일 SQL 문으로 구성되어야 합니다.절차지향적 방식인 mysql_prepare()의 경우  <a href="http://docs.php.net/manual/en/function.mysqli-connect.php">mysqli_connect()</a> 또는 <a href="http://docs.php.net/manual/en/mysqli.init.php">mysqli_init( )</a>에 의해 반환된 <a href="http://docs.php.net/manual/en/class.mysqli.php">mysqli</a> 객체를 $mysql로 넘겨 주여야 합니다.</p>
<p>명령문 템플릿에는 자리 표시자라고도 하는 0개 이상의 물음표( ?) 매개변수 마커가 포함될 수 있습니다. 매개변수 마커는 명령문을 실행하기 전에 <a href="http://docs.php.net/manual/en/mysqli-stmt.bind-param.php">mysqli_stmt_bind_param()</a> 을 사용하여 애플리케이션 변수에 바인딩되어야 합니다. 일반적으로 매개변수는 DML(데이터 조작 언어) 문에서만 유효하고 DDL(데이터 정의어) 문에서는 유효하지 않습니다.</p>
<blockquote>
<p>마커는 SQL 문의 특정 위치에서만 유효합니다. 예를 들어, 명령문의 VALUES() 목록 INSERT(행에 대한 열 값 지정)에서 또는 WHERE비교 값을 지정하기 위해 절의 열과의 비교에서 허용됩니다.
그러나 식별자(예: 테이블 또는 열 이름)에 대해 또는 =등호와 같은 이항 연산자의 두 피연산자를 모두 지정하는 데에는 허용되지 않습니다. 후자의 제한은 매개변수 유형을 결정하는 것이 불가능하기 때문에 필요합니다. 일반적으로 매개변수는 DML(데이터 조작 언어) 문에서만 유효하고 DDL(데이터 정의어) 문에서는 유효하지 않습니다.</p>
</blockquote>
<h3 id="예제-1-mysqliprepare-예제">예제 #1 mysqli::prepare() 예제</h3>
<h4 id="객체-지향-스타일">객체 지향 스타일</h4>
<pre><code class="language-php">mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli(&quot;localhost&quot;, &quot;my_user&quot;, &quot;my_password&quot;, &quot;world&quot;);

$city = &quot;Amersfoort&quot;;

/* create a prepared statement */
$stmt = $mysqli-&gt;prepare(&quot;SELECT District FROM City WHERE Name=?&quot;);

/* bind parameters for markers */
$stmt-&gt;bind_param(&quot;s&quot;, $city);

/* execute query */
$stmt-&gt;execute();

/* bind result variables */
$stmt-&gt;bind_result($district);

/* fetch value */
$stmt-&gt;fetch();

printf(&quot;%s is in district %s\n&quot;, $city, $district);</code></pre>
<h4 id="절차적-스타일-1">절차적 스타일</h4>
<pre><code class="language-php">mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = mysqli_connect(&quot;localhost&quot;, &quot;my_user&quot;, &quot;my_password&quot;, &quot;world&quot;);

$city = &quot;Amersfoort&quot;;

/* create a prepared statement */
$stmt = mysqli_prepare($link, &quot;SELECT District FROM City WHERE Name=?&quot;);

/* bind parameters for markers */
mysqli_stmt_bind_param($stmt, &quot;s&quot;, $city);

/* execute query */
mysqli_stmt_execute($stmt);

/* bind result variables */
mysqli_stmt_bind_result($stmt, $district);

/* fetch value */
mysqli_stmt_fetch($stmt);

printf(&quot;%s is in district %s\n&quot;, $city, $district);</code></pre>
<p><br><br></p>
<blockquote>
</blockquote>
<pre><code class="language-php">public mysqli_stmt::get_result(): mysqli_result|false</code></pre>
<pre><code class="language-php">mysqli_stmt_get_result(mysqli_stmt $statement): mysqli_result|false</code></pre>
<p>준비된 명령문에서 결과 집합을 <a href="http://docs.php.net/manual/en/class.mysqli-result.php">mysqli_result</a> 객체 로 가져옵니다. 데이터는 MySQL 서버에서 PHP로 가져옵니다. 이 메서드는 결과 집합을 생성하는 쿼리에 대해서만 호출해야 합니다.</p>
<blockquote>
<p>이 함수는 mysqli_stmt_store_result()와 함께 사용할 수 없습니다 . 이 두 함수는 모두 MySQL 서버에서 전체 결과 세트를 검색합니다.</p>
</blockquote>
<p><br><br></p>
<h2 id="트렌젝션">트렌젝션</h2>
<p>mysqli는 기본적으로 오토 커밋을 하게 됩니다. 커밋을 해야 실제 Database에 적용 됩니다. 커밋전에 롤백하게 되면 그동안 작업한 내용들은 실제 Database에 적용되지 않습니다.</p>
<blockquote>
<p>mysqli::autocommit ,  mysqli_autocommit — 데이터베이스 수정 자동 커밋을 켜거나 끕니다.</p>
</blockquote>
<p>참고로 트렌젝션 중 일부 에러가 발생한다면 전체 트렌젝션이 적용되지 않습니다. (틀렸다면 댓글 남겨 주세요)</p>
<blockquote>
</blockquote>
<pre><code class="language-php">public mysqli::autocommit(bool $enable): bool</code></pre>
<pre><code class="language-php">mysqli_autocommit(mysqli $mysql, bool $enable): bool</code></pre>
<h3 id="예제">예제</h3>
<pre><code class="language-php">/* 오류가 발생하면 예외를 던지도록 mysqli에 지시 */
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

$mysqli = mysqli_connect(&quot;localhost&quot;, &quot;my_user&quot;, &quot;my_password&quot;, &quot;world&quot;);

/* 테이블 엔진이 트랜잭션을 지원해야 합니다 */
mysqli_query($mysqli, &quot;CREATE TABLE IF NOT EXISTS language (
    Code text NOT NULL,
    Speakers int(11) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;&quot;);

/* 자동 커밋 끄기 */
mysqli_autocommit($mysqli, false);

$result = mysqli_query($mysqli, &quot;SELECT @@autocommit&quot;);
$row = mysqli_fetch_row($result);
printf(&quot;Autocommit is %s\n&quot;, $row[0]);

try {
    /* Prepare insert */
    $stmt = mysqli_prepare($mysqli, &#39;INSERT INTO language(Code, Speakers) VALUES (?,?)&#39;);
    mysqli_stmt_bind_param($stmt, &#39;ss&#39;, $language_code, $native_speakers);

    /* Insert some values */
    $language_code = &#39;DE&#39;;
    $native_speakers = 50_123_456;
    mysqli_stmt_execute($stmt);
    $language_code = &#39;FR&#39;;
    $native_speakers = 40_546_321;
    mysqli_stmt_execute($stmt);

    /* 데이터베이스의 데이터를 커밋합니다. 이것은 autocommit=true로 설정되지 않습니다 */
    mysqli_commit($mysqli);
    print &quot;Committed 2 rows in the database\n&quot;;

    $result = mysqli_query($mysqli, &quot;SELECT @@autocommit&quot;);
    $row = mysqli_fetch_row($result);
    printf(&quot;Autocommit is %s\n&quot;, $row[0]);

    /* Try to insert more values */
    $language_code = &#39;PL&#39;;
    $native_speakers = 30_555_444;
    mysqli_stmt_execute($stmt);
    $language_code = &#39;DK&#39;;
    $native_speakers = 5_222_444;
    mysqli_stmt_execute($stmt);

    /* autocommit=true로 설정하면 커밋이 트리거됩니다. */
    mysqli_autocommit($mysqli, true);

    print &quot;Committed 2 row in the database\n&quot;;
} catch (mysqli_sql_exception $exception) {
    mysqli_rollback($mysqli);

    throw $exception;
}</code></pre>
<hr>
<h1 id="mysql-개선된-확장">MySQL 개선된 확장</h1>
<p>이와 관련된 내용은 공식 자료를 살펴보시기 바라며 링크는 아래에 기록되어 있습니다.
Velog가 링크까지 복사를 못해오네요</p>
<blockquote>
<p><a href="https://paric.tistory.com/790">https://paric.tistory.com/790</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP]Output Buffering Control]]></title>
            <link>https://velog.io/@coding_wizard/PHPOutput-Buffering-Control</link>
            <guid>https://velog.io/@coding_wizard/PHPOutput-Buffering-Control</guid>
            <pubDate>Sat, 25 Jun 2022 06:56:20 GMT</pubDate>
            <description><![CDATA[<h2 id="기본-사용-방법">기본 사용 방법</h2>
<h3 id="예-1-출력-제어-예">예 #1 출력 제어 예</h3>
<pre><code class="language-php">ob_start();

echo &quot;Hello\n&quot;;
setcookie(&quot;cookiename&quot;, &quot;cookiedata&quot;);

ob_end_flush();</code></pre>
<p>위의 예에서 echo 의 출력은 <a href="http://docs.php.net/manual/en/function.ob-end-flush.php">ob_end_flush()</a> 가 호출 될 때까지 출력 버퍼에 저장됩니다.
<br><br></p>
<hr>
<h2 id="출력-버퍼링-제어-기능">출력 버퍼링 제어 기능</h2>
<blockquote>
<ul>
<li><strong>flush</strong> — 시스템 출력 버퍼 플러시</li>
</ul>
</blockquote>
<ul>
<li><strong>ob_clean</strong> — 출력 버퍼 청소(지우기)</li>
<li><strong>ob_end_clean</strong> — 출력 버퍼를 청소(지우기)하고 출력 버퍼링을 끕니다.</li>
<li><strong>ob_end_flush</strong> — 출력 버퍼를 플러시(전송)하고 출력 버퍼링을 끕니다.</li>
<li><strong>ob_flush</strong> — 출력 버퍼를 플러시(보내기)</li>
<li><strong>ob_get_clean</strong> — 현재 버퍼 내용을 가져오고 현재 출력 버퍼를 삭제합니다.</li>
<li><strong>ob_get_contents</strong> — 출력 버퍼의 내용을 반환합니다.</li>
<li><strong>ob_get_flush</strong> — 출력 버퍼를 플러시하고 문자열로 반환하고 출력 버퍼링을 끕니다.</li>
<li><strong>ob_get_length</strong> — 출력 버퍼의 길이를 반환</li>
<li><strong>ob_get_level</strong> — 출력 버퍼링 메커니즘의 중첩 수준을 반환합니다.</li>
<li><strong>ob_get_status</strong> — 출력 버퍼의 상태 가져오기</li>
<li><strong>ob_gzhandler</strong> — gzip 출력 버퍼에 대한 ob_start 콜백 함수</li>
<li><strong>ob_implicit_flush</strong> — 암시적 플러시 켜기/끄기</li>
<li><strong>ob_list_handlers</strong> — 사용 중인 모든 출력 핸들러 나열</li>
<li><strong>ob_start</strong> — 출력 버퍼링 켜기</li>
<li><strong>output_add_rewrite_var</strong> — URL 재작성기 값 추가</li>
<li><strong>output_reset_rewrite_vars</strong> — URL 재작성기 값 재설정</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] 사전 정의된 변수(Predefined Variables)]]></title>
            <link>https://velog.io/@coding_wizard/PHP-%EC%82%AC%EC%A0%84-%EC%A0%95%EC%9D%98%EB%90%9C-%EB%B3%80%EC%88%98Predefined-Variables</link>
            <guid>https://velog.io/@coding_wizard/PHP-%EC%82%AC%EC%A0%84-%EC%A0%95%EC%9D%98%EB%90%9C-%EB%B3%80%EC%88%98Predefined-Variables</guid>
            <pubDate>Sat, 25 Jun 2022 06:47:08 GMT</pubDate>
            <description><![CDATA[<p>PHP는 모든 스크립트에 미리 정의된 많은 변수를 제공합니다. <a href="http://docs.php.net/manual/en/language.variables.external.php">변수는 외부 변수</a> 에서 내장 환경 변수, 마지막 오류 메시지에서 마지막으로 검색된 헤더에 이르기까지 모든 것을 나타냅니다 .</p>
<p>이러한 사전 정의된 변수들은 굉장히 일반적으로 사용되기 대문에 필히 숙지해 놓을 필요가 있습니다.</p>
<blockquote>
</blockquote>
<ul>
<li><strong>Superglobal</strong> — 모든 범위에서 항상 사용할 수 있는 내장 변수</li>
<li><strong>$GLOBALS</strong> — 전역 범위에서 사용 가능한 모든 변수를 참조합니다.</li>
<li><strong>$_SERVER</strong> — 서버 및 실행 환경 정보</li>
<li><strong>$_GET</strong> — HTTP GET 변수</li>
<li><strong>$_POST</strong> — HTTP POST 변수</li>
<li><strong>$_FILES</strong> — HTTP 파일 업로드 변수</li>
<li><strong>$_REQUEST</strong> — HTTP 요청 변수</li>
<li><strong>$_SESSION</strong> — 세션 변수</li>
<li><strong>$_ENV</strong> — 환경 변수</li>
<li><strong>$_COOKIE</strong> — HTTP 쿠키</li>
<li><strong>$php_errormsg</strong> — 이전 오류 메시지</li>
<li><strong>$http_response_header</strong> — HTTP 응답 헤더</li>
<li><strong>$argc</strong> — 스크립트에 전달된 인수의 수</li>
<li><strong>$argv</strong> — 스크립트에 전달된 인수 배열</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] 세션(Session)]]></title>
            <link>https://velog.io/@coding_wizard/PHP-%EC%84%B8%EC%85%98Session</link>
            <guid>https://velog.io/@coding_wizard/PHP-%EC%84%B8%EC%85%98Session</guid>
            <pubDate>Sat, 25 Jun 2022 05:59:20 GMT</pubDate>
            <description><![CDATA[<p>session_save_path()</p>
<p>session_start()</p>
<p>session_set_cookie_params();</p>
<blockquote>
<p>PHP파일을 통해 php.ini설정을 수정하려면 ini_set()함수를 사용하면 됩니다.</p>
</blockquote>
<p><strong>php.ini</strong> 설정에서 <strong>session.use_strict_mode = 1</strong>로 설정되어 있다면 Session ID가 영구적으로 사용될 수 있습니다. 이렇게 될 경우 공격자가 세션 ID 훔쳐와 사용할 수 있기 때문에 해당설정은 0으로 꺼두는 것이 좋습니다.</p>
<p><strong>session.use_only_cookies</strong>는 쿠키로면 session ID 를 사용하도록 하는 것으로 URL의 GET 값으로 PHPSESSID가 전달되는 것을 지원하지 않게 합니다.  해당 설정은 1로 켜주세요.</p>
<p><strong>session.cookie_httpOnly</strong>는 Javascript Injection을 통해 클라이언트의 Session ID가 노출 될 수 있으므로 1로 켜서 막아주어야 합니다.</p>
<p><strong>session.cookie_secure</strong>설정은 https를 사용할 때 사용하는 것이 좋습니다.</p>
<p>세션에는 쿠키와 마찮가지로 유효기간이 있습니다. 이 유효기간이 만료되면 GC에 의해서 삭제되게 됩니다.
이러한 설정은 php.ini에서 <strong>session.gc</strong>로 시작되는 설정들입니다.
session.gc_maxlifetime이 바로 유효기간으로 설정은 초단위 정수로 전달됩니다.</p>
<ul>
<li>sesion_set_cookie_params()</li>
<li>session_gc()</li>
</ul>
<p>session_gc는 유효기간이 만료된 세션들을 정리해주는 함수이지만 session_gc의 수행은 완벽하지 않기 때문에 해당 작업을 온전히 믿어서는 안됩니다.</p>
<pre><code class="language-php">ini_set(&#39;session.gc_maxlifetime&#39;,10);
session_set_cookie_params(10);
session_start();
session_gc();</code></pre>
<p>일반적으로는 session_gc를 주기적으로 수행하도록해 세션 파일들을 정리해줍니다.</p>
<br>

<h2 id="타임-스템프를-활용한-세션-관리">타임 스템프를 활용한 세션 관리</h2>
<pre><code class="language-php">session_save_path(dirname(__DIR__) . &#39;/sessions&#39;);
session_start();

$_SESSION[&#39;timestamp&#39;] = $_SERVER[&#39;REQUEST_TIME&#39;];

$time = strtotime(&#39;+10 seconds&#39;);
$diff = $time - $_SESSION[&#39;timestamp&#39;];
$sessionTimeOut = 10;

if ($diff &gt;= $sessionTimeOut) {
    /*
        ~세션을 파괴 후 기타 작업 진행 (php 가이드라인에서 권장하지 않음)
    */
    /* 세션 재설정 방법 */
    session_regenerate_id();
    $_SESSION[&#39;timestamp&#39;] = time();
    exit;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] 보안 - XSS(Cross Site Scripting) & CSRF]]></title>
            <link>https://velog.io/@coding_wizard/PHP-%EB%B3%B4%EC%95%88-XSSCross-Site-Scripting-CSRF</link>
            <guid>https://velog.io/@coding_wizard/PHP-%EB%B3%B4%EC%95%88-XSSCross-Site-Scripting-CSRF</guid>
            <pubDate>Tue, 21 Jun 2022 03:32:11 GMT</pubDate>
            <description><![CDATA[<h2 id="서론">서론</h2>
<p>모든 값을 다룰 때는 해당 데이터가 오염되었다는 가정하에 사용하는 것이 좋습니다.
클라이언트로 부터 받아오는 값을 서버에서는 필터를 통한 다음 사용하여야 하며, 
클라이언트로 전달할 값 또한 필터를 거친 다음 출력하여야 합니다.<br></p>
<p>웹 개발은 사실 어떤 것 보다 가장 쉬우면서도 어려운게 이러한 부분들이 아닌가 싶습니다.
값 하나를 출력하거나 입력 받을 때도 수많은 경우를 고려하여야만이 비로소 견고한 웹이 제작되기 때문입니다.</p>
<p>보안은 습관임과 동시의 시스템이라 생각합니다. 어떤 제작사든 이에 대한 올바른 가이드라인을 제작하여 이를 바탕으로 수행하는 것이 좋습니다. 회사는 개개인의 역량을 통해 하나의 시스템을 만드는 곳이기 때문입니다.</p>
<p>서두가 길었습니다. 이번 편은 보안에 대한 이야기로 그중에서도 XSS에 대한 가벼운 글 입니다.</p>
<p>누군가 이 글을 읽는 다면 혹시나 저와 같은 루키시라면 백앤드를 지향하시더라도 프론트에 대한 전반적인 워크플로우를 이해하고 숙지하신다면 필히 좋은 정상을 향해 나아갈 수 있을 것 입니다.
<br></p>
<h2 id="xss란">XSS란?</h2>
<p>XSS는 Cross-Site Scripting의 약자로 CSS가 되어야 함이 옳지만 CSS는 이미 Cascading Style Sheets라는 뜻으로 정의되어 있어 선이 겹치는 X를 차용해 XSS가 되었습니다. </p>
<p>XSS 공격은 웹 애플리케이션이 사용자로부터 입력 받은 값을 제대로 검사하지 않고 사용할 때 유효한 공격입니다.</p>
<p>주로 여러 사용자들이 보게되는 게시판에 악성 스크립트를 내포하여 글을 올리곤 합니다. 이러한 공격을 통해 서버에는 악성 스크립트가 포함된 정보가 저장되게 되고 이렇게 저장된 스크립트는 서버를 통해 또다시 출력되게 됩니다. </p>
<p>이렇듯 XSS는 사용자로부터 값을 받아와 출력하는 모든 곳에 사용될 수 있습니다. 
<span style="color:#EF1037">※ XSS공격을 막기 위해 클라이언트 단에서 검사하지 마십시오. 해당 필터를 우회할 수 있으므로 클라이언트 사이드 필터 유무와 관계 없이 서버에서도 검사하여야 합니다.</span></p>
<p>이를 활용한 공격은 CSRF(XSRF)로 발전될 수 잇습니다. CSRF에 대한 내용은 본고에 담지않습니다.
XSS공격은 결국 서버에서 클라이언트에 대한 악성 공격을 수행하게 됩니다.</p>
<pre><code class="language-php">htmlentities($_POST[&#39;content&#39;]);
strip_tags($_POST[&#39;content&#39;]);
filter_input(INPUT_POST, &#39;content&#39;, FILTER_SANITIZE_FULL_SPECIAL_CHARS);

output_add_rewrite_var(&#39;csrf_token&#39;, $_SESSION[&#39;token&#39;]);</code></pre>
<br>

<h3 id="예-1-token을-사용한-csrf-공격-보안">예 #1. token을 사용한 CSRF 공격 보안</h3>
<pre><code class="language-php">session_start();

switch($_SERVER[&#39;REQUEST_METHOD&#39;]) {
    case &#39;GET&#39;:
        $_SESSION[&#39;token&#39;] = bin2hex(random_bytes(32));
        output_add_rewrite_var(&#39;csrf_token&#39;, $_SESSION[&#39;token&#39;]);

        echo &lt;&lt;&lt; &#39;HTML&#39;
&lt;form action=&quot;/&quot; method=&quot;POST&quot;&gt;
    &lt;textarea name=&quot;content&quot; rows=25 cols=50&gt; &lt;/textarea&gt;
    &lt;input type=&quot;submit&quot;&gt;
&lt;/form&gt;
HTML;
        break;
    case &#39;POST&#39;:
        if (hash_equals($_SESSION[&#39;token&#39;], $_POST[&#39;csrf_token&#39;])) {
            $uid = $_POST[&#39;uid&#39;];
            echo &#39;Hello, world&#39;;
        }

        // echo htmlentities($_POST[&#39;content&#39;]).PHP_EOL;
        // echo strip_tags($_POST[&#39;content&#39;]).PHP_EOL;
        echo filter_input(INPUT_POST, &#39;content&#39;, FILTER_SANITIZE_FULL_SPECIAL_CHARS).PHP_EOL;
        break;
    default:
        http_response_code(404);
}</code></pre>
<p>32byte의 난수를 생성하여 세션에 저장하고 해당 값을 클라이언트 FORM에 hidden으로 출력합니다. 이렇게 전송된 토큰 값을 submit될 때 받아와 비교하게 된다면 session에 저장된 토큰과 클라이언트로부터 받아온 토큰값을 비교하여 검증할 수 있습니다.</p>
<p>일반적으로 이러한 값을 nonce라고 합니다. 프레임워크나 Wordpress와 같은 CMS에서는 이와 관련된 함수들은 nonce와 같은 이름으로 붙여져 있으므로 참고하여 주시기 바랍니다. </p>
<p>이렇듯 XSS 공격은 값을 서버로 받아올 때와 서버에서 내보낼 때 모두 해주셔야 합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] php.ini (PHP 환경설정)]]></title>
            <link>https://velog.io/@coding_wizard/PHP-php.ini-PHP-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@coding_wizard/PHP-php.ini-PHP-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95</guid>
            <pubDate>Tue, 21 Jun 2022 03:27:59 GMT</pubDate>
            <description><![CDATA[<p>php.ini는 PHP에 대한 설정값들이 저장되어 있는 파일입니다.
다양한 값들이 저장되어 있으며 php extension에 대한 설정 또는 사용자가 추가한 값들도 저장될 수 있습니다.</p>
<p>php.ini 설정은 PHP 함수를 통해 제어하거나 php.ini 파일을 직접 수정할 수 있습니다.
이렇게 값을 변경한 이후에는 아파치를 재시작 시켜 php.ini 설정값들을 다시 불러 오도록 해야 합니다.</p>
<h2 id="주요-설정">[주요 설정]</h2>
<p>개발시 사용되는 환경 설정 값들은 정말 다양하고 많습니다만 그 중 일부 설정에 대해 알아봅니다</p>
<blockquote>
<p>0과 1로 주는 설정들은 대부분 <span style="color:#EF1037">1: 켠상태, 0: 끈상태</span> 입니다.</p>
</blockquote>
<p><strong>opcache.enable</strong>
해당 옵션이 켜져 있으면 PHP 파일이 수정되더라도 즉시 반영되지 않고 짧게는 몇초 길게는 1분 가량의 시간이 지난 다음에야 웹페이지에 적용됩니다. 개발 시에는 이러한 기능이 굉장히 불편하기 때문에 0으로 꺼주시고 개발 이후에는 1로 변경하여 PHP의 성능을 높일 수 있습니다.</p>
<p><strong>max_execution_time = 30</strong>
스크립트의 최대 실행시간(초단위)을 설정합니다.</p>
<p><strong>max_input_time = 60</strong>
POST, GET, 파일업로드 등의 입력 데이터를 받아들이는 최대시간(초단위) 설정</p>
<p><strong>memory_limit = 128M</strong>
스크립트가 사용할 수 있는 최대 메모리양 입니다.</p>
<p>*<em>file_uploads = On
*</em>파일 업로드 허가여부를 설정 합니다.</p>
<p>*<em>upload_max_filesize = 20M
*</em>업로드 파일의 최대 사이즈를 설정합니다. =&gt; upload_max_filesize보다 post_max_size가 커야합니다.</p>
<p><strong>post_max_size = 80M</strong>
POST 데이터가 허용하는 최대 사이즈를 설정합니다. (post_max_size가 upload_max_filesize보다 커야합니다.)</p>
<p><strong>display_errors = ON</strong>
개발 시 디버깅을 용이하게 해주는 설정입니다. 해당 설정을 켜게 될 경우 PHP 어느 부분에 에러가 발생하였는지를 알려줍니다. 그렇기 때문에 <strong>개발 완료 후에는 설정을 Off로</strong> 꺼두어야 합니다.</p>
<p> <br><br><br></p>
<hr>
<h2 id="php-환경설정phpini--language-options">php 환경설정(php.ini) : [Language Options]</h2>
<p><strong>engine = On</strong> : Apache에서 PHP 스크립트 언어 엔진 적용(Off로 설정시 PHP파일을 보여주지 못하고 다운로드하게 됨)
zend.ze1_compatibility_mode = Off : zend 엔진 버전1의 호환모드 설정
short_open_tag = On : &lt;? 태그 사용 허용(Off로 설정시 &lt;?php, 와 <script> 태그만 인식)
asp_tags = Off : ASP 스타일의 <%, %> 태그 사용여부 설정
precision = 12 : 부동소수점의 유효 자리수 설정
y2k_compliance = On : 2000년 호환모드로 설정
output_buffering = Off : 모든 파일의 출력 버퍼링 활성화 여부 설정(구체적인 숫자 입력시 출력 버퍼링을 특정 사이즈로 제한)
;output_handler = : 스크립트의 모든 출력을 특정 함수를 통해 할 수 있음
zlib.output_compression = Off : zlib을 사용해 페이지를 압축할 것인지 설정
;zlib.output_compression_level = -1 : 압축 레벨 설정
;zlib.output_handler = : zlib.output_compression을 활성화할 경우, 추가 출력 핸들러를 지정할 수 없음
implicit_flush = Off : On 설정시 print(), echo() 및 각 HTML 블록의 뒤에 flush()함수를 부르는 것과 동일하게 작용(성능저하 유발)</p>
<p>unserialize_callback_func = : unserialize 중에 정의되지 않은 클래스를 작성해야 할 경우, 콜백 함수를 호출(정의되지 않은 클래스를 작성해야 할 때마다 호출)
allow_call_time_pass_reference = On : 함수 사용시 변수를 강제적으로 참조하는 것 금지</p>
<br>

<h3 id="php-환경설정phpini--safe-mode">php 환경설정(php.ini) : [Safe Mode]</h3>
<p>safe_mode = Off : 안전모드 사용여부 설정
safe_mode_gid = Off : 파일이 열릴 때, UID 비교검사 수행(On 설정시 GID 비교검사 수행)
safe_mode_include_dir = : 지정한 디렉토리 및 하위 디렉토리의 파일을 include 하는 경우, UID/GID 검사 미수행
safe_mode_exec_dir = : (안전모드에서) system() 및 시스템 프로그램을 실행하는 함수의 경로(이 디렉토리에 없으면 함수를 실행할 수 없음)
safe_mode_allowed_env_vars = PHP_ : (안전모드에서) 지정된 문자로 시작하는 환경변수만 변경 가능
safe_mode_protected_env_vars = LD_LIBRARY_PATH : putenv()로 변경할 수 없는 환경변수 설정
;open_basedir = : 안전모드와 관계없이 PHP가 열 수 있는 디렉토리 설정
disable_functions = : 특정 함수 사용 금지 설정
disable_classes = : 특정 클래스 사용 금지 설정
;highlight.string = #DD0000 : 문법의 하이라이트 표시 설정(string, comment, keywork, bg, default, html 설정 가능)
;ignore_user_abort = On : 클라이언트가 연결을 끊었을 때, 스크립트 수행을 중단한 것인지 설정(기본값은 스크립트 중단)
;realpath_cache_siae = 16k : realpath 캐쉬 양 설정
;realpath_cache_ttl = 120 : 캐쉬의 유효기간을 초단위로 설정
expose_php = On : PHP가 해당 서버에 인스톨되고, 사용되고 있다는 내용 알림 설정(On 설정시 내용 알림)
<br></p>
<h3 id="php-환경설정phpini--resource-limits">php 환경설정(php.ini) : [Resource Limits]</h3>
<p><strong>max_execution_time</strong> = 30 : 스크립트 최대 실행시간(초단위) 설정
<strong>max_input_time</strong> = 60 : POST, GET, 파일업로드 등의 입력 데이터를 받아들이는 최대시간(초단위) 설정
<strong>memory_limit</strong> = 128M : 스크립트가 사용할 수 있는 최대 메모리양 설정
<br></p>
<h3 id="error-handling-and-logging">[Error handling and logging]</h3>
<p><strong>error_reporting</strong> = E_ALL & ~E_NOTICE : E_NOTICE를 제외한 모든 에러 출력</p>
<blockquote>
</blockquote>
<ul>
<li>E_ALL</li>
<li>E_ERROR</li>
<li>E_RECOVERABLE_ERROR</li>
<li>E_WARNING</li>
<li>E_PARSE</li>
<li>E_NOTICE</li>
<li>E_CORE_ERROR</li>
<li>E_CORE_WARNING</li>
<li>E_COMPILE_ERROR</li>
<li>E_COMPILE_WARNING</li>
<li>E_USER_ERROR</li>
<li>E_USER_WARNING</li>
<li>E_USER_NOTICE</li>
</ul>
<p><strong>display_errors</strong> = On : 에러 표시 설정(보안상 이 기능 대신 error_log를 사용할 것을 권장)
<strong>display_startup_errors *<em>= Off : PHP 시작시 에러 미표시 설정
*</em>log_errors</strong> = Off : 로그파일에 에러로그 기록여부 설정
<strong>ignore_repeated_errors</strong> = Off : 반복된 에러의 기록여부 설정(Off 설정시 반복 에러 기록 안함)
<strong>track_errors</strong> = Off : $php_errormsg에 마지막 에러/경고 메시지 저장 여부 설정
<strong>;html_errors</strong> = Off : 에러 메세지에 HTML 태그 추가여부 설정(Off 설정시 HTML 태그 미추가)
<strong>;error_prepend_string</strong> = : 에러 메세지 앞에 출력하는 라인 설정
<strong>;error_append_string</strong> = : 에러 메세지의 뒤에 출력하는 라인 설정
<strong>;error_log</strong> = filename : 지정된 파일에 에러 기록
<strong>;error_log</strong> = syslog : syslog에 에러 기록</p>
<br>



<h3 id="data-handling">[Data Handling]</h3>
<p>;arg_separator.output = "&amp;" : PHP가 생성한 URL 인자를 구분하는 구분자 설정
;arg_separator.input = ";&" : PHP가 URL에서 변수를 분리하는데 사용하는 구분자 설정
variables_order = "EGPCS" : EGPCS[각주:14] 변수의 파싱순서 설정(GP로 설정시 GET 변수는 같은 이름의 POST 변수에 덮어씌워짐)
register_globals = Off : 입력 데이터의 글로벌 변수 등록여부 설정(Off 설정시 $var 대신 $<em>REQUEST["var"], $_GET["var"], $_POST["var"] 등으로 써야 함 - 권장)
register_long_arrays = On : $HTTP</em>*_VARS 형태의 예약변수 등록 여부 설정(Off 설정시 $HTTP_GET_VARS 대신 $_GET 등의 자동 전역배열을 사용함 - 권장)
register_argc_argv = On : argc 및 argv 변수의 사용여부 설정
post_max_size = 8M : POST 데이터가 허용하는 최대 사이즈 설정(큰 파일 업로드시 post_max_size가 upload_max_filesize보다 커야함)
magic_quotes_gpc = On : GET/POST/Cookie의 입력 데이터에 포함된 작은 따옴표, 큰 따옴표, 역슬래쉬, NULL은 자동으로 역슬래쉬로 이스케이프할지 설정
magic_quotes_runtime = Off : DB나 텍스트 파일에 포함된 작은 따옴표, 큰 따옴표, 역슬래쉬, NULL을 자동으로 역슬래쉬로 이스케이프할지 설정
magic_quotes_sybase = Off : 작은 따옴표를 &#39; 대신 ''로 변환할지 설정(On 설정시 ''로 변환)
auto_prepend_file =, auto_append_file = : PHP 문서 전후에 추가할 파일 설정
default_mimetype = "text/html", default_charset = "utf-8" : Content-type: 헤더로 출력할 문자 인코딩 설정
;always_populate_raw_post_data = On : 항상 $HTTP_RAW_POST_DATA 변수를 선언할지 설정</p>
<br>


<h3 id="paths-and-directories">[Paths and Directories]</h3>
<p>; include_path = ".:/php/includes" : require(), include(), fopen_with_path() 함수가 파일을 찾는 디렉토리 목록 설정
doc_root = : PHP 루트 디렉토리 설정(안전모드 설정시 루트 디렉토리 밖의 파일은 사용할 수 없음)
user_dir : PHP 파일을 사용하는 유저의 홈 디렉토리(public_html) 이름 설정
extension_dir = "/usr/local/server/php/modules" : 확장모듈 디렉토리 설정
extension = mysqli.so ; : PHP가 시작할 때 읽어들일 모듈 설정
enable_dl = On : dl() 함수를 유효하게 할 것인지 설정
; cgi.force_redirect = 1 : 대부분의 웹서버에서 PHP를 CGI로 사용할 때 보안을 위해 설정(기본값 On)
; cgi.redirect_status_env = ; : ?
; cgi.rfc2616_headers = 0 : PHP가 HTTP 응답코드를 보낼때 사용할 헤더 설정(0 설정시 Status: 헤더를, 1 설정시 RFC 2616 호환 헤더 전송)</p>
<br>


<h3 id="file-uploads">[File Uploads]</h3>
<p>file_uploads = On : 파일 업로드 허가여부 설정
;upload_tmp_dir = : HTTP로 파일 업로드시 임시 작업 디렉토리 설정(미 지정시 시스템 디폴트 디렉토리[각주:15]가 사용됨)
upload_max_filesize = 20M : 업로드 파일의 최대 사이즈 설정</p>
<br>

<h3 id="fopen-wrappers">[Fopen wrappers]</h3>
<p>allow_url_fopen = Off : 파일 액세스시 외부사이트 파일을 불러올 수 있는지여부 설정(보안상 Off로 설정할 것을 권장함)
;from="<a href="mailto:admin@myhome.com">admin@myhome.com</a>" : 익명 FTP의 패스워드 설정
;user_agent = "PHP" : PHP가 전송하는 유저에이전트 설정
default_socket_timeout = 60 : 소켓기반 스트림의 기본 시간제한 설정
;auto_detect_line_endings = Off : fget(), file()로 읽은 데이터의 줄바꿈 방식 선택여부 설정(On 설정시 유닉스, MS-DOS, 매킨토시 방식 중 어떤 것을 사용할 것인지 검사)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] URL 쿼리 문자열에서 ($_GET) 특정 매개 변수 제거하기]]></title>
            <link>https://velog.io/@coding_wizard/PHP-URL-%EC%BF%BC%EB%A6%AC-%EB%AC%B8%EC%9E%90%EC%97%B4%EC%97%90%EC%84%9C-GET-%ED%8A%B9%EC%A0%95-%EB%A7%A4%EA%B0%9C-%EB%B3%80%EC%88%98-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@coding_wizard/PHP-URL-%EC%BF%BC%EB%A6%AC-%EB%AC%B8%EC%9E%90%EC%97%B4%EC%97%90%EC%84%9C-GET-%ED%8A%B9%EC%A0%95-%EB%A7%A4%EA%B0%9C-%EB%B3%80%EC%88%98-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 21 Jun 2022 03:19:47 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-php">function strip_param_from_url( $url, $param ) {
    $base_url = strtok($url, &#39;?&#39;);              // Get the base url
    $parsed_url = parse_url($url);              // Parse it 
    $query = $parsed_url[&#39;query&#39;];              // Get the query string
    parse_str( $query, $parameters );           // Convert Parameters into array
    unset( $parameters[$param] );               // Delete the one you want
    $new_query = http_build_query($parameters); // Rebuilt query string
    return $base_url.&#39;?&#39;.$new_query;            // Finally url is ready
}
// Usage
echo strip_param_from_url( &#39;http://url.com/search/?location=london&amp;page_number=1&#39;, 
    &#39;location&#39; )</code></pre>
<blockquote>
<p><a href="https://code-paper.com/php/examples-php-remove-a-parameter-from-url-query-string">https://code-paper.com/php/examples-php-remove-a-parameter-from-url-query-string</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] 디렉토리 제어(Directories)]]></title>
            <link>https://velog.io/@coding_wizard/PHP-%EB%94%94%EB%A0%89%ED%86%A0%EB%A6%AC-%EC%A0%9C%EC%96%B4Directories</link>
            <guid>https://velog.io/@coding_wizard/PHP-%EB%94%94%EB%A0%89%ED%86%A0%EB%A6%AC-%EC%A0%9C%EC%96%B4Directories</guid>
            <pubDate>Tue, 21 Jun 2022 03:18:31 GMT</pubDate>
            <description><![CDATA[<p>일반적으로 <strong>DIR</strong>이나 <strong>FILE</strong> 등을 활용해 현재 위치를 구해 경로를 제어하지만</p>
<p>실제 터미널과 같이 파일 시스템에서의 디렉토리 제어가 필요한 경우들이 있습니다.</p>
<p>opendir 등은 resource인 open directory handle를 반환합니다.
<br><br></p>
<h2 id="chdirstring-directory-bool">chdir(string $directory): bool</h2>
<p>PHP의 현재 디렉토리를 변경합니다.</p>
<pre><code class="language-php">echo getcwd() . &quot;\n&quot;;
chdir(&#39;public_html&#39;);
echo getcwd() . &quot;\n&quot;;
/* result to:
/home/paric
/home/paric/public_html
*/</code></pre>
<br>

<h2 id="chrootstring-directory-bool">chroot(string $directory): bool</h2>
<p>루트 디렉토리를 변경하고자 할 때 사용되는 함수입니다. 현재 작업 디렉토리를 &quot;/&quot;로 변경합니다.</p>
<p>이 기능은 GNU 및 BSD 시스템에서만 사용할 수 있으며 CLI, CGI 또는 Embed SAPI를 사용할 때만 사용할 수 있습니다. ※ 루트 권한이 필요합니다.</p>
<p>이 함수를 호출해도 <strong>DIR</strong> 및 <strong>FILE</strong>매직 상수의 값은 변경되지 않습니다.</p>
<blockquote>
</blockquote>
<ul>
<li><span style="color:#EF1037">Windows에서 구현되지 않습니다.</span></li>
<li><span style="color:#EF1037">ZTS(Zend Thread Safety)가 활성화된 PHP 인터프리터에서는 사용할 수 없습니다.</span></li>
</ul>
<pre><code class="language-php">chroot(&quot;/path/to/your/chroot/&quot;);
echo getcwd();
/* result to :
/
*/</code></pre>
 <br>

<h2 id="getcwd-stringfalse">getcwd(): string|false</h2>
<p>현재 작업 디렉토리를 가져옵니다.</p>
<p>PHP 인터프리터가 ZTS(Zend Thread Safety)가 활성화된 상태로 빌드된 경우 getcwd()가 반환하는 현재 작업 디렉터리는 운영 체제 인터페이스에서 반환된 디렉터리와 다를 수 있습니다.</p>
<br>


<h2 id="scandirstring-directory-int-sorting_order--scandir_sort_ascending-resource-context--null-arrayfalse">scandir(string $directory, int $sorting_order = SCANDIR_SORT_ASCENDING, ?resource $context = null): array|false</h2>
<p>지정된 경로 내에 있는 파일 및 디렉토리를 배열로 반환합니다.</p>
<br>


<h2 id="opendirstring-directory-resource-context--null-resourcefalse">opendir(string $directory, ?resource $context = null): resource|false</h2>
<p>closedir() , readdir() 및 rewinddir() 호출에서 사용할 디렉토리 핸들을 엽니다.</p>
<br>


<h2 id="closedirresource-dir_handle--null-void">closedir(?resource $dir_handle = null): void</h2>
<p> dir_handle로 표시된 디렉토리 스트림을 닫습니다. 스트림은 이전에 opendir() 에 의해 열려 있어야 합니다 .</p>
<pre><code class="language-php">$dir = &quot;/etc/php5/&quot;;

// 디렉토리를 열고 디렉토리를 변수로 읽은 다음 닫습니다.
if (is_dir($dir)) {
    if ($dh = opendir($dir)) {
        $directory = readdir($dh);
        closedir($dh);
    }
}</code></pre>
<br>

<h2 id="readdirresource-dir_handle--null-stringfalse">readdir(?resource $dir_handle = null): string|false</h2>
<p>디렉토리에서 다음 항목의 이름을 반환합니다. 항목은 파일 시스템에 저장된 순서대로 반환됩니다.</p>
<p>PHP8부터 $dir_handle은 nullalbe해 졌습니다. $dir_handle 값이 null일 경우opendir()에 의해 열린 마지막 링크로 가정됩니다.</p>
<br> 

<h2 id="rewinddirresource-dir_handle--null-void">rewinddir(?resource $dir_handle = null): void</h2>
<p>dir_handle로 표시된 디렉토리 스트림을 디렉토리의 시작 부분으로 재설정합니다.</p>
<p>readdir()을 실행할 때 마다 커서가 옮겨지게되는데 이를 초기화하는 함수라 보면 됩니다.</p>
 <br>

<hr>
<h2 id="directories">Directories</h2>
<h3 id="미리-정의된-상수"><a href="http://docs.php.net/manual/en/dir.constants.php">미리 정의된 상수</a></h3>
<h3 id="디렉토리--디렉토리-클래스"><a href="http://docs.php.net/manual/en/class.directory.php">디렉토리</a> — 디렉토리 클래스</h3>
<ul>
<li>Directory::close — 디렉토리 핸들 닫기</li>
<li>Directory::read — 디렉토리 핸들에서 항목 읽기</li>
<li>Directory::rewind — 디렉토리 핸들 되감기</li>
</ul>
<h3 id="디렉토리-기능"><a href="http://docs.php.net/manual/en/ref.dir.php">디렉토리 기능</a></h3>
<ul>
<li>chdir — 디렉토리 변경</li>
<li>chroot — 루트 디렉토리 변경</li>
<li>Closedir — 디렉토리 핸들 닫기</li>
<li>dir — Directory 클래스의 인스턴스를 반환합니다.</li>
<li>getcwd — 현재 작업 디렉토리를 가져옵니다.</li>
<li>opendir — 디렉토리 핸들 열기</li>
<li>readdir — 디렉토리 핸들에서 항목 읽기</li>
<li>rewinddir — 디렉토리 핸들 되감기</li>
<li>scandir — 지정된 경로 내의 파일 및 디렉토리 나열</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP]파일시스템(file system)]]></title>
            <link>https://velog.io/@coding_wizard/PHP%ED%8C%8C%EC%9D%BC%EC%8B%9C%EC%8A%A4%ED%85%9Cfile-system</link>
            <guid>https://velog.io/@coding_wizard/PHP%ED%8C%8C%EC%9D%BC%EC%8B%9C%EC%8A%A4%ED%85%9Cfile-system</guid>
            <pubDate>Tue, 21 Jun 2022 03:12:37 GMT</pubDate>
            <description><![CDATA[<h3 id="basenamestring-path-string-suffix---string">basename(string $path, string $suffix = &quot;&quot;): string</h3>
<p>파일이나 디렉토리에 대한 경로를 포함하는 문자열이 주어지면 이 함수는 후행 이름 구성요소를 반환합니다.
<strong>basename()</strong> 은 로케일을 인식하므로 멀티바이트 문자 경로가 있는 올바른 기본 이름을 보려면 <a href="http://docs.php.net/manual/en/function.setlocale.php">setlocale()</a> 함수를 사용하여 일치하는 로케일을 설정해야 합니다. path현재 로케일에 유효하지 않은 문자가 포함되어있으면 <strong>basename()</strong> 의 동작 이 정의되지 않습니다.</p>
<ul>
<li><a href="http://docs.php.net/manual/en/function.dirname.php">dirname()</a> - 상위 디렉토리의 경로를 반환합니다.</li>
<li><a href="http://docs.php.net/manual/en/function.pathinfo.php">pathinfo()</a> - 파일 경로에 대한 정보를 반환합니다.</li>
</ul>
<pre><code class="language-php">echo &quot;1) &quot;.basename(&quot;/etc/sudoers.d&quot;, &quot;.d&quot;).PHP_EOL;
echo &quot;2) &quot;.basename(&quot;/etc/sudoers.d&quot;).PHP_EOL;
echo &quot;3) &quot;.basename(&quot;/etc/passwd&quot;).PHP_EOL;
echo &quot;4) &quot;.basename(&quot;/etc/&quot;).PHP_EOL;
echo &quot;5) &quot;.basename(&quot;.&quot;).PHP_EOL;
echo &quot;6) &quot;.basename(&quot;/&quot;);
/* result to:
    1) sudoers
    2) sudoers.d
    3) passwd
    4) etc
    5) .
    6) 
*/</code></pre>
<h2 id="realpathstring-path-stringfalse">realpath(string $path): string|false</h2>
<p>정규화된 절대 경로 이름을 반환 합니다. 성공 시 정규화된 절대 경로 이름을 반환합니다. 결과 경로에는 기호 링크 /./, /../ 또는 extra /구성 요소가 없습니다. \및 /와 같은 후행 구분 기호도 제거됩니다.</p>
<p>실행 중인 스크립트에는 계층 구조의 모든 디렉토리에 대한 실행 권한이 있어야 합니다. 그렇지 않으면 realpath()가 false를 반환 합니다.</p>
<h3 id="예제-1">예제 #1</h3>
<pre><code class="language-php">chdir(&#39;/var/www/&#39;);
echo realpath(&#39;./../../etc/passwd&#39;) . PHP_EOL;
echo realpath(&#39;/tmp/&#39;) . PHP_EOL;
/* 출력결과:
/etc/passwd 
/tmp
*/</code></pre>
<h3 id="예제-2--windows의-realpath">예제 #2.  Windows의 realpath()</h3>
<pre><code class="language-php">echo realpath(&#39;/windows/system32&#39;), PHP_EOL;
echo realpath(&#39;C:\Program Files\\&#39;), PHP_EOL;
/* 실행 결과
C:\WINDOWS\System32
C:\Program Files
*/</code></pre>
<h2 id="pathinfostring-path-int-flags--pathinfo_all-arraystring">pathinfo(string $path, int $flags = PATHINFO_ALL): array|string</h2>
<p>파일 경로에 대한 정보를 반환합니다. 현재 경로 정보 검색에 대한 정보는 <a href="http://docs.php.net/manual/en/language.variables.predefined.php">사전 정의된 예약 변수</a> 섹션을 참조하세요.</p>
<blockquote>
<p><strong>※ pathinfo()</strong> 는 로케일을 인식하므로 멀티바이트 문자가 포함된 경로를 올바르게 구문 분석하려면 setlocale() 함수를 사용하여 일치하는 로케일을 설정해야 합니다.</p>
</blockquote>
<br>

<h3 id="예제-1-pathinfo-기본-사용">예제 #1 pathinfo() 기본 사용</h3>
<pre><code class="language-php">$path_parts = pathinfo(&#39;/www/htdocs/inc/lib.inc.php&#39;);
echo $path_parts[&#39;dirname&#39;], &quot;\n&quot;;
echo $path_parts[&#39;basename&#39;], &quot;\n&quot;;
echo $path_parts[&#39;extension&#39;], &quot;\n&quot;;
echo $path_parts[&#39;filename&#39;], &quot;\n&quot;;
/* output:
/www/htdocs/inc
lib.inc.php
php
lib.inc
*/</code></pre>
<h2 id="globstring-pattern-int-flags--0-arrayfalse">glob(string $pattern, int $flags = 0): array|false</h2>
<p>libc glob() 함수에서 사용하는 규칙에 따라 pattern에 일치하는 모든 경로 이름을 검색합니다. 이는 일반적인 셸에서 사용하는 규칙과 유사합니다.</p>
<pre><code class="language-php">foreach (glob(&quot;*.txt&quot;) as $filename) {
    echo &quot;$filename size &quot; . filesize($filename) . &quot;\n&quot;;
}
/* result to:
funclist.txt size 44686
funcsummary.txt size 267625
quickref.txt size 137820
*/</code></pre>
<h2 id="fnmatchstring-pattern-string-filename-int-flags--0-bool">fnmatch(string $pattern, string $filename, int $flags = 0): bool</h2>
<p>전달된 $filename 항목이 지정된 $pattern이 일치하는지 판별합니다. (패턴에 대해 파일 이름 일치 여부 체크)</p>
<p>사실 fnmatch보다는 결국 정규표현식을 활용해 체크하는게 일반적인 방법 입니다.</p>
<br>

<h2 id="copystring-from-string-to-resource-context--null-bool">copy(string $from, string $to, ?resource $context = null): bool</h2>
<p>$from에 파일 $to를 복사 합니다. 파일을 이동하려면 rename() 함수를 사용하세요!</p>
<p>※ 대상 파일이 이미 있는 경우 덮어씁니다.</p>
<ul>
<li><p><a href="http://docs.php.net/manual/en/function.move-uploaded-file.php">move_uploaded_file()</a> - 업로드된 파일을 새 위치로 이동합니다.</p>
</li>
<li><p><a href="http://docs.php.net/manual/en/function.rename.php">rename()</a> - 파일 또는 디렉토리의 이름을 바꿉니다.</p>
<br>

</li>
</ul>
<h2 id="mkdirstring-directory-int-permissions--0777-bool-recursive--false-resource-context--null-bool">mkdir(string $directory, int $permissions = 0777, bool $recursive = false, ?resource $context = null): bool</h2>
<p>$directory에 의해 지정된 디렉토리 생성을 시도합니다.</p>
<p>is_dir() - 파일 이름이 디렉토리인지 여부를 알려줍니다.</p>
<br>


<h2 id="rmdirstring-directory-resource-context--null-bool">rmdir(string $directory, ?resource $context = null): bool</h2>
<p>$directory에 의해 명명된 디렉토리를 제거하려고 시도합니다. 디렉토리는 비어 있어야 하며 관련 권한이 이를 허용해야 합니다. </p>
<br>


<h2 id="unlinkstring-filename-resource-context--null-bool">unlink(string $filename, ?resource $context = null): bool</h2>
<p>$filename을 삭제 합니다. Unix C unlink() 함수와 유사합니다. </p>
 <br>


<h2 id="fopen----string-filename----string-mode----bool-use_include_path--false----resource-context--null-resourcefalse">fopen(    string $filename,    string $mode,    bool $use_include_path = false,    ?resource $context = null): resource|false</h2>
<p>파일 또는 URL을 엽니다.</p>
<pre><code class="language-php">$handle = fopen(&quot;/home/rasmus/file.txt&quot;, &quot;r&quot;);
$handle = fopen(&quot;/home/rasmus/file.gif&quot;, &quot;wb&quot;);
$handle = fopen(&quot;http://www.example.com/&quot;, &quot;r&quot;);
$handle = fopen(&quot;ftp://user:password@example.com/somefile.txt&quot;, &quot;w&quot;);</code></pre>
<p>** fopen()**의 사용 가능한 $mode 목록 및 설명
<img src="https://velog.velcdn.com/images/coding_wizard/post/a2229662-f770-4e99-a79b-7d3d932d4b69/image.png" alt=""></p>
<h2 id="file_get_contentsstring-filename-bool-use_include_path--false-resource-context--null----int-offset--0----int-length--null-stringfalse">file_get_contents(string $filename, bool $use_include_path = false, ?resource $context = null,    int $offset = 0,    ?int $length = null): string|false</h2>
<p>전체 파일을 문자열로 읽습니다. 이 함수는 file_get_contents() 가 지정된 최대 바이트에서 시작하여 문자열로 파일을 반환 한다는 점을 제외하면 file() 과 유사합니다. </p>
<p>※ 공백과 같은 특수 문자가 있는 URI를 여는 경우 urlencode() 를 사용하여 URI를 인코딩해야 합니다 .</p>
 <br>

<h2 id="filestring-filename-int-flags--0-resource-context--null-arrayfalse">file(string $filename, int $flags = 0, ?resource $context = null): array|false</h2>
<p>전체 파일을 배열로 반환해 줍니다.</p>
<ul>
<li>file_get_contents() 를 사용하여 파일의 내용을 문자열로 반환 할 수 있습니다 .</li>
</ul>
<p>라인별로 각 index key마다 담기게 되는데 $flags 옵션을 통해 빈 라인은 제외할 수도 있습니다.</p>
 <br>


<h2 id="readfilestring-filename-bool-use_include_path--false-resource-context--null-intfalse">readfile(string $filename, bool $use_include_path = false, ?resource $context = null): int|false</h2>
<p> 파일을 출력합니다.</p>
<h3 id="예제-1-readfile을-사용하여-강제-다운로드">예제 #1 readfile()을 사용하여 강제 다운로드</h3>
<pre><code class="language-php">$file = &#39;monkey.gif&#39;;

if (file_exists($file)) {
    header(&#39;Content-Description: File Transfer&#39;);
    header(&#39;Content-Type: application/octet-stream&#39;);
    header(&#39;Content-Disposition: attachment; filename=&quot;&#39;.basename($file).&#39;&quot;&#39;);
    header(&#39;Expires: 0&#39;);
    header(&#39;Cache-Control: must-revalidate&#39;);
    header(&#39;Pragma: public&#39;);
    header(&#39;Content-Length: &#39; . filesize($file));
    readfile($file);
    exit;
}</code></pre>
 <br>


<h2 id="fgetsresource-stream-int-length--null-stringfalse">fgets(resource $stream, ?int $length = null): string|false</h2>
<p>파일 포인터에서 한 줄을 가져옵니다.</p>
<h3 id="예제-1-파일을-한-줄씩-읽기">예제 #1. 파일을 한 줄씩 읽기</h3>
<pre><code class="language-php">$fp = @fopen(&quot;/tmp/inputfile.txt&quot;, &quot;r&quot;);
if ($fp) {
    while (($buffer = fgets($fp, 4096)) !== false) {
        echo $buffer;
    }
    if (!feof($fp)) {
        echo &quot;Error: unexpected fgets() fail\n&quot;;
    }
    fclose($fp);
}</code></pre>
<br>

<h2 id="feofresource-stream-bool">feof(resource $stream): bool</h2>
<p>파일 포인터에서 파일 끝을 테스트합니다. 파일의 끝인지 알아보고 끝이 아니면 다음 라인을 가져올 때 체크용으로 사용합니다.</p>
<br>

<h2 id="fseekresource-stream-int-offset-int-whence--seek_set-int">fseek(resource $stream, int $offset, int $whence = SEEK_SET): int</h2>
<p>파일 포인터를 찾거나 설정합니다.</p>
<p>$whence값은 다음과 같습니다.</p>
<p>SEEK_SET- 위치를 offset바이트와 ​​동일하게 설정합니다.
SEEK_CUR- 위치를 현재 위치 플러스로 설정 offset합니다.
SEEK_END- 위치를 파일 끝 플러스로 설정합니다 offset.</p>
<pre><code class="language-php">$fp = fopen(&#39;somefile.txt&#39;, &#39;r&#39;);
$data = fgets($fp, 4096);
fseek($fp, 0);</code></pre>
 <br>

<h2 id="ftellresource-stream-intfalse">ftell(resource $stream): int|false</h2>
<p>파일 읽기/쓰기 포인터의 현재 위치를 반환합니다.</p>
<p>$fp = fopen(&quot;/etc/passwd&quot;, &quot;r&quot;);
$data = fgets($fp, 12);
echo ftell($fp); // 11
fclose($fp);
rewind() - 파일 포인터의 위치를 ​​되감습니다.</p>
 <br>

<h2 id="rewindresource-stream-bool">rewind(resource $stream): bool</h2>
<p> 파일 포인터의 위치를 초기화합니다.</p>
 <br>

<h2 id="fpassthruresource-stream-int">fpassthru(resource $stream): int</h2>
<p>파일 포인터에 남아 있는 모든 데이터 출력</p>
 <br>

<h2 id="freadresource-stream-int-length-stringfalse">fread(resource $stream, int $length): string|false</h2>
<pre><code class="language-php">// get contents of a file into a string
$filename = &quot;/usr/local/something.txt&quot;;
$handle = fopen($filename, &quot;r&quot;);
$contents = fread($handle, filesize($filename));
fclose($handle);</code></pre>
 <br>

<h2 id="fwriteresource-stream-string-data-int-length--null-intfalse">fwrite(resource $stream, string $data, ?int $length = null): int|false</h2>
<p>파일 스트림에 데이터를 씁니다.</p>
 <br>

<h2 id="file_put_contents-string-filename-mixed-data-int-flags--0-resource-context--null--intfalse">file_put_contents( string $filename, mixed $data, int $flags = 0, ?resource $context = null ): int|false</h2>
<p>파일에 데이터를 쓰는 함수로, fopen() , fwrite() 및 fclose() 를 연속적으로 호출하여 파일에 데이터를 쓰는 것과 동일합니다.</p>
 <br>

<h2 id="fflushresource-stream-bool">fflush(resource $stream): bool</h2>
<p>이 함수는 버퍼링된 모든 출력을 파일이 가리키는 리소스에 강제로 기록합니다</p>
 <br>

<h3 id="예제-1-fflush-를-사용한-파일-쓰기-예제">예제 #1 fflush() 를 사용한 파일 쓰기 예제</h3>
<pre><code class="language-php">$filename = &#39;bar.txt&#39;;

$file = fopen($filename, &#39;r+&#39;);
rewind($file);
fwrite($file, &#39;Foo&#39;);
fflush($file);
ftruncate($file, ftell($file));
fclose($file);</code></pre>
 <br>

<h2 id="ftruncateresource-stream-int-size-bool">ftruncate(resource $stream, int $size): bool</h2>
<p>파일을 주어진 길이로 자릅니다.</p>
 <br>


<h2 id="fcloseresource-stream-bool">fclose(resource $stream): bool</h2>
<p>열려 있는 파일 포인터를 닫습니다.</p>
 <br>

<h2 id="handle--fopensomefiletxt-r">$handle = fopen(&#39;somefile.txt&#39;, &#39;r&#39;);</h2>
<p>fclose($handle);</p>
 <br>

<h2 id="fstatresource-stream-arrayfalse">fstat(resource $stream): array|false</h2>
<p>열린 파일 포인터를 사용하여 파일에 대한 정보를 가져 옵니다.</p>
 <br>

<h2 id="statstring-filename-arrayfalse">stat(string $filename): array|false</h2>
<p>fstat()과 달리 파일 경로를 통해 파일에 대한 정보를 가져옵니다.</p>
 <br>

<h2 id="linkstring-target-string-link-bool">link(string $target, string $link): bool</h2>
<p>하드 링크를 생성합니다.</p>
  <br>

<h2 id="symlinkstring-target-string-link-bool">symlink(string $target, string $link): bool</h2>
<p> 심볼릭 링크를 생성합니다.</p>
<blockquote>
<p>link() - 하드 링크 생성
readlink() - 심볼릭 링크의 대상을 반환합니다. (원본)
linkinfo() - 링크에 대한 정보를 가져 옵니다.
unlink() - 파일 삭제</p>
</blockquote>
<p>  <br><br></p>
<h2 id="파일-개별-정보-가져오기">파일 개별 정보 가져오기</h2>
<blockquote>
<p>fileatime — 파일의 마지막 액세스 시간을 가져 옵니다.
filectime — 파일의 inode 변경 시간을 가져 옵니다.
filegroup — 파일 그룹을 가져 옵니다.
fileinode — 파일 inode를 가져 옵니다.
filemtime — 파일 수정 시간을 가져 옵니다.
fileowner — 파일 소유자 가져 오기
fileperms — 파일 권한 을 얻습니다.
filesize — 파일 크기 가져 오기
filetype — 파일 형식 가져 오기</p>
</blockquote>
 <br>

<h2 id="기본-검증">기본 검증</h2>
<blockquote>
<p>is_dir — 파일 이름이 디렉토리인지 여부를 알려줍니다.
is_file — 파일 이름이 일반 파일인지 여부를 알려줍니다.
is_link — 파일 이름이 심볼릭 링크인지 여부를 알려줍니다.
is_executable — 파일 이름이 실행 가능한지 여부를 알려줍니다.
is_readable — 파일이 존재하고 읽을 수 있는지 여부를 알려줍니다.
is_uploaded_file — 파일이 HTTP POST를 통해 업로드되었는지 여부를 알려줍니다.
is_writable — 파일 이름이 쓰기 가능한지 여부를 알려줍니다.
is_writeable — is_writable의 별칭</p>
</blockquote>
<p> <br><br></p>
<h2 id="filesystem">Filesystem</h2>
<h3 id="predefined-constants"><a href="http://docs.php.net/manual/en/filesystem.constants.php">Predefined Constants</a></h3>
<h3 id="filesystem-functions"><a href="http://docs.php.net/manual/en/ref.filesystem.php">Filesystem Functions</a></h3>
<ul>
<li>basename — 경로의 후행 이름 구성요소를 반환합니다.</li>
<li>chgrp — 파일 그룹 변경</li>
<li>chmod — 파일 모드 변경</li>
<li>chown — 파일 소유자 변경</li>
<li>clearstatcache — 파일 상태 캐시를 지웁니다.</li>
<li>copy — 파일을 복사합니다.</li>
<li>delete — 연결 해제 또는 설정 해제 참조</li>
<li>dirname — 상위 디렉토리의 경로를 반환합니다.</li>
<li>disk_free_space — 파일 시스템 또는 디스크 파티션에서 사용 가능한 공간을 반환합니다.</li>
<li>disk_total_space — 파일 시스템 또는 디스크 파티션의 전체 크기를 반환합니다.</li>
<li>diskfreespace — disk_free_space의 별칭</li>
<li>fclose — 열려 있는 파일 포인터를 닫습니다.</li>
<li>fdatasync — 데이터(메타 데이터 제외)를 파일에 동기화합니다.</li>
<li>feof — 파일 포인터에서 파일 끝 테스트</li>
<li>fflush — 출력을 파일로 플러시합니다.</li>
<li>fgetc — 파일 포인터에서 문자 가져오기</li>
<li>fgetcsv — 파일 포인터에서 행을 가져오고 CSV 필드에 대한 구문 분석</li>
<li>fgets — 파일 포인터에서 라인 가져오기</li>
<li>fgetss — 파일 포인터에서 줄을 가져오고 HTML 태그를 제거합니다.</li>
<li>file_exists — 파일이나 디렉토리가 존재하는지 확인</li>
<li>file_get_contents — 전체 파일을 문자열로 읽습니다.</li>
<li>file_put_contents — 파일에 데이터 쓰기</li>
<li>file — 전체 파일을 배열로 읽습니다.</li>
<li>fileatime — 파일의 마지막 액세스 시간을 가져 옵니다.</li>
<li>filectime — 파일의 inode 변경 시간을 가져 옵니다.</li>
<li>filegroup — 파일 그룹을 가져 옵니다.</li>
<li>fileinode — 파일 inode를 가져 옵니다.</li>
<li>filemtime — 파일 수정 시간을 가져 옵니다.</li>
<li>fileowner — 파일 소유자 가져 오기</li>
<li>fileperms — 파일 권한 을 얻습니다.</li>
<li>filesize — 파일 크기 가져 오기</li>
<li>filetype — 파일 형식 가져 오기</li>
<li>flock — 이동 가능한 자문 파일 잠금</li>
<li>fnmatch — 패턴에 대해 파일 이름 일치</li>
<li>fopen — 파일 또는 URL을 엽니 다.</li>
<li>fpassthru — 파일 포인터에 남아 있는 모든 데이터 출력</li>
<li>fputcsv — 행을 CSV로 형식화하고 파일 포인터에 쓰기</li>
<li>fputs — fwrite의 별칭</li>
<li>fread — 바이너리 안전 파일 읽기</li>
<li>fscanf — 형식에 따라 파일의 입력을 구문 분석합니다.</li>
<li>fseek — 파일 포인터 찾기</li>
<li>fstat — 열린 파일 포인터를 사용하여 파일에 대한 정보를 가져 옵니다.</li>
<li>fsync — 파일의 변경 사항을 동기화합니다(메타 데이터 포함).</li>
<li>ftell — 파일 읽기/쓰기 포인터의 현재 위치를 반환합니다.</li>
<li>ftruncate — 파일을 주어진 길이로 자릅니다.</li>
<li>fwrite — 이진 안전 파일 쓰기</li>
<li>glob — 패턴과 일치하는 경로 이름 찾기</li>
<li>is_dir — 파일 이름이 디렉토리인지 여부를 알려줍니다.</li>
<li>is_executable — 파일 이름이 실행 가능한지 여부를 알려줍니다.</li>
<li>is_file — 파일 이름이 일반 파일인지 여부를 알려줍니다.</li>
<li>is_link — 파일 이름이 심볼릭 링크인지 여부를 알려줍니다.</li>
<li>is_readable — 파일이 존재하고 읽을 수 있는지 여부를 알려줍니다.</li>
<li>is_uploaded_file — 파일이 HTTP POST를 통해 업로드되었는지 여부를 알려줍니다.</li>
<li>is_writable — 파일 이름이 쓰기 가능한지 여부를 알려줍니다.</li>
<li>is_writeable — is_writable의 별칭</li>
<li>lchgrp — 심볼릭 링크의 그룹 소유권 변경</li>
<li>lchown — symlink의 사용자 소유권 변경</li>
<li>link — 하드 링크 만들기</li>
<li>linkinfo — 링크에 대한 정보를 가져 옵니다.</li>
<li>lstat — 파일 또는 심볼릭 링크에 대한 정보 제공</li>
<li>mkdir — 디렉토리를 만듭니다.</li>
<li>move_uploaded_file — 업로드된 파일을 새 위치로 이동합니다.</li>
<li>parse_ini_file — 구성 파일 구문 분석</li>
<li>parse_ini_string — 구성 문자열 구문 분석</li>
<li>pathinfo — 파일 경로에 대한 정보를 반환합니다.</li>
<li>pclose — 프로세스 파일 포인터를 닫습니다.</li>
<li>popen — 프로세스 파일 포인터를 엽니 다.</li>
<li>readfile — 파일을 출력합니다.</li>
<li>readlink — 심볼릭 링크의 대상을 반환합니다.</li>
<li>realpath_cache_get — 실제 경로 캐시 항목 가져오기</li>
<li>realpath_cache_size — 실제 경로 캐시 크기 가져오기</li>
<li>realpath — 정규화된 절대 경로 이름을 반환 합니다.</li>
<li>rename — 파일 또는 디렉터리의 이름을 바꿉니다.</li>
<li>rewind — 파일 포인터의 위치를 ​​되감습니다.</li>
<li>rmdir — 디렉토리 제거</li>
<li>set_file_buffer — stream_set_write_buffer의 별칭</li>
<li>stat — 파일에 대한 정보 제공</li>
<li>symlink — 심볼릭 링크를 생성합니다.</li>
<li>tempnam — 고유한 파일 이름으로 파일 생성</li>
<li>tmpfile — 임시 파일을 생성합니다.</li>
<li>touch — 파일의 액세스 및 수정 시간 설정</li>
<li>umask — 현재 umask를 변경합니다.</li>
<li>unlink — 파일을 삭제합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[PHP] 스트림(Streams)]]></title>
            <link>https://velog.io/@coding_wizard/PHP-%EC%8A%A4%ED%8A%B8%EB%A6%BCStreams</link>
            <guid>https://velog.io/@coding_wizard/PHP-%EC%8A%A4%ED%8A%B8%EB%A6%BCStreams</guid>
            <pubDate>Tue, 21 Jun 2022 02:40:28 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Tistory로 작성된 글을 Velog로 옮기는 중입니다.
원글 : <a href="https://paric.tistory.com/787">https://paric.tistory.com/787</a></p>
</blockquote>
<h3 id="stream_context_createarray-options--null-array-params--null-resource">stream_context_create(?array $options = null, ?array $params = null): resource</h3>
<p>사전 설정 에 제공된 모든 옵션을 사용하여 스트림 컨텍스트를 만들고 반환합니다</p>
<blockquote>
<p>stream_context_create — 스트림 컨텍스트를 생성합니다.
stream_context_get_default — 기본 스트림 컨텍스트 검색
stream_context_get_options — 스트림/래퍼/컨텍스트에 대한 옵션 검색
stream_context_get_params — 컨텍스트에서 매개변수를 검색합니다.
stream_context_set_default — 기본 스트림 컨텍스트 설정
stream_context_set_option — 스트림/래퍼/컨텍스트에 대한 옵션을 설정합니다.
stream_context_set_params — 스트림/래퍼/컨텍스트에 대한 매개변수 설정</p>
</blockquote>
<br>

<h3 id="stream_context_set_option">stream_context_set_option</h3>
<p>(    resource $stream_or_context,    string $wrapper,    string $option,    mixed $value): bool</p>
<br>

<h3 id="stream_context_set_optionresource-stream_or_context-array-options-bool">stream_context_set_option(resource $stream_or_context, array $options): bool</h3>
<p>스트림/래퍼/컨텍스트에 대한 옵션을 설정합니다.</p>
<p>스트림 옵션 목록은 <a href="http://docs.php.net/manual/en/context.php">컨텍스트 옵션 및 매개변수</a> 를 참조하세요</p>
<pre><code class="language-php">$opts = array(
  &#39;http&#39;=&gt;array(
    &#39;method&#39;=&gt;&quot;GET&quot;,
    &#39;header&#39;=&gt;&quot;Accept-language: en\r\n&quot; .
              &quot;Cookie: foo=bar\r\n&quot;
  )
);

$context = stream_context_create($opts);

$fp = fopen(&#39;http://www.example.com&#39;, &#39;r&#39;, false, $context);
fpassthru($fp);
fclose($fp);</code></pre>
<p><br><br></p>
<h1 id="스트림-필터">스트림 필터</h1>
<hr>
<h3 id="stream_get_filters-array">stream_get_filters(): array</h3>
<p>실행 중인 시스템에 등록된 필터 목록을 검색합니다.</p>
<blockquote>
</blockquote>
<p>stream_filter_append — 스트림에 필터 연결
stream_filter_prepend — 스트림에 필터 연결
stream_filter_register — 사용자 정의 스트림 필터 등록
stream_filter_remove — 스트림에서 필터 제거</p>
<br>


<h2 id="스트림-socket">스트림 Socket</h2>
<blockquote>
<p>stream_socket_server — 인터넷 또는 Unix 도메인 서버 소켓 생성
stream_socket_client — 인터넷 또는 Unix 도메인 소켓 연결 열기
stream_socket_accept — stream_socket_server에 의해 생성된 소켓에 대한 연결 수락
stream_socket_enable_crypto — 이미 연결된 소켓에서 암호화 켜기/끄기
stream_socket_get_name — 로컬 또는 원격 소켓의 이름 검색
stream_socket_pair — 연결되고 구별할 수 없는 소켓 스트림 쌍을 생성합니다.
stream_socket_recvfrom — 연결 여부에 관계없이 소켓에서 데이터 수신
stream_socket_sendto — 연결 여부에 관계없이 소켓에 메시지를 보냅니다.
stream_socket_shutdown — 전이중 연결 종료</p>
</blockquote>
 <br>

<h3 id="예제-1-tcp-서버-소켓-사용">예제 #1 TCP 서버 소켓 사용</h3>
<pre><code class="language-php">$socket = stream_socket_server(&quot;tcp://0.0.0.0:8000&quot;, $errno, $errstr);

if (!$socket) {
  echo &quot;$errstr ($errno)&lt;br /&gt;\n&quot;;
} else {
  while ($conn = stream_socket_accept($socket)) {
    fwrite($conn, &#39;The local time is &#39; . date(&#39;n/j/Y g:i a&#39;) . &quot;\n&quot;);
    fclose($conn);
  }
  fclose($socket);
}</code></pre>
<br>

<h3 id="예제-2-udp-서버-소켓-사용">예제 #2 UDP 서버 소켓 사용</h3>
<pre><code class="language-php">$socket = stream_socket_server(&quot;udp://127.0.0.1:1113&quot;, $errno, $errstr, STREAM_SERVER_BIND);
if (!$socket) {
    die(&quot;$errstr ($errno)&quot;);
}
do {
    $pkt = stream_socket_recvfrom($socket, 1, 0, $peer);
    echo &quot;$peer\n&quot;;
    stream_socket_sendto($socket, date(&quot;D M j H:i:s Y\r\n&quot;), 0, $peer);
} while ($pkt !== false);
예제 #3. stream_socket_client() TCP 예제

$fp = stream_socket_client(&quot;tcp://www.example.com:80&quot;, $errno, $errstr, 30);
if (!$fp) {
    echo &quot;$errstr ($errno)&lt;br /&gt;\n&quot;;
} else {
    fwrite($fp, &quot;GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n&quot;);
    while (!feof($fp)) {
        echo fgets($fp, 1024);
    }
    fclose($fp);
}</code></pre>
<br>

<h3 id="예제-3-stream_socket_client-udp-연결-예제">예제 #3. stream_socket_client() UDP 연결 예제</h3>
<p>localhost의 UDP 서비스 &quot;daytime&quot;(포트 13)에서 날짜와 시간을 검색합니다.</p>
<pre><code class="language-php">$fp = stream_socket_client(&quot;udp://127.0.0.1:13&quot;, $errno, $errstr);
if (!$fp) {
    echo &quot;ERROR: $errno - $errstr&lt;br /&gt;\n&quot;;
} else {
    fwrite($fp, &quot;\n&quot;);
    echo fread($fp, 26);
    fclose($fp);
}</code></pre>
<h2 id="brbrbr"> <br><br><br></h2>
<h1 id="참고-사항">참고 사항</h1>
<h3 id="php_user_filter--php_user_filter-클래스"><a href="http://docs.php.net/manual/en/class.php-user-filter.php">php_user_filter</a> — php_user_filter 클래스</h3>
<ul>
<li>php_user_filter::filter — 필터를 적용할 때 호출됩니다.</li>
<li>php_user_filter::onClose — 필터를 닫을 때 호출됩니다.</li>
<li>php_user_filter::onCreate — 필터를 생성할 때 호출됩니다.</li>
</ul>
<h3 id="streamwrapper--streamwrapper-클래스"><a href="http://docs.php.net/manual/en/class.streamwrapper.php">streamWrapper</a> — streamWrapper 클래스</h3>
<ul>
<li>streamWrapper::__construct — 새 스트림 래퍼를 생성합니다.</li>
<li>streamWrapper::__destruct — 기존 스트림 래퍼를 파괴합니다.</li>
<li>streamWrapper::dir_closedir — 디렉토리 핸들 닫기</li>
<li>streamWrapper::dir_opendir — 디렉토리 핸들 열기</li>
<li>streamWrapper::dir_readdir — 디렉토리 핸들에서 항목 읽기</li>
<li>streamWrapper::dir_rewinddir — 디렉토리 핸들 되감기</li>
<li>streamWrapper::mkdir — 디렉토리 생성</li>
<li>streamWrapper::rename — 파일 또는 디렉토리의 이름을 바꿉니다.</li>
<li>streamWrapper::rmdir — 디렉토리를 제거합니다.</li>
<li>streamWrapper::stream_cast — 기본 리소스 검색</li>
<li>streamWrapper::stream_close — 리소스 닫기</li>
<li>streamWrapper::stream_eof — 파일 포인터에서 파일 끝 테스트</li>
<li>streamWrapper::stream_flush — 출력을 플러시합니다.</li>
<li>streamWrapper::stream_lock — 권고 파일 잠금</li>
<li>streamWrapper::stream_metadata — 스트림 메타데이터 변경</li>
<li>streamWrapper::stream_open — 파일 또는 URL을 엽니 다.</li>
<li>streamWrapper::stream_read — 스트림에서 읽기</li>
<li>streamWrapper::stream_seek — 스트림의 특정 위치를 찾습니다.</li>
<li>streamWrapper::stream_set_option — 스트림 옵션 변경</li>
<li>streamWrapper::stream_stat — 파일 리소스에 대한 정보 검색</li>
<li>streamWrapper::stream_tell — 스트림의 현재 위치 검색</li>
<li>streamWrapper::stream_truncate — 스트림 자르기</li>
<li>streamWrapper::stream_write — 스트림에 쓰기</li>
<li>streamWrapper::unlink — 파일 삭제</li>
<li>streamWrapper::url_stat — 파일에 대한 정보 검색</li>
</ul>
<h3 id="스트림-함수"><a href="http://docs.php.net/manual/en/ref.stream.php">스트림 함수</a></h3>
<ul>
<li>stream_bucket_append — 여단에 버킷 추가</li>
<li>stream_bucket_make_writeable — 여단에서 작업할 버킷 객체를 반환합니다.</li>
<li>stream_bucket_new — 현재 스트림에서 사용할 새 버킷 생성</li>
<li>stream_bucket_prepend — 여단 앞에 버킷 추가</li>
<li>stream_context_create — 스트림 컨텍스트를 생성합니다.</li>
<li>stream_context_get_default — 기본 스트림 컨텍스트 검색</li>
<li>stream_context_get_options — 스트림/래퍼/컨텍스트에 대한 옵션 검색</li>
<li>stream_context_get_params — 컨텍스트에서 매개변수를 검색합니다.</li>
<li>stream_context_set_default — 기본 스트림 컨텍스트 설정</li>
<li>stream_context_set_option — 스트림/래퍼/컨텍스트에 대한 옵션을 설정합니다.</li>
<li>stream_context_set_params — 스트림/래퍼/컨텍스트에 대한 매개변수 설정</li>
<li>stream_copy_to_stream — 한 스트림에서 다른 스트림으로 데이터를 복사합니다.</li>
<li>stream_filter_append — 스트림에 필터 연결</li>
<li>stream_filter_prepend — 스트림에 필터 연결</li>
<li>stream_filter_register — 사용자 정의 스트림 필터 등록</li>
<li>stream_filter_remove — 스트림에서 필터 제거</li>
<li>stream_get_contents — 스트림의 나머지 부분을 문자열로 읽습니다.</li>
<li>stream_get_filters — 등록된 필터 목록 검색</li>
<li>stream_get_line — 스트림 리소스에서 지정된 구분 기호까지 줄을 가져옵니다.</li>
<li>stream_get_meta_data — 스트림/파일 포인터에서 헤더/메타 데이터 검색</li>
<li>stream_get_transports — 등록된 소켓 전송 목록 검색</li>
<li>stream_get_wrappers — 등록된 스트림 목록 검색</li>
<li>stream_is_local — 스트림이 로컬 스트림인지 확인</li>
<li>stream_isatty — 스트림이 TTY인지 확인</li>
<li>stream_notification_callback — 알림 컨텍스트 매개변수에 대한 콜백 함수</li>
<li>stream_register_wrapper — stream_wrapper_register의 별칭</li>
<li>stream_resolve_include_path — 포함 경로에 대해 파일 이름 확인</li>
<li>stream_select — 시간 제한이 초 및 마이크로초로 지정된 지정된 스트림 배열에 대해 select() 시스템 호출과 동일한 것을 실행합니다.</li>
<li>stream_set_blocking — 스트림에서 차단/비차단 모드 설정</li>
<li>stream_set_chunk_size — 스트림 청크 크기 설정</li>
<li>stream_set_read_buffer — 주어진 스트림에서 읽기 파일 버퍼링 설정</li>
<li>stream_set_timeout — 스트림의 시간 초과 기간 설정</li>
<li>stream_set_write_buffer — 주어진 스트림에서 쓰기 파일 버퍼링을 설정합니다.</li>
<li>stream_socket_accept — stream_socket_server에 의해 생성된 소켓에 대한 연결 수락</li>
<li>stream_socket_client — 인터넷 또는 Unix 도메인 소켓 연결 열기</li>
<li>stream_socket_enable_crypto — 이미 연결된 소켓에서 암호화 켜기/끄기</li>
<li>stream_socket_get_name — 로컬 또는 원격 소켓의 이름 검색</li>
<li>stream_socket_pair — 연결되고 구별할 수 없는 소켓 스트림 쌍을 생성합니다.</li>
<li>stream_socket_recvfrom — 연결 여부에 관계없이 소켓에서 데이터 수신</li>
<li>stream_socket_sendto — 연결 여부에 관계없이 소켓에 메시지를 보냅니다.</li>
<li>stream_socket_server — 인터넷 또는 Unix 도메인 서버 소켓 생성</li>
<li>stream_socket_shutdown — 전이중 연결 종료</li>
<li>stream_supports_lock — 스트림이 잠금을 지원하는지 여부를 알려줍니다.</li>
<li>stream_wrapper_register — PHP 클래스로 구현된 URL 래퍼 등록</li>
<li>stream_wrapper_restore — 이전에 등록되지 않은 내장 래퍼를 복원합니다.</li>
<li>stream_wrapper_unregister — URL 래퍼 등록 취소</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>