WEB/정리

WEB 기초 4주차 정리 - PHP&MySQL 1~10

너굴맨이해치움 2022. 7. 31. 06:50

1. 수업소개 ~ 2. PHP와 MySQL의 연동 원리

 

https://youtu.be/NChP-7KMQ_U

웹사이트에서 다뤄야 할 정보의 양, 종류, 사용자가 많아짐에 따라

이전에 고민할 필요 없었던 문제가 대두되기 시작함

-> PHP와 데이터베이스를 연동하는 방법 등장

-> db의 성능, 편의성, 보안성을 그대로 물려받은 현대적 어플리케이션 개발

 

대략적인 구조는 이렇다. 웹 브라우저에서 .php 양식의 파일을 웹 서버에 요청하면

웹 서버는 이를 혼자 처리할 수 없으므로 php에 위탁한다.

php는 이를 받고 MySQL의 저장 장소에 있을 정보를 MySQL에게 요청하고,

MySQL은 요청대로 php에게 정보를 내어준다. 이 정보를 받아 html 파일로 웹페이지를 구성하면

웹서버가 이를 받아 브라우저에게 서비스하게 된다.

 


3. 수업준비 ~ 4. MySQL Client로서의 PHP*

(실제 강의 제목과 차이가 있는데, 해당 영상 댓글에서 이 표현이 더 정확하지 않느냐는 질문이 있었고

영상 업로더가 이에 동의했다.)

https://youtu.be/wKD_ZjyNn3U

 

 

(수업준비는 3-1과 3-2편 영상의 더보기란에 있는 링크에서 코드를 복사하도록 한다.)

 

" db와 연동되는 php는 db 서버에 있어 클라이언트이다 "

: 우리가 앞선 mysql 수업에서 사용했던 mysql 모니터는 mysql 서버에 쿼리를 전달하고 정보를 받아오는 클라이언트였다.

같은 원리로 php는 db와 연동될 때 db에 쿼리를 전달하고, 정보를 받아올 수 있는 클라이언트로서 기능한다.

즉, 모니터에서 db 서버와 상호작용하기 위해 했던 모든 것들을 이제 php로 해야 할 필요가 있다.

 


5. MySQL API 찾기

https://youtu.be/SR00gij8lr4

 

 

php로 mysql에 연결할 수 있는 api를 찾아본다.

보통 mysqli / pdo / mysql 세 가지 종류가 있는데

mysql은 오래되어 사용을 권장하지 않고,

pdo는 다른 관계형 데이터베이스를 사용하게 될 때도 코드를 바꾸지 않고 db를 교체할 수 있으나

객체지향 구조에 익숙하지 않다면 mysqli를 사용하는 것도 좋다.

 

mysqli는 함수 방식으로 제어하며, 이 강의에서는 mysqli를 사용한다.

 


6.1. mysqli_connect

https://youtu.be/3tVZvEHdUMk

 

 

 

php로 만들어진 페이지가 mysql에 접속하게 하는 코드는 다음과 같다.

localhost는 우리가 아는 127.0.0.1 주소이다. 현재 사용 중인 컴퓨터를 가리키는 도메인이다.

root와 111111은 mysql 모니터에서 처음 접속할 때와 같은 입력값이다. 루트 권한과 비밀번호이다.

(교육용이 아닌 목적으로 실제 사용할 땐 저런 비번을 써서는 절대로 안 된다!

사실 이렇게 코드에 비밀번호가 드러나는 방식을 취하는 것 자체가 보안상으로 위험하다.)

opentutorials는 사용할 스키마이다.

 

위 코드로 접속하는 것을 제너럴 로그로 찍어보면 이런 로그가 뜬다.

루트 권한, 현재 위치 로컬호스트로 해당 스키마를 사용하는 접속 시도에 성공했다.


6.2. mysqli_query

https://youtu.be/OrJ3LIzDHQw

 

이번에는 PHP에서 DB 테이블에 내용을 넣는 작업을 해 보자.

내용을 넣는 것은 쿼리문으로 처리해야 하므로

mysqli_query(링크, 쿼리 내용);

과 같은 형식의 코드를 사용할 것이다. 이런 식으로 작성한다.

<?php
$conn = mysqli_connect("localhost", "root", "111111", "opentutorials");
mysqli_query($conn, "
  INSERT INTO topic
    (title, description, created)
    VALUE(
      'MySQL',
      'MySQL is ..',
      NOW()
      )
");
 ?>

일단 db에 접속하는 코드를 맨 윗줄에 쓴 뒤, 그것을 변수에 담는다.

그리고 mysqli_query의 첫 번째 인자로 접속하는 코드를 담은 변수, 다음 인자로 쿼리 내용을 적는다.

 

위 php 코드를 브라우저로 실행시킨 뒤 db 모니터에서 확인해 보면 정상적으로 테이블에 내용이 들어갔음을 알 수 있다.


6.3. mysqli_error

https://youtu.be/2Jh4mmeJLvI

 

 

개발에 있어 에러는 필연적인 것이지만, php는 기본적으로 에러를 알려주는 기능을 지원하지 않는다.

이때 쓰면 좋을 것이 mysqli_error이다.

 

<?php
$conn = mysqli_connect("localhost", "root", "111111", "opentutorials");
$sql = "
  INNSERT INTO topic
    (title, description, created)
    VALUE(
      'MySQL',
      'MySQL is ..',
      NOW()
      )
";
mysqli_query($conn, $sql);
echo mysqli_error($conn);
 ?>

쿼리문을 변수에 담아서 수정하기 좋게 하고, 내용에 일부러 오타를 냈다.(INNSERT)

이때 mysqli_error(링크) 형식 코드를 쓰면 그 연결에서 발생한 에러를 php가 페이지에 표시해 준다.

 

한 단계 더 발전시키면 이런 것도 가능하다.

<?php
$conn = mysqli_connect("localhost", "root", "111111", "opentutorials");
$sql = "
  INSERT INTO topic
    (title, description, created)
    VALUE(
      'MySQL',
      'MySQL is ..',
      NOW()
      )
";
$result = mysqli_query($conn, $sql);
if ($result === false){
  echo mysqli_error($conn);
};
 ?>

이것은 쿼리를 변수화해서 if문의 조건식에 달아놓은 것이다. 쿼리에서 에러가 발생하면 해당 값이 false가 된다.

이 경우 에러를 출력하게 되므로 해당 쿼리로 대상을 좁혀서 에러가 발생했는지 아닌지를 알 수 있게 된다.

 

그러나 이는 개발할 때만 용납되는 방식이며, 실제 시스템에서는 이런 식으로 echo를 써서 에러를 외부에 출력해서는 안 된다. 공격자에게 내부 정보를 넘겨주는 것이나 다름없기 때문이다. (지난주 비박스 웹해킹 게시글 참고)


7. 활용 - 글생성

https://youtu.be/uIemIQzSO0U

 

여태까지 배웠던 기능들을 활용해서 위키 사이트를 만들어 보자.

 

 

우선 사이트의 기조가 되는 화면이다. 처음 접속했을 때는 아래와 같은 화면이 뜰 것이다.

a 태그를 이용해 create를 누르면 create.php 파일이 실행되도록 만들어 준다.

 

create를 눌렀을 때 나타나는 create.php 화면이다.

form 태그와 textarea를 이용해 제목과 본문을 입력할 수 있도록 했다.

제출을 누르면 action인 process_create.php로 넘어간다.

 

post 방식이기 때문에 우선 form에서 작성한 정보가 잘 넘어왔는지 var_dump로 확인해 준다.

 

정보 전송에 문제가 없는 것을 확인했다면 쿼리문을 변수에 넣는다.

INSERT문으로 topic 테이블에 제목, 본문, 생성 날짜가 들어가도록 할 것이다.

생성 날짜는 NOW() 함수를 이용한다.

 

SQL 접속, 쿼리 전달, 실패했을 경우에 대비한 에러 메시지까지 갖춘 코드이다.

에러 메시지는 error_log 함수를 이용해 외부가 아닌 내부 에러로그 파일에 저장되도록 했다.

정상적으로 작동했으며, 모니터에서 확인한 바 INSERT문이 정상 처리된 것을 볼 수 있다.


8. SELECT 사용법

https://youtu.be/AQGpcSc52Vw

 

 

이번에는 SELECT 쿼리로 추출한 내용을 PHP에서 전달받는 방법에 대해 살펴보자.

 

비슷한 방식이다. SELECT문 쿼리를 변수에 담고 mysqli_query문으로 실행한다.

이때 결과값을 잠깐 var_dump로 살펴보자. 이런 배열값이 나올 것이다.

-> 기호를 활용해서 원하는 부분만 추출할 수도 있다. 행의 개수인 num_rows를 추출한 모습이다.

 

 

mysqli_fetch_array를 print_r문으로 출력해서 보면 좀더 깔끔한 결과를 얻을 수 있다.

페이지 소스 보기로 줄바꿈된 것을 본 결과다. 자세히 보면 같은 값이 인덱스로 한 번, 컬럼명으로 한 번 출력되고 있다.

이것이 무엇을 의미하는가?

 

인덱스(숫자)로도 값을 꺼낼 수 있고, 그 값의 필드명을 직접 입력해서도 값을 꺼낼 수 있다는 뜻이다.

후자의 방식이 가능한, 즉 값 자체를 키로 삼을 수 있는 배열을 연관 배열이라고 한다.

 

mysqli_fetch_array는 하나의 배열이기 때문에, 이를 변수에 담아서 뒤에 인덱스명을 붙이면

간단히 아래와 같이 제목과 내용을 출력할 수 있다.

 

반복문으로 실행한 모습이다. mysqli_fetch_array는 호출될 때마다 계속해서 다음 값을 꺼내오는데,

더 꺼내올 값이 없으면 널 값을 가져온다. 이 점을 이용해 while문을 짜면 깔끔하게 테이블의 모든 값을 확인할 수 있다.


9. 글읽기

https://youtu.be/6u55XwoUYtM

 

 

 

1. index.php에서 db 연결을 취한다.

2. 쿼리문 전달과 배열 출력으로 db 안의 글 제목들을 리스트화한다.

3. 반복문으로 이를 리스트에 담은 뒤 변수화해 하단에서 출력한다.

변수 하나의 출력은 <?=(변수명)?>으로 간단하게 가능하다.

4. 아이디를 매개로 제목과 글내용을 뽑아온 뒤 변수화한다.

5. 하단에서 변수 출력한다.

 

create.php에도 같은 내용을 복사 후 붙여넣기한다.


10. 보안 - filtering, sql injection의 원리, escaping

https://youtu.be/GdRZhWjTDnE

 

filtering = 입력 단계에서 문제가 될 소지가 있는 정보를 거르는 것

escaping = 출력 단계에서 문제가 될 소지가 있는 정보를 거르는 것

 

보안의 기본은 사용자가 입력하는 정보를 불신하는 것이다. (그 이유는 웹해킹 게시물을 살펴보면 알 수 있다.)

입력단에서는 사용자가 입력하는 정보를 걸러야 하고, 출력단에서는 사용자에게 약점을 노출하지 않게 주의해야 한다.

 

1. 입력에서의 보안인 필터링 기법 중 가장 보편적인 것은 이 코드이다.

mysqli_real_escaping_string()

이 함수는 인자로 받아들여진 스트링이 코드로 사용되지 못하도록 막는다.

db와 연동되는 웹에서 사용자가 sql 인젝션 공격을 하려고 한다면 이를 막을 장치가 필요하기 때문에

위와 같은 스트링 검열 함수를 통해 한 번 거르는 것이다.

보통 입력값을 위 함수로 한 번 감싼 뒤 변수에 담아

다른 코드 부분에서 입력값을 사용하려 할 때는 그 한번 거른 변수를 날것의 입력값 대신 사용한다.

 

 

2. sql 인젝션 공격에서는 --(주석 기호), ;(쿼리 분리 기호) 등을 이용해

기존의 쿼리에서 필요없는 문자를 지우고 뒤에 자신이 원하는 쿼리를 덧붙여 여러 개의 쿼리가 실행되게끔 하는 식으로 공격방식을 취한다. (3주차 웹해킹 게시물 참고)

이때 위 1번의 방식을 사용하면 이러한 인젝션 공격을 막을 수 있고

mysqli_multi_query 대신 mysqli_query 함수를 사용하면 다중 쿼리를 방지할 수 있다.

 

3. 여러 번 웹해킹 게시글에서 언급되었듯

유명한 이스케이핑 함수로는 htmlspecialchars()가 있다.

이 함수를 사용하면 인젝션에 사용될 수 있는 html 기호(<, /, > 등)가 모두 단순한 스트링으로 변환되어

인젝션 공격이 쉽게 무효화된다.