정규 표현식 Regular Expression (regExp) 과 Apache Rewrite

하늘 No.234 [컴퓨터] 4558
정규 표현식 Regular Expression (regExp) 과 Apache Rewrite

정규표현식은 원하는 문자열의 범위를 조건에 따라 지정하는 방법입니다.
일반 프로그래밍 언어를 비롯해서 어플리케이션의 조건 설정등에 쓰이며 약간의 차이는 있지만 대부분 대동소이합니다.
Apache 의 ReWrite 에서 사용되는 정규표현식과 일반적인 정규표현식의 내용을 함께 정리했습니다.


Apache RewriteEngine 활성화
-----------------------------
$ sudo a2enmod rewrite

Step2 설정 파일에서 RewriteEngine 사용하기
Rewrite 설정은 운영중인 사이트가 여러개인 경우 모든 사이트에 적용을 원한다면 httpd.conf에(우분투는 /etc/apache2/apache2.conf) 설정을 하시면 되고,
버추얼호스트가 적용된 특정 사이트에만 적용을 원할 경우 아파치가 설치된 경로의 sites-available 디렉터리 내의 가상호스트 설정 파일에 적용을 해 주면 됩니다.


URI 조건 검사 : RewriteCond 구문
-----------------------------

RewriteCond Teststring Condition [Flags]

RewriteCond 구문은 들어오는 URI를 1차적으로 검사하는 역할을 합니다.

여기서 URI가 특정 조건에 일치(요청 URI가 파일인지 아닌지, 특정 문자열이 포함되어 있는지, 리퍼러가 특정 사이트가 아닌 경우 등등등)하는 경우,

바로 다음에 나타나는 RewriteRule 규칙에 따라 URI를 특정 경로로 리다이렉션 시킵니다.

Teststring에 올 수 있는 서버 변수는 다음과 같습니다


플래그
-------
Flags는 Teststring 자체에 적용할 일종의 조건이며 여러개인 경우 ','(쉼표, 콤마) 로 구분합니다.

[L] - 조건 끝
[R] - Redirect, R=301 영구적 이동, R=302 임시 이동
[NC] - Case Insensitive 라는 의미로 테스트스트링의 대소문자를 구분하지 않습니다.

Teststring의 값이(주로 서버변수, 아래에서 설명합니다) Condition에서 정규식으로 일치하는 문자(열)이 있는 경우 참이 되고, 이후 처음으로 등장하는 RewriteRule을 실행한다.


특정 URI로 리다이렉트 : RewriteRule 구문
-----------------------------

RewriteRule Pattern Substitution [Flags]

RewriteRule 구문은 요청받은 URI에서 Pattern에 작성될 정규식을 통해 특정한 패턴을 가진 부분이 있는지 검사하는 것입니다.

Pattern의 정규식에 일치되는 URI를 찾았으면 'Substitution' 에서 일치하는 해당 URI를 리다이렉션시킬 경로를 작성해 주면 됩니다.


정규식
\ : 이스케이프 문자. 아래 특수한 기호들의 의미가 아니라 글자 자체를 의미하도록 함
Escape 해야 할 문자  . \ + *? [^] $ () {} =! <> | : - / 
주의) 특수한 기호를 제외한 일반 문자를 \ 으로 이스케이프할 경우 해당 문자 자체가 아니라 다른 의미를 가짐 ( s 는 일반 문자 \s는 공백문자,  \S 공백문자를 제외한 문자)

^ : 입력 문자열의 처음
$  입력 문자열의 처음

(a|b) : a 또는 b
(~~~) 문자열 집합, 괄호의 사용법은 위의 | 를 이용해서 두개의 문자열 중 하나를 의미함, 괄호는 이후 파라매터 $1, $2 등에서 사용됨.
[abc] 괄호 안에 오는 문자 중 하나라도 맞는 것. '()' 와 달리 '[]' 는 문자 한 개를 뜻합니다.
[^abc] [] 안의 ^ 은 처음이 아니라 NOT의 의미. ~~~ 에 포함되는 문자는 올 수 없음

표기 문자 종류

. : 한 개의 문자
\s : 공백
[:punct:] 모든 종류의 문장 부호 (., ,, ', " 등등)
[:space:] 모든 종류의 공백 문자
[:blank:] 공백이나 탭


문자의 반복수

a? : 0 또는 1개의 a
a* : 0개 이상의 a
a+ : 1개 이상의 a
a{3} : 3개의 a를 의미합니다. '(aaa)' 와 정확히 같은 표현입니다. 그럼 반대로 탐욕적인 경우는 모두 일치시키게 되겠죠?
a-zA-Z : 범위 지정하기 a~z, A~Z 별다른 구분자는 사용하지 않고 문자~문자 의 형태로 구분짓습니다.
(안 중요)
a{3,} : 3개 이상의 a
a{3,6} : 3 ~ 6 개 사이의 a
a{,6} : 최대 6개까지의 a

그리고 정규식을 통해 일치시킨 문자(열)은 순서대로 $1~9 까지의 변수에 저장됩니다.
변수에 저장된 문자(열)들은 'Substitutuion' 부분에서 불러와 치환시킬 수 있습니다.

Flags 에서는 Pattern 자체에 적용될 조건을 줄 수 있습니다. 여러개의 조건은 ','(콤마) 로 구분합니다.

C 다음 Rule과 연결됨.
CO=cookie 특정 쿠키를 만듦.
F Fobidden 에러를 출력함.
N 다음 Rule 처리를 계속함.
L URI 재작성 조건검사를 중단함.

QSA 쿼리스트링을 붙임. 기본적으로 Rewrite에서 모든 쿼리스트링은 제거되는 대신 QSA 변수에 저장되므로 필요한 부분에서 꺼내어 쓸 수 있습니다.

S=x 다음 x개의 Rule을 건너뜀.
NC 대소문자를 구분하지 않음.

RewriteCond는 다음에 올 RewriteRule 를 적용하기 앞서 예외처리 등을 위해 URI의 조건을 한번 먼저 검사하고 룰을 실행할지 말지를 판단하는 역할을 합니다.
즉, 실제로 URI를 재작성하는 기능은 없기 때문에 RewriteRule을 사용해서 충분하다면 RewriteCond는 없어도 되는 구문이거든요

1. http://example.com/board/12 와 같은 URI가 있을 때 /board/(여기) 에 오는 모든 숫자값들을 /board/viewArticle.php?no=(여기) 로 이동하도록 처리하고 숫자가 아닌 경우에는 메인페이지로 이동하도록 RewriteRule을 작성하여라.

RewriteRule /board/([0-9]+?) /board/viewArticle.php?no=$1
설명: [0-9]로 숫자만 올 수 있도록 하고 +?를 사용하여 1개 이상의 숫자가 오는 것을 일치시킵니다(비탐욕적)


2. $n 변수를 이용하여 호스트명/(foo)/(bar) 형태로 요청되는 URI를 내부적으로 /index.php?req=(foo)&num=(bar) 와 같이 처리하도록 하는 RewriteRule 구문을 작성하여라

RewriteRule ^/(.+)/(.+)$ /index.php?req=$1&num=$2
설명 (foo)와 (bar)를 각각 (.+)로 일치시킨 다음 $1과 $2로 치환시킵니다.

출처: https://hellocomputer.tistory.com/27

----
정규 표현식 생성기/디버거
Regex tester : https://regex101.com/
RegExr : https://regexr.com/
PHP Live Regex https://www.phpliveregex.com/
RegEx Testing : https://www.regextester.com
RegEx Testing Apache : https://www.regextester.com/94156

시각적 정규 표현식 테스터
Regex visualizer : https://extendsclass.com/regex-tester.html

정규표현식 (Regular Expression, Reg Ex)
PHP 정규식(PCRE) utf-8
https://docs.microsoft.com/ko-kr/dotnet/standard/base-types/regular-expression-language-quick-reference

Escape 해야 할 문자     . \ + *? [^] $ () {} =! <> | : - /
웹에서 흔히 사용되는 특수문자 패턴 :  []{}():=./@&,; -> \[\]\{\}\(\)\:\=\.\/@&,;
https://regex-escape.com/online-regex-escape.php?hl=ko

기타 참고
https://hbase.tistory.com/160
https://hhhh88.tistory.com/7
https://ponyozzang.tistory.com/174
https://blog.asamaru.net/2017/01/25/php-regex-epilogue/

https://SkyMoon.info/a/HeismeNote/234  

삶은 언제나 쉽지 않은 일이지만 단 한순간이라도 죽을 만큼 힘들지는 않다. 아직까지 살아 있음이 그것의 가장 명확한 증거이다 [하늘-내 안의 거울 2]