The Pursuit of Happyness

반응형

테스팅


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0



- 테스트를 하는 이유

애플리케이션이 우리의 기대에 따라 지속적으로 작동하도록 보장하기 위해서!


- 테스트 시점

-- 개발 전

개발 전에 테스팅 도구를 설치하고 구성해야 한다.

-- 개발 도중

각 부분을 만들 때마다 테스트를 작성하고 실행한다. 새로운 클래스를 추가하면 그 즉시 테스트를 만들어 실행한다.

-- 개발 후

애플리케이션 출시 후 버그를 발견하면 버그 픽스를 만들어야 하며, 올바른 동작을 보장하기 위해 새로운 테스트도 함께 작성한다.

코드 수정시 그에 따른 영향을 받는 테스트 역시 수정해야 한다.


- 테스트 대상

애플리케이션을 구성하는 가장 작은 조각들 - 유닛 테스트 (미시적 관점)

전체 애플리케이션 - 기능 테스트 (거시적 관점)


- 테스트 방법

-- 단위 테스트

큰 애플리케이션에 포함된 클래스, 메써드, 함수를 고립시킨 상태로 검증하는 테스트 방식


-- 테스트 주도 개발 (TDD)

테스트 작성이 애플리케이션 코드 작성보다 선행

의도적인 실패를 통해 애플리케이션의 행동 방식을 묘사하고, 애플리케이션의 기능이 갖춰지고 나서야 성공적으로 수행된다.

목표 지향적이며 무엇을 만들어야 할지, 결과물은 어떻게 작동해야 할지를 사전에 인지할 수 있게 도와준다.


-- 행위 주도 개발 (BDD)

애플리케이션이 행동하는 방식을 이야기처럼 묘사하는 개발 방법론.

--- 스펙 BDD

인간 친화적인 언어로 애플리케이션 구현을 묘사하는 단위 테스트 유형

--- 스토리 BDD

하위 수준 구현 보다는 상위 수준 행동에 관심이 있다.


ex) PDF 보고서를 작성하고 이메일로 발송하는 애플리케이션 제작

---- 스펙 BDD : PDF 생성 클래스 메서드가 매개변수를 입력받아 올바르게 PDF 파일을 생성하는 지 검증

---- 스토리 BDD : 프로젝트 관리자 관점에서 PDF가 생성되어지는지와 email이 보내지는 지 같은 포괄적인 애플리케이션 동작을 검증

=> 둘 간의 차이는 테스트 영역이라고 생각하면 됨


- PHP 유닛

PHP 유닛 테스트 => 테스트 케이스 => 테스트 스위트

테스트 러너를 통해 테스트 스위트를 실행한다.

테스트 케이스는 PHPUnit_Framework_TestCase 클래스를 확장한 단일 PHP 클래스

컴포저를 이용하여 설치할 수 있다.


> composer require --dev phpunit/phpunit 




반응형

반응형

서버 설정 2


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0


- PHP-FRM

PHP 프로세스 풀을 관리하는 소프트웨어

PHP 프로세스는 엔진엑스 같은 웹 서버로부터 받은 요청을 처리


repository를 추가하고 패키지 매니저를 이용하여 설치한다.


 # 우분투

> sudo apt-get install python-software-properties

> sudo add-apt-repository ppa:ondrej/php5-5.6

> sudo apt-get update

> sudo apt-get install php5-fpm php5-cli php5-curl php5-gd php5-json php5-mcrypt php5-mysqlnd


# CentOS

> sudo rpm -Uvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm

> sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

> sudo yum -y --enablerepo=epel, remi, remi-php56 install php-fpm php-cli php-gd php-mbstring php-mcrypt php-mysqlnd php-opcache php-pdo php-devel


- 엔진엑스

엔진엑스는 아파치와 유사한 웹 서버지만 더 적은 시스템 메모리를 사용한다.


-- 설치

CetnOS 의 경우 바로 앞에서 설치한 EPEL 이 추가되어 있다고 가정


 # 우분투

> sudo add-apt-repository ppa:nginx/stable

> sudo apt-get update

> sudo apt-get install nginx


# CentOS

> sudo yum install nginx

> sudo systemctl enable nginx

> sudo systemctl start nginx


-- 가상 호스트

우분투의 경우 /etc/nginx/sites-available/example.conf 

CentOS 의 경우 /etc/nginx/conf.d/example.conf 

설정을 변경한다.


반응형

반응형

서버 설정 1


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0


1. 최초 로그인

ssh 명령어를 실행해 서버에 접속한다. 처음에는 호스트를 확인하는 메시지가 표시되며 yes를 입력하고 암호를 입력하면 로그인이 완료 된다.


2. 소프트웨어 업데이트

운영체제를 최신으로 업데이트 한다.


# 우분투

>  apt-get update

> apt-get upgrade


# CentOS

> yum update


3. 사용자 계정 추가

루트 사용자의 권한을 제한 하기 위해 deploy 라는 이름의 계정을 생성해서 사용해 보자. 

우분투의 경우 adduser 를 실행하면 바로 사용자 암호를 설정하는 화면으로 넘어가지만 CentOS 의 경우 passwd 명령어로 비밀번호 설정을 별도로 해줘야 한다. deploy 유저에게 sudo 권한을 주기위해서 그룹을 설정해 주는데, 우분투에서는 sudo 그룹으로 CentOS에서는 wheel 그룹에 추가해 준다.


# 우분투

> adduser deploy

> usermod -a -G sudo deploy


# CentOS

> adduser deploy

> passwd deploy

> usermod -a -G wheel deploy


4. SSH 키 쌍 인증

ssh 서버 접속시 비밀번호 인증 대신 SSH 키 쌍 인증을 사용해서 서버 보안을 강화한다.


1). 접속할 로컬 컴퓨터 (클라이언트 PC) 에서 ssh-keygen 명령어를 이용해서 개인키 (~/.ssh/id_rsa), 공개키 (~/.ssh/id_rsa.pub)를 생성한다.

개인키는 로컬 컴퓨터에 두고 유출되지 않도록 보호해야 하며, 공개 키는 접속할 ssh 서버로 scp 등을 이용하여 복사한다.


> ssh-keygen


2). 접속할 로컬 컴퓨터에서 scp ~/.ssh/id_rsa.pub deploy@server_address: 명령어를 입력한다.

마지막에 ":" 콜론을 붙이면 deploy의 홈 디렉터리에 업로드 된다.


> scp ~/.ssh/id_rsa.pub deploy@server_address:


3). ssh 서버에서 deploy 홈 디렉터리에서 mkdir ~/.ssh  명령어를 이용하여 ~/.ssh 디렉터리를 생성한다.  


> mkdir ~/.ssh


4). ssh 서버에서 touch ~/.ssh/authorized_keys 명령어를 이용해서 authorized_keys 파일을 생성한다.


> touch ~/.ssh/authorized_keys


5). ssh 서버에서 cat ~/id_rsa.pub >> ~/.ssh/authorized_keys 명령어를 이용해서 공개키를 등록한다.


> cat ~/id_rsa.pub >> ~/.ssh/authorized_keys


6). ssh 서버에서 deploy 사용자만 ~/.ssh 디렉터리에 접근해서 authorized_keys 파일을 읽을 수 있도록 권한을 변경한다.


> chown -R deploy:deploy ~/.ssh

chmod 700 ~/.ssh

chmod 600 ~/.ssh/authorized_keys


여기까지 작업이 되었으면, 개인 키가 있는 로컬 컴퓨터에서는 비밀번호 없이 ssh로 원격 서버에 접속할 수 있다.


5. 비밀번호 인증 및 루트 로그인 비활성화

1) ssh 서버에서 /etc/ssh/sshd_config 파일을 편집하여 PasswordAuthentication과 PermitRootLogin 설정값을 찾아 모두 no로 수정한다. 주석처리 되어 있으면 주석을 풀어준다.


2) 아래 명령으로 ssh 서비스를 재시작한다.


# 우분투

> sudo service ssh restart


# CentOS

> sudo systemctl restart sshd




반응형

반응형

PHP 모범 사례 4


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0


- 스트림

파일, 네트워크, 데이터 압축처럼 공통적인 기능과 사용 방법을 공유하는 작업들을 일반화하는 수단.


-- 스트림 래퍼

고유한 프로토콜로 읽고 쓸수 있는 스트림 데이터의 유형. 다음과 같은 공통 과정을 거친다.

1. 통신 시작

2. 데이터 읽기

3. 데이터 쓰기

4. 통신 종료


형식

<scheme>://<target>

ex) 

https://www.google.com


생략시 file scheme으로 인식

ex) 

fopen('/etc/hosts', 'rb');

fopen('file:///etc/hosts', 'rb'); // "file://" 이후에 절대 경로 ("/etc/hosts" )를 적어 줘야 한다.


-- php:// 스트림 래퍼

php://stdin - 읽기 전용 PHP 스트림, CLI 에서 파이프를 통해 스크립트로 전달된 정보를 수신할 수 있다.

php://stdout - 현재 출력 버퍼에 데이터를 기록할 수 있다. (쓰기 전용으로 읽거나 탐색은 불가)

php://memory - 시스템 메모리 데이터를 읽고 쓸 수 있다. 

php://temp - php://memory 스트림과 동일하게 작동하지만 가용 메모리가 고갈되면 임시 파일에 기록된다.


-- 스트림 콘텍스트

스트림 콘텍스트를 이용하면 file_get_contents() 함수를 이용해서 HTTP POST 요청을 보낼 수 있다.


ex)


<?php

$requestBody = '{"username":"josh"}';

$context = stream_context_create( array(

    'http' => array(

        'method' => 'POST', 'header' => "Content-Type: application/json;charset=utf-8;\r\n" . "Content-Length: " . mb_strlen($requestBody), 'content' => $requestBody

    )

));

$response = file_get_contents('https://your_test_server.com/users', false, $context);


-- 스트림 필터

스트림을 전송하는 동안 데이터를 여과, 변형, 추가, 제거하기 위해 사용


ex) 마크다운 파일을 스트림으로 열어 메모리로 읽어들이면서 HTML 변환을 하는 작업

ex) 파일을 읽어서 모두 대문자로 변경해서 출력하는 작업


<?php

$handle = fopen('data.txt', 'rb');

stream_filter_append($handle, 'string.toupper');

while(feof($handle) !== true) {

    echo fgets($handle);

}

fclose($handle);





반응형

반응형

PHP 모범 사례 3


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0


- 데이터베이스

-- PDO 사용 (PHP data objects)

단일한 사용자 인터페이스로 다양한 SQL 데이터베이스와 통신 가능한 PHP 클래스 집합체

데이터베이스 구현을 추상화하고, 이를 이용하여 DBMS 타입에 관계없이 하나의 인터페이스를 통해 쿼리를 작성하고 실행할 수 있다. (DBMS 마다 다른 Query dialect 는 신경써야 한다.)


-- DB 연결 및 DSN

PHP에서 PDO 클래스 인스턴스를 생성하고 PDO 인스턴스로 PHP와 데이터베이스를 연결한다.

PDO 클래스 생성시 DB 연결 정보를 제공하는 문자열 인수를 DSN 이라고 한다.

DSN은 DB 드라이버명과 호스트명 혹은 IP 주소 그리고 포트번호, DB이름, 문자 집합 등이 포함된다.


ex)

<?php

try {

    $pdo = new PDO('mysql:host=127.0.0.1;port=3306;dbname=acme;charset=utf8', 'dbaccount', 'dbpassword');

} catch (PDOException $e) {

    echo 'fail to connect';

    exit;

} 


-- 데이터베이스 인증 정보 보관

인증 정보는 PHP 파일에 직접 넣어서 사용하면 안된다. 웹 문서 루트 외부에 있는 설정 파일로 옮겨서 PHP 파일에서 읽어서 처리한다. .gitignore 파일을 이용해서 버전 관리에서도 제외 시킨다.


-- 준비된 구문 (Statement)

Query Injection 등의 위험을 제거하기 위해서 Statement를 이용한다.


ex)

<?php

$sql = 'SELECT id FROM users WHERE email = :email';

$statement = $pdo->prepare($sql);


$email = filter_input(INPUT_GET, 'email');

$statement->bindValue(':email', $email, PDO:PARAM_STR);

$statement->execute();


while( ($result = $statement->fetch(PDO::FETCH_ASSOC)) !== false ) {

    echo $result['email'];

}



-- 쿼리 결과

PDO::FETCH_ASSOC - 배열 키는 데이터베이스 열 이름

PDO::FETCH_NUM - 배열 키는 데이터베이스 열 순서 번호

PDO::FETCH_BOTH - 배열 키는 데이터베이스 열 이름과 열 순서 번호 모두 사용 가능

PDO::FETCH_OBJ - 데이터베이스 열 이름이 객체 속성명으로 사용되는 객체 반환


-- 트랜젝션

트랜잭션은 더 이상 나눌 수 없는 데이터베이스 명령문 집합

DBMS에 따라서 지원 여부가 결정된다.


ex)

<?php

$pdo->beginTransaction();


// insert or update queries


$pdo->commit();







반응형

반응형

PHP 모범 사례 2


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0

- 비밀번호 관리

-- DB가 해킹당해도 비밀번호를 알 수 없게 평문이나 복호화가 가능한 비밀번호를 저장하지 말 것

-- 비밀번호에 제한을 두지 말 것

-- 비밀번호를 절대 이메일로 보내지 말 것

-- bcrypt로 해시화 할 것

암호화 NO, 해시화 YES!

해싱 알고리즘 (MD5, SHA1, bcrypt, scrypt ...)

bcrypt - 단점은 느린 속도. 레인보우 테이블 공격을 저지하기 위해 데이터에 솔트를 추가한다.

password_hash() 함수를 사용하면 default로 bcrypt 해싱 알고리즘을 사용한다. (참고 password_verify(), password_needs_rehash())


- 날짜, 시간, 시간대

-- 기본 시간대 지정

php.ini 파일에 date.timezone 항목을 설정한다.

혹은 date_default_timezone_set() 함수를 이용해서 설정한다.


-- DateTime 클래스

-- DateInterval 클래스, DatePeriod 클래스

DateTime 클래스를 조작하기 위해서 사용된다.


ex)


<?php

$datetime = new DateTime();    // create DateTime instance 


$interval = new DateInterval('P2W');    // Period of 2 weeks


$datetime->add($interval);

echo $datetime->format('Y-m-d H:i:s');


$dateInterval = DateInterval::createFromDateString('-1 day');

$datePeriod = new DatePeriod($datetime, $dateInterval, 3);    // 3 periods

foreach ($datePeriod as $date) {

    echo $date->format('Y-m-d') . PHP_EOL;

}



주) 예전에는 strtotime 을 이용해서 date을 변경해 가면서 for 문을 돌렸는데, 조금 더 직관적인 방법이 되었네요..



반응형

반응형

PHP 모범 사례 1


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0


입력값의 위험을 제거하고 데이터의 유효성을 검사하고 출력을 예외 처리하라!


- 입력값 위험 제거

-- 입력 데이터가 애플리케이션 저장소 계층 (DB, CacheDB 등) 에 도달하기 전에 위험을 제거하는 것이 중요

-- HTML

htmlentities() 함수나 HTML purifier 라이브러리를 이용 

-- SQL

준비된 PDO 문을 사용하여 쿼리 인젝션 공격에 대비한다.

-- 사용자 정보

filter_var(), filter_input() 함수를 이용하여 필터링 한다.


- 유효성 검사

-- filter_var() 함수를 이용하여 유효성 검사를 통해 잠재적인 DB 오류를 방지한다.


- 출력 예외 처리

-- 애플리케이션 사용자에 의해 악의적인 코드가 표시되거나 부주의하게 실행되는 것을 막아준다.

htmlentities() 사용, ENT_QUOTES 를 이용해서 따옴표 처리, 적절한 문자 인코딩을 명시 (보통 UTF-8)


반응형

반응형

컴포넌트 사용


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0


PHP에서의 컴포넌트는 PHP 애플리케이션의 특정 문제를 해결하도록 도와주는 코드 모음이다. 기술적으론느 한가지 문제를 해결하는 데 관련된 클래스, 인터페이스, 트레이트의 모음이다.컴포넌트를 이루는 클래스, 인터페이스, 트레이트는 보통 동일한 네임스페이스 하위에 위치한다.


- 좋은 컴포넌트의 특징

-- 목적이 정확하다.

-- 작다.

-- 협력적이다.

-- 충분한 테스트를 거쳤다.

-- 문서화 수준이 높다.


- 컴포넌트 선택

-- 패키지스트에서 찾을 수 있음 

https://packagist.org


- 컴포넌트 사용

-- 컴포저를 사용한다.

https://getcomposer.org

-- 컴포저는 CLI로 동작하는 PHP 컴포넌트 의존성 관리자

-- 컴포저를 실행하면 해당 프로젝트에 필요한 컴포넌트와 의존성 컴포넌트를 프로젝트 폴더에 다운로드 하여 설치해준다.

-- 컴포저 설치


> curl -sS https://getcomposer.org/installer | php

> mv composer.phar /usr/local/bin/composer

> chmod +x /usr/local/bin/composer


첫 명령어는 getcomposer.org 사이트에서 installer 스크립트를 다운로드해서 php 로 실행하는 명령어로 그 결과 composer.phar 파일을 생성하는데, composer.phar 파일은 컴포저 바이너리 파일이다.

생성된 바이너리 파일을 실행이 가능한 위치 (/usr/local/bin) 에 composer 라는 이름으로 이동하고 나서 실행 가능한 권한을 준다.

-- 컴포저 사용법

1. 패키지스트에서 필요한 컴포넌트를 검색한다.

2. PHP 컴포넌트는 vendor / package 형식으로 되어 있다.

3. 아래 명령어를 프로젝트 루트 폴더에서 실행하면 컴포저가 flysystem  컴포넌트를 다운로드해서 vendor 폴더에 설치해 주고, composer.json 파일과 composer.lock 파일을 생성해 준다. composer.json 에는 프로젝트를 위해 설치한 콤포넌트 정보가 기록되며, composer.lock 에는 콤포넌트 설치 시점의 정보들이 기록된다.


> composer require league/flysystem






반응형

반응형

PHP 표준 권장안


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0


PHP에는 다른 언어들과 달리 콤포넌트를 이용하여 코드를 재활용하는 부분이 어려웠는데, 표준 (코딩 규약이나 composer 등) 을 이용하면 누군가 훌륭한 사람들이 만들어 놓은 많은 라이브러리를 활용하여 빠르고 안정적인 코딩이 가능하다.


PSR - PHP Standard Recommendation (PHP 표준 권장안)


http://www.php-fig.org/psr/


현재 채택되어진 PSR-1, PSR-2, PSR-3, PSR-4, PSR-6, PSR-7 을 참고 (책에서는 PSR-6, PSR-7은 언급되지 않음)


- PSR-1 요약

-- 파일은 <?php 나  <? 태그만 사용해야 한다.

-- 파일은 BOM (byte order mark) 이 없는 UTF-8 인코딩을 사용한다.

-- 파일은 클래스, 함수, 상수 등의 심볼을 정의하거나 결과물을 만들어 내거나 세팅에 필요한 것들을 정의 해야 하며 두 가지를 같이 처리하지 않는다.

-- 네임스페이스와 클래스는 반드시 autoloading PSR을 따른다.

-- 클래스 이름은 첫글자를 대문자로 적는다.

-- 상수는 대문자와 언더스코어 (_) 만을 이용한다.

-- 메써드 이름은 낙타표기법을 따른다.


- PSR-2 요약

-- PSR-1을 따른다.

-- 띄어쓰기는 스페이스 4칸 (탭은 쓰지 말것!)

-- 라인 길이는 80자 이내로 하는 것을 권장한다. (No Hard Limit, Soft Limit 120)

-- 네임스페이스 선언 이후에는 한줄을 비운다. use 선언들 이후에도 한줄을 비운다.

-- 클래스 및 메써드를 여닫는 괄호는 다음줄에 한다.

-- 모든 속성과 메써드에는 가시성 키워드를 선언해야 하며, abstract 와 final 키워드는 가시성 키워드 앞에 온다. static 키워드는 가시성 키워드 뒤에 둔다. (ex final private static function functionName())

-- if, else 등의 제어 키워드 뒤에는 반드시 공백을 하나 둔다. 시작 괄호는 같은 줄에 끝나는 괄호는 내용이 끝난 다음 줄에 둔다. 시작괄호 뒤나 끝 괄호 앞에 공백을 둘 필요는 없다.


- PSR-3 은 Logger 사용에 대한 부분


- PSR-4 은 오토로더 사용법에 대한 부분으로 런타임시 필요에 따라 PHP 클래스, 인터페이스, 트레이스를 찾아 인터프리터로 불러오게 된다. PSR-4 오토로더 표준을 지원하는 PHP 컴포넌트와 프레임워크들은 단 하나의 오토로더만으로 인터프리터로 불러올 수 있다.

기존의 include, require 등을 사용하거나 제작자들만의 __autoload() spl_autoload_register() 함수를 이용하는 대신 파일시스템 디렉터리와 PHP 네임스페이스만으로 코드를 구성함으로써 기존 코드를 수정하지 않고도 사용이 가능하다. 네임스페이스에 있는 클래스, 인터페이스, 트레이트는 src/ 하위에 있는 디렉터리 혹은 PHP 파일에 매핑된다.


- PSR-6 은 Cache interface


- PSR-7 은 HTTP message interface 



반응형

반응형

모던 PHP 특징


http://www.hanbit.co.kr/book/look.html?isbn=978-89-6848-225-0


- 네임스페이스

-- PHP 코드를 운영체제의 파일시스템 디렉터리 구조처럼 가상 계층 구조로 격리시켜준다.

-- 키워드 namespace, use


- 인터페이스

-- interface 를 정의하고 implements 해서 쓸 수 있다.


- 트레이트

-- 서로 상속관계로 묶기 애매하고 인터페이스로 공통 요소를 추상화 하기도 힘든 경우 사용

-- Trait을 사용할 클래스에 필요한 변수와 메써드를 정의하고, 각 클래스에서 use 키워드를 이용해서 trait 기능을 이용한다.

ex) 영화와 게임 클래스를 만든다고 하면, 둘 간에 상속관계도 없고, 추상화 할 요소도 없다. 각 클래스에 이름이라는 속성과 setName, getName 이라는 메써드만 공통적으로 사용된다면 아래와 같이 trait을 이용할 수 있다.


<?php

trait MediaMetaData 

{

    protected $mediaName;

    public function setMediaName($mediaName)

    {

        $this->mediaName = $mediaName;

    }

    public function getMediaName()

    {

        return $this->mediaName;

    }

} 


<?php

class Movie 

{

    use MediaMetaData;

} 


<?php

$movieTest = new Movie();

$movieTest->setMediaName("Test Movie");

echo $movieTest->getMediaName();


- 제네레이터

-- Iterator 와 달리 요구가 있을 때마다 반복적으로 값을 계산해서 돌려주는 기능

-- 계산 결과를 메모리에 모두 올릴 필요가 없어 매우 효율적인 운영이 가능


아래 예제에서 arrayOld 의 경우 $length 크기의 배열을 생성해서 전달

반면에 arrayGen의 경우 foreach에서 호출시 마다 다음 값만 생성해서 전달


<?php

function arrayOld($length)

{

        $ret = [];

        for ($i = 0;$i < $length; $i++)

        {

                $ret[$i] = $i;

        }

        return $ret;

}


function arrayGen($length)

{

        for ($i = 0;$i < $length; $i++)

                yield $i;

}


$len = 100000


foreach (arrayOld($len) as $i)

    echo $i . PHP_EOL;


foreach (arrayGen($len) as $i)

    echo $i . PHP_EOL; 




- 클로저

-- 생성 당시 자신의 주변 상태를 캡슐화한 함수 (함수 포인터라고 생각하면 된다.)


<?php

$closure = function ($name) {

        return sprintf("Hi %s", $name);

};


echo $closure("Tom") . PHP_EOL;




-  PHP 를 이용하여 http 서비스 테스트 하기

명령 프롬프트에서 다음과 같이 입력하면 8000 포트로 동작하는 http 서버를 띄울 수 있다. 한번에 하나의 요청씩만 처리하기 때문에 개발 테스트 용으로는 쓸수 있으나 Production 서비스 용으로는 적합하지 않다.


php -S localhost:8000


반응형