'Programming/Slim'에 해당하는 글 17건

Request 헤더


모든 HTTP 요청은 헤더를 가진다. 요청 본분에 보이지 않으며 HTTP 요청을 나타내는 메타데이터이다.

PSR-7 요청 객체는 헤더를 검사하는 여러 메소드들을 제공한다.


getHeaders() 는 모든 HTTP 요청 헤더를 배열로 가져온다.

배열의 키는 헤더 이름이 되고, 그 값은 문자열로 된 숫자 배열이다.


1
2
3
4
5

$headers = $request->getHeaders();
foreach ($headers as $name => $values) {
    echo $name . ": " . implode(", "$values);
}
cs


getHeader($name) 은 하나의 헤더값을 가져온며 지정된 헤더 이름($name)의 값을 배열로 반환한다. 하나의 HTTP 헤더는 하나 이상의 값을 가질 수 있다.

getHeaderLine($name) 은 헤더의 모든 값을 콤마로 구분된 문자열로 가져온다.

hasHeader($name) 은 해당 헤더의 존재 여부를 확인할 수 있다.



Request 본문


모든 HTTP 요청은 본문을 가진다. 

JSON 이나 XML 데이터로 HTTP 요청을 하는 경우, PSR-7 요청 객체의 getParsedBody() 를 사용하여 PHP 형식으로 HTTP 요청 본문을 파싱할 수 있다.

  • JSON 요청은 json_decode($input, true) 을 사용하여 배열로 변환된다.
  • XML 요청은 simplexml_load_string($input) 을 사용하여 SimpleXMLElement 로 변환된다.
  • URL-encoded 요청은 parse_str($input) 을 사용하여 PHP 로 변환된다.


Slim 의 PSR-7 요청 객체는 \Psr\Http\Message\StreamInterface 의 인스턴스로 HTTP 요청 본문을 표현한다.

getBody() 메소드로 HTTP 요청 본문 SteamInterface 인스턴스를 얻을 수 있다.

getBody() 메소드는 요청된 HTTP 의 크기를 알 수 없거나 이용 가능한 메모리 보다 크기가 더 큰 경우에 사용한다.


\Psr\Http\Message\StreamInterface 인스턴스는 PHP 리소스를 검사하고 반복 작업할 다음의 메소드들을 제공한다.

  • getSize()
  • tell()
  • eof()
  • isSeekable()
  • seek()
  • rewind()
  • isWritable()
  • write($string)
  • isReadable()
  • read($length)
  • getContents()
  • getMetadata($key = null)



Request 헬퍼


Slim 의 PSR-7 Request 객체는 HTTP 요청을 더 자세히 분석하는데 도움을 주는 추가적인 메소드를 제공한다.


Request 객체의 isXhr() 메소드로 HTTP 요청 헤더에 XHR 요청(X-Requested-With: XMLHttpRequest)이 존재하는지 확인할 수 있다.


1
2
3
4
5
6
7
POST /path HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 7
X-Requested-With: XMLHttpRequest
 
foo=bar
cs


1
2
3
4
5
6
7
8
9

if ($request->isXhr()) {
    // Do something
}
 
$contentType = $request->getContentType();
$mediaType = $request->getMediaType();
$mediaParams = $request->getMediaTypeParams();
$length = $request->getContentLength();
cs



Route 객체


가끔은 미들웨어에서 라우트 파라미터를 필요로 한다.

예제에서는 먼저 사용자가 로그인이 되었는지 체크하고, 특정 비디오를 볼 수 있는 권한이 있는지 체크한다.


1
2
3
4
5
6
7

$app->get('/course/{id}', Video::class.":watch")->add(Permission::class)->add(Auth::class);
 
//.. In the Permission Class's Invoke
/** @var $route \Slim\Route */
$route = $request->getAttribute('route');
$courseId = $route->getArgument('id');
cs



Media Type 파서


Slim 은 요청의 미디어 타입을 확인하고, 인식되는 경우, $request->getParsedBody() 를 사용하여 구조화된 데이터로 파싱된다.

이것은 보통 배열이지만, XML 미디어 타입 객체이다.

다음은 인식하고 파싱되는 미디어 타입이다.

  • application/x-www-form-urlencoded
  • application/json
  • application/xml & text/xml


이 외 다른 미디어 타입을 파싱하려면, 가공되지 않은 본문을 파싱하거나 새로운 미디어 파서를 등록해야 한다.

미디어 파서는 단순히 $input 문자열로 입력을 받고 파싱된 객체나 배열을 반환하는 호출 가능한 것이다.

파싱된 본문에 처음으로 접근을 시도하기 전에 어플리케이션이나 라우트 미들웨어에 새로운 미디어 파서를 등록하라.

예를 들어, text/javascript content type 으로 보내진 JSON 을 자동으로 파싱하기 위해, 미들웨어에 다음과 같이 미디어 타입 파서를 등록한다.


1
2
3
4
5
6
7
8
9
10
11
12
13

// Add the middleware
$app->add(function ($request$response$next) {
    // add media parser
    $request->registerMediaTypeParser(
        "text/javascript",
        function ($input) {
            return json_decode($inputtrue);
        }
    );
    
    return $next($request$response);
};
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Slim app 의 라우트와 미들웨어는 웹서버로부터 받은 HTTP 요청을 나타내는 PSR-7 요청 객체를 제공한다.

요청 객체는 HTTP 요청 메소드, 헤더, 본문을 다룰수 있는 PSR-7 ServerRequestInterface 를 구현한다.



Request 객체 얻는 방법


PSR-7 요청 객체를 라우트 콜백의 첫번째 매개변수로 넣는 예제

1
2
3
4
5
6
7
8
9
10
11
<?php
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
 
$app = new \Slim\App;
$app->get('/foo'function (ServerRequestInterface $request, ResponseInterface $response) {
    // Use the PSR 7 $request object
 
    return $response;
});
$app->run();
cs


PSR-7 요청 객체를 미들웨어 콜백의 첫번째 매개변수로 넣는 예제

1
2
3
4
5
6
7
8
9
10
11
12
<?php
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
 
$app = new \Slim\App;
$app->add(function (ServerRequestInterface $request, ResponseInterface $response, callable $next) {
    // Use the PSR 7 $request object
 
    return $next($request$response);
});
// Define app routes...
$app->run();
cs



Request 메소드


모든 HTTP 요청은 다음 메소드 중 하나를 가진다.

- GET POST PUT DELETE HEAD  PATCH OPTIONS


Request 객체 메소드인 getMethod() 로 HTTP 요청 메소드를 확인할 수 있다.


1
2

$method = $request->getMethod();
cs


Slim 에 내장된 PSR-7 객체는 또한 부울린 값을 반환하는 다음 메소드도 제공한다.

  • $request->isGet()
  • $request->isPost()
  • $request->isPut()
  • $request->isDelete()
  • $request->isHead()
  • $request->isPatch()
  • $request->isOptions()


HTTP 요청 메소드도 변경할 수 있다.

예를 들어, GET 과 POST 요청만 가능한 웹 브라우저로 PUT 요청을 해야할 때 유용하다.

HTTP 요청 메소드를 덮어 씌우는 두가지 방법이 있다.


- POST 요청 본문에 _METHOD 매개변수를 포함하고 content-type 은 application/x-www-form-urlencoded  을 사용한다.

1
2
3
4
5
6
POST /path HTTP/1.1
Host: example.com
Content-type: application/x-www-form-urlencoded
Content-length: 22
 
data=value&_METHOD=PUT
cs


- X-Http-Method-Override HTTP 요청 헤더를 추가한다.

1
2
3
4
5
6
7
POST /path HTTP/1.1
Host: example.com
Content-type: application/json
Content-length: 16
X-Http-Method-Override: PUT
 
{"data":"value"}
cs


원래의 HTTP 요청 메소드는 getOriginalMethod() 를 사용하여 가져올 수 있다.



Request URI


모든 HTTP 요청은 어플리케이션 리소스를 식별하는 URI 를 가지며, URI 는 여러 부분으로 구성된다.

  • Scheme (e.g. http or https)
  • Host (e.g. example.com)
  • Port (e.g. 80 or 443)
  • Path (e.g. /users/1)
  • Query string (e.g. sort=created&dir=asc)


getUri() 메소드로 PSR-7 요청 객체의 URI 를 가져올 수 있다.


1
2

$uri = $request->getUri();
cs


PSR-7 요청 객체의 URI 는 HTTP 요청 URL 부분들을 검사하는 다음 메소드들을 제공하는 객체이다.

  • getScheme()
  • getHost()
  • getPort()
  • getPath()
  • getBasePath()
  • getQuery() (returns string)
  • getQueryParams() (returns associative array)


getBasePath() 는 Slim 어플리케이션을 프로젝트의 최상위 디렉토리에 설치하지 않았을 때, 설치된 서브디렉토리를 상대경로로 가져온다.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Slim 은 어플리케이션 의존성을 관리하는 의존 컨테이너를 사용한다.

Slim 은 Container-Interop 인터페이스를 구현하는 컨테이너를 제공한다.

Pimple 에 기반한 Slim 내장 컨테이너나, Acclimate 같은 3rd-party 컨테이너나, PHP-DI 를 사용할 수 있다.



컨테이너 사용 방법


우리는 의존 컨테이너를 제공할 필요가 없다.

필요한 경우 Slim 어플리케이션의 생성자에 컨테이너 인스턴스를 삽입해야 한다.


1
2
3
<?
$container = new \Slim\Container;
$app = new \Slim\App($container);
cs


우리는 컨테이너로부터 명시적이나 암시적으로 서비스들을 가져올 수 있다.

Slim 어플리케이션 라우트 안에서 컨테이너 인스턴스에 명시적/암시적 참조를 가져오는 예제.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?
/**
 * Example GET route
 *
 * @param  \Psr\Http\Message\ServerRequestInterface $req  PSR7 request
 * @param  \Psr\Http\Message\ResponseInterface      $res  PSR7 response
 * @param  array                                    $args Route parameters
 *
 * @return \Psr\Http\Message\ResponseInterface
 */
$app->get('/foo'function ($req$res$args) {
    $myService = $this->get('myService');       // explicit
    $myService = $this->myService;              // implicit
    return $res;
});
cs


Slim 은 어플리케이션 인스턴스에 존재하지 않는 모든 속성들을 어플리케이션 컨테이너로 보내는 __get() 과 __isset() 매직 메소드를 사용한다.



필수 서비스


컨테이너는 다음 필수 서비스들을 구현해야 한다.

만약 Slim 내장 컨테이너를 사용한다면 이 서비스들은 제공되지만, 3rd-party 컨테이너를 사용하면 이 필수 서비스들을 모두 정의해야 한다.


settings

httpVersion, outputBuffering, responseChunkSize, determineRouteBeforeAppMiddleware 키를 포함하는 어플리케이션 세팅의 배열


environment

\Slim\Interfaces\Http\EnvironmentInterface 인스턴스


request

\Psr\Http\Message\ServerRequestInterface 인스턴스


response

\Psr\Http\Message\ResponseInterface 인스턴스


router

\Slim\Interfaces\RouterInterface 인스턴스


foundHandler

\Slim\Interfaces\InvocationStrategyInterface 인스턴스


errorHandler

어플리케이션 에러시 다음 세가지의 매개변수를 갖는 \Psr\Http\Message\ResponseInterface 인스턴스를 반환해야 한다.

  1. \Psr\Http\Message\ServerRequestInterface
  2. \Psr\Http\Message\ResponseInterface
  3. \Exception


notFoundHandler

HTTP 요청 URI 가 라우트와 매칭되지 않을 때 다음 두가지의 매개변수를 갖는 \Psr\Http\Message\ResponseInterface 인스턴스를 반환해야 한다.

  1. \Psr\Http\Message\ServerRequestInterface
  2. \Psr\Http\Message\ResponseInterface


notAllowedHandler

HTTP 요청 URI 가 라우트와 매칭되지만 메소드가 없을 때 다음 세가지의 매개변수를 갖는 \Psr\Http\Message\ResponseInterface 인스턴스를 반환해야 한다.

  1. \Psr\Http\Message\ServerRequestInterface
  2. \Psr\Http\Message\ResponseInterface
  3. 가능한 HTTP 메소드 배열


callableResolver

\Slim\Interfaces\CallableResolverInterface 인스턴스


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Slim Middleware

Programming/Slim 2016. 2. 29. 22:05

Request 와 Response 객체를 처리하기 위해 Slim 어플리케이션 전후에 특정 코드를 실행하는 것을 미들웨어라고 한다.

csrf 로부터 app 을 보호하거나 app 실행 전에 인증 요청을 하는 것들이 미들웨어이다.



미들웨어의 동작


미들웨어는 아래 그림처럼 Slim 어플리케이션의 중심을 둘러싸는 레이어로써 겹겹이 추가된다.

각 새로운 미들웨어 레이어는 이미 존재하는 미들웨어 레이어를 둘러싼다.

이러한 동심원의 구조로 미들웨어 레이어가 추가되면서 확장된다.


Request 와 Response 객체는 Slim 어플리케이션을 실행하기 위해, 바깥쪽에서 안쪽으로 들어온다.

먼저 가장 바깥의 미들웨어에 진입하고, 그 다음 미들웨어, 또 그 다음 미들웨어, ... 그리고 Slim 어플리케이션에 도달한다.

Slim 어플리케이션이 적절한 라우터를 전달하면, Response 객체는 다시 안쪽에서 바깥쪽으로 미들웨어 레이어를 거치며 나간다.

최종적으로 가장 바깥쪽 미들웨어를 빠져나가 HTTP 응답으로 직렬화된 Response 객체는 클라이언트에 반환된다.








미들웨어 작성법


미들웨어는 세 개의 매개변수를 받는 호출 가능한 것(함수/클래스)이다.


  • \Psr\Http\Message\ServerRequestInterface - PSR7 요청 객체
  • \Psr\Http\Message\ResponseInterface - PSR7 응답 객체
  • callable - 호출 가능한 다음 미들웨어


여기서 중요한 것은 미들웨어가 \Psr\Http\Message\ResponseInterface 의 인스턴스를 반환해야 한다.

각 미들웨어는 다음 미들웨어를 호출하고 매개변수로 Request 와 Response 객체를 전달하는 것이 좋다.



Closure(익명 함수) 미들웨어 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
/**
 * Example middleware closure
 *
 * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
 * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
 * @param  callable                                 $next     Next middleware
 *
 * @return \Psr\Http\Message\ResponseInterface
 */
function ($request$response$next) {
    $response->getBody()->write('BEFORE');
    $response = $next($request$response);
    $response->getBody()->write('AFTER');
 
    return $response;
};
cs



호출 가능한 클래스 미들웨어 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class ExampleMiddleware
{
    /**
     * Example middleware invokable class
     *
     * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
     * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
     * @param  callable                                 $next     Next middleware
     *
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function __invoke($request$response$next)
    {
        $response->getBody()->write('BEFORE');
        $response = $next($request$response);
        $response->getBody()->write('AFTER');
 
        return $response;
    }
}
 
$subject->add( new ExampleMiddleware() );
cs


이 예제는 매직 __invoke() 메소드를 구현하는 호출 가능한 클래스이다.

미들웨어로 이 클래스를 사용하기 위해, $app, Route, group() 중 하나(예제는 $subject 로 표현)의 다음에 add() 함수로 사용할 수 있다.



미들웨어 추가


우리는 Slim 어플리케이션, 라우터, 라우터 그룹에 미들웨어를 추가할 것이다.

이들은 같은 미들웨어 인터페이스를 적용하고 구현한다.



Application middleware


어플리케이션 미들웨어는 모든 들어오는 HTTP 요청으로부터 호출된다.

Slim 의 app 인스턴스의 add() 메소드로 어플리케이션 미들웨어를 추가하라.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$app = new \Slim\App();
 
$app->add(function ($request$response$next) {
    $response->getBody()->write('BEFORE');
    $response = $next($request$response);
    $response->getBody()->write('AFTER');
 
    return $response;
});
 
$app->get('/'function ($req$res$args) {
    echo ' Hello ';
});
 
$app->run();
 
// This would output this HTTP response body:
// BEFORE Hello AFTER
cs



Route middleware


라우트 미들웨어는 라우트가 현재 HTTP 요청 메소드 및 URI와 일치할 때만 호출된다.

라우트 미들웨어는 Slim app 의 라우팅 메소드(get(), post())를 호출한 다음에 바로 지정된다.

각 라우팅 메소드는 \Slim\Route 인스턴스를 반환하고, 이 클래스는 Slim app 인스턴스로써 같은 미들웨어 인터페이스를 제공한다.

Route 인스턴스의 add() 메소드로 라우트에 미들웨어를 추가하라.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$app = new \Slim\App();
 
$mw = function ($request$response$next) {
    $response->getBody()->write('BEFORE');
    $response = $next($request$response);
    $response->getBody()->write('AFTER');
 
    return $response;
};
 
$app->get('/'function ($req$res$args) {
    echo ' Hello ';
})->add($mw);
 
$app->run();
 
// This would output this HTTP response body:
// BEFORE Hello AFTER
cs



Group Middleware


모든 어플리케이션과 미들웨어를 적용할 수 있는 표준 라우트에 더하여, group() 멀티 라우트 정의 기능 또한 내부적으로 각 라우트를 허용한다.

라우트 그룹 미들웨어는 라우트가 그룹으로부터 정의된 HTTP 요청 메소드 및 URI 중 하나와 일치하면 호출된다.

콜백 내에 미들웨어를 추가하려면 group() 메소드 뒤에 add() 메소드로 설정하라.


다음은 url-핸들러 그룹에 콜백 미들웨어를 사용하는 예제이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
 
require_once __DIR__.'/vendor/autoload.php';
 
$app = new \Slim\App();
 
$app->get('/'function ($request$response) {
    return $response->getBody()->write('Hello World');
});
 
$app->group('/utils'function () use ($app) {
    $app->get('/date'function ($request$response) {
        return $response->getBody()->write(date('Y-m-d H:i:s'));
    });
    $app->get('/time'function ($request$response) {
        return $response->getBody()->write(time());
    });
})->add(function ($request$response$next) {
    $response->getBody()->write('It is now ');
    $response = $next($request$response);
    $response->getBody()->write('. Enjoy!');
 
    return $response;
});
 
// When calling the /utils/date method, output:
// It is now 2015-07-06 03:11:01. Enjoy!
 
// visiting /utils/time, output:
// It is now 1436148762. Enjoy!
 
// but visiting / (domain-root), no middleware has been assigned, output:
// Hello World
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Slim PSR-7

Programming/Slim 2016. 2. 28. 01:01

Slim 은 Request 와 Response 객체에 대해 PSR-7 인터페이스를 제공한다.

예를 들면, Slim 의 라우트는 \Slim\Http\Response 인스턴스를 반환하지 않고,

\GuzzleHttp\Psr7\CachingStream 의 인스턴스나 \GuzzleHttp\Psr7\stream_for() 함수로부터 전달된 인스턴스를 반환할 수 있다.


Slim 은 자체 PSR-7 인터페이스 구현을 제공하지만, Slim 의 기본 PSR-7 객체를 서드파티 구현으로 대신할 수도 있다.

단지 \Psr\Http\Message\ServerRequestInterface 와 \Psr\Http\Message\ResponseInterface 각각의 인스턴스로 어플리케이션의 request 와 response 서비스를 덮어 씌우면 된다.



Value objects


Slim 의 Request 와 Response 객체는 변하지 않는 Value Object 이다.

이 객체들은 변경된 속성 값을 가진 복제된 버전을 요청하여 변경될 수 있다.

이 때의 처리 시간/메모리(overhead)등은 성능에 영향을 주지 않는다.


우리는 어떤 PSR-7 인터페이스 메소드를 호출하여 값 객체의 복사를 요청할 수 있다.

예를 들면, PSR-7 Response 객체의 withHeader($name, $value) 메소드는 새로운 HTTP header 로 복제된 값 객체를 반환한다.


1
2
3
4
5
6
7
8
9
<?php
$app = new \Slim\App;
$app->get('/foo'function ($req$res$args) {
    return $res->withHeader(
        'Content-Type',
        'application/json'
    );
});
$app->run();
cs



Request 와 Response 객체를 변경하는 PSR-7 인터페이스의 메소드


  • withProtocolVersion($version)
  • withHeader($name, $value)
  • withAddedHeader($name, $value)
  • withoutHeader($name)
  • withBody(StreamInterface $body)


Request 객체를 변경하는 PSR-7 인터페이스의 메소드


  • withMethod($method)
  • withUri(UriInterface $uri, $preserveHost = false)
  • withCookieParams(array $cookies)
  • withQueryParams(array $query)
  • withUploadedFiles(array $uploadedFiles)
  • withParsedBody($data)
  • withAttribute($name, $value)
  • withoutAttribute($name)


Response 객체를 변경하는 PSR-7 인터페이스의 메소드

  • withStatus($code, $reasonPhrase = '')




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,