Symfony HttpFoundation使用文档

1.概述

HttpFoundation组件是在HTTP基础上提供了一个面向对象操作封装。在PHP中,我们通常使用\$_GET\$_POST\$_FILES\$_COOKIE\$_SESSION,…等全局变量来读取HTTP请求内容(request),使用函数:echoheader()setcookie(),…**等来生成响应内容(response)。**Symfony HttpFoundation对这些全局变量和函数进行了封装,提供了一个面向对象操作层。

2.安装

如果你已经安装了composer包管理器,那么可以使用下面的命令进行安装:

$ composer require symfony/http-foundation

或者,直接克隆git项目:https://github.com/symfony/http-foundation 。

如果你是在Symfony应用之外单独使用HttpFoundation组件,那么你需要在脚本中引入vendor/autoload.php文件,这是HttpFoundation组件类加载文件。

3.Request

通常,我们可以使用函数::createFromGlobals()来创建一个request

use Symfony\Component\HttpFoundation\Request;

$request = Request::createFromGlobals();

这等同于下面通过构造函数__construct()来创建request对象的方式:

$request = new Request(
    $_GET,
    $_POST,
    array(),
    $_COOKIE,
    $_FILES,
    $_SERVER
);

(1)访问Request数据

Request对象中包含着一个客户端请求request的数据,我们可以通过下面几个Request对象的属性来进行读取:

  • request: 等同于$_POST;
  • query: 等同于$_GET ($request->query->get('name'));
  • cookies: 等同于$_COOKIE;
  • attributes: 用于存储一些其它的数据
  • files: 等同于$_FILES;
  • server: 等同于$_SERVER;
  • headers: 相当于$_SERVER的子集 ($request->headers->get('User-Agent')).

每个属性实质上都是一个ParameterBag 实例,如下:

  • requestParameterBag
  • queryParameterBag
  • cookiesParameterBag
  • attributesParameterBag
  • filesFileBag
  • serverServerBag
  • headersHeaderBag

为便于操作和复用,HttpFoundation组件对这些参数进行了统一封装,ParameterBagFileBagServerBagHeaderBagRequest类图如下:

经过这样的参数封装之后,我们可以使用add方法,存储一些其它的数据到request对象中,在我们的应用中就可以很方便的进行读取。

我们可以使用content()方法获取原始请求体(request body)的内容,这对于处理客户端通过POST方法提交过来的JSON字符串非常有用:

$content = $request->getContent();

(2)模拟Request请求

我们可以通过下面的方式模拟一个request请求

$request = Request::create(
    '/hello-world',
    'GET',
    array('name' => 'Fabien')
);

在这个request对象的基础上,可以使用overrideGlobals()方法来覆盖PHP全局的变量。

$request->overrideGlobals();

(3)读取Session

如果请求中包含session信息,可以使用getSession()方法来读取会话信息,返回的是一个Session

$session = $request->getSession();

可以使用hasSession()方法来检测请求中是否包含session信息。

(4)HTTP 头部处理

Symfony提供了一个HeaderUtils类,专门用于处理头部的空白和转义等字符。

use Symfony\Component\HttpFoundation\HeaderUtils;

// 使用一个或多个字符对HTTP header进行分割
HeaderUtils::split('da, en-gb;q=0.8', ',;');
// 返回结果:array(array('da'), array('en-gb','q=0.8'))

// Combines an array of arrays into one associative array
HeaderUtils::combine(array(array('foo', 'abc'), array('bar')));
// 返回结果:array('foo' => 'abc', 'bar' => true)

// Joins an associative array into a string for use in an HTTP header
HeaderUtils::toString(array('foo' => 'abc', 'bar' => true, 'baz' => 'a b c'), ',');
// 返回结果:'foo=abc, bar, baz="a b c"'

// 对引号字符进行转义
HeaderUtils::quote('foo "bar"');
// 返回结果: '"foo \"bar\""'

// 去掉转义字符,返回原字符串
HeaderUtils::unquote('"foo \"bar\""');
// 返回结果:'foo "bar"'

(5)读取HTTP头部Accept-*数据

  • getAcceptableContentTypes():返回一个可接受的内容类型列表,按照容忍系数的大小降序排列。

  • getLanguages():返回可接受的语言类型列表,按照容忍系数的大小降序排列。

  • getCharsets():返回可接受的字符编码集列表,按照容忍系数的大小降序排列。

  • getEncodings():返回可接受的传输编码格式列表,按照容忍系数的大小降序排列。

(6)覆盖Request

一般情况下,我们不应该对HTTP请求进行覆盖操作,但是作为应用代理的角色时,我们需要一些修改HTTP Request内容的操作。如下所示:

use App\Http\SpecialRequest;
use Symfony\Component\HttpFoundation\Request;

Request::setFactory(function (
    array $query = array(),
    array $request = array(),
    array $attributes = array(),
    array $cookies = array(),
    array $files = array(),
    array $server = array(),
    $content = null
) {
    return new SpecialRequest(
        $query,
        $request,
        $attributes,
        $cookies,
        $files,
        $server,
        $content
    );
});

$request = Request::createFromGlobals();

4.Response

Response对象中包含了需要返回给客户端的全部信息,它的构造需要三个参数:响应内容、状态码、头部字段数组。如下所示:

use Symfony\Component\HttpFoundation\Response;

$response = new Response(
    'Content',
    Response::HTTP_OK,
    array('content-type' => 'text/html')
);

Response对象创建完成后,我们还可以继续对其进行修改。

$response->setContent('Hello World');

// 头部的公共属性是一个ResponseHeaderBag对象
$response->headers->set('Content-Type', 'text/plain');

$response->setStatusCode(Response::HTTP_NOT_FOUND);

(1)发送响应

发送响应之前,可选择调用prepare()方法,主要用于处理HTTP标准的相关兼容性问题。

$response->prepare($request);

调用send()方法,发送响应给客户端。

$response->send();

(2)设置Cookie

响应的cookie的设置主要通过配置header的公共属性来实现:

use Symfony\Component\HttpFoundation\Cookie;

$response->headers->setCookie(new Cookie('foo', 'bar'));

setCookie()方法需要Cookie类的实例作为参数。

clearCookie()方法可以清除cookie。

(3)管理HTTP缓存

涉及到缓存设置的方法如下:

  • setPublic():设置cache-directive的值为public,所有内容都将被缓存(客户端和代理服务器都可缓存)。
  • setPrivate():设置cache-directive的值为private,内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)。
  • expire()
  • setExpires():设置缓存过期时间。
  • setMaxAge():设定max-age。指示客户端愿意接收其绝对时间不大于指定的时间,以秒计。除非还包含 max-stale 指令,否则客户端不期望接收一个陈旧的响应。
  • setSharedMaxAge():设置s-maxage。如果一个响应包含 s-maxage 指令,那么对于共享缓存(而不是对私有缓存),由该指令规定的最大绝对时间会覆盖由 max-age 指令或 Expires 头规定的最绝对时间。s-maxage 指令也隐含 proxy-revalidate 指令的语义(将在本文“控制缓存重新验证和重新加载”小节介绍),也就是说,当共享缓存对接下来的请求的响应变得陈旧后,该请求没有与源服务器重新验证,共享缓存不能使用缓存条目。私有缓存总是忽略 s-maxage 指令。

一般情况下,我们使用setCache()方法就可以完成大多数cache设置。

$response->setCache(array(
    'etag'          => 'abcdef',
    'last_modified' => new \DateTime(),
    'max_age'       => 600,
    's_maxage'      => 600,
    'private'       => false,
    'public'        => true,
));

(4)重定向

将客户端的请求重定位到指定的URL,需要引入RedirectResponse类。

use Symfony\Component\HttpFoundation\RedirectResponse;

$response = new RedirectResponse('http://example.com/');

(5)输出流

脚本执行过程中输出到客户端的数据先暂存到缓存中,最后一并发送给客户端,StreamedResponse类会将输出缓存流中的数据全部发送到客户端。

use Symfony\Component\HttpFoundation\StreamedResponse;

$response = new StreamedResponse();
$response->setCallback(function () {
    var_dump('Hello World');
    flush();
    sleep(2);
    var_dump('Hello World');
    flush();
});
$response->send();

(6)文件服务

发送文件时,必须要在Response的头部添加Content-Dispositon字段。Content-disposition是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。当 Internet Explorer 接收到头时,它会激活文件下载对话框,它的文件名框自动填充了头中指定的文件名(请注意,这是设计导致的;无法使用此功能将文档保存到用户的计算机上,而不向用户询问保存位置)。

例:Content-Disposition: attachment; filename=FileName.txt,就是当用户想把请求所得的内容存为一个文件的时候提供一个默认的文件名。

Symfony将相关的设置操作进行了封装,提供了makeDisposition()方法。

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

$fileContent = ...; // 生成好的文件内容
$response = new Response($fileContent);

$disposition = $response->headers->makeDisposition(
    ResponseHeaderBag::DISPOSITION_ATTACHMENT,
    'foo.pdf'
);

$response->headers->set('Content-Disposition', $disposition);

如果提供的文件是一个静态文件,也可以使用BinaryFileResponse类方便操作。

use Symfony\Component\HttpFoundation\BinaryFileResponse;

$file = 'path/to/file.txt';
$response = new BinaryFileResponse($file);

文件过大需要分段传输时,BinaryFileResponse类会自动处理请求头部的RangeIf-Range参数。如果服务器支持X-Sendfile,可以使用trustXSendfileTypeHeader()方法来启用。

BinaryFileResponse::trustXSendfileTypeHeader();

知识介绍X-Sendfile 是一种将文件下载请求由后端应用转交给前端 web 服务器处理的机制,它可以消除后端程序既要读文件又要处理发送的压力,从而显著提高服务器效率,特别是处理大文件下载的情形下。X-Sendfile 通过一个特定的 HTTP header 来实现:在 X-Sendfile头中指定一个文件的地址来通告前端 web 服务器。当 web 服务器检测到后端发送的这个 header 后,它将忽略后端的其他输出,而使用自身的组件包括缓存头和断点重连等优化机制将文件发送给用户。不过,在使用 X-Sendfile之前,我们必须明白这并不是一个标准特性,在默认情况下它是被大多数 web 服务器禁用的。而不同的 web 服务器的实现也不一样,包括规定了不同的 X-Sendfile头格式。如果配置失当,用户可能下载到 0 字节的文件。使用 X-Sendfile将允许下载非 web 目录中的文件例如/root/,即使文件在 .htaccess 保护下禁止访问,也会被下载。

对于BinaryFileResponse,我们仍然可以对文件的Content-Type属性和以及响应头部的Content-Disposition字段进行修改。

// ...
$response->headers->set('Content-Type', 'text/plain');
$response->setContentDisposition(
    ResponseHeaderBag::DISPOSITION_ATTACHMENT,
    'filename.txt'
);

Symfnoy提供了deleteFileAfterSend()方法,用于文件发送完成后删除缓存的文件,释放内存。需要注意的是:对于使用了X-Sendfile文件发送机制来说,不会起作用。

$response->deleteFileAfterSend(true);

(7)创建JSON响应

通过设置Response类的内容属性和头部属性,我们就可以生成想要的响应。如返回一个JSON响应,设置正确的响应内容和头部字段:

use Symfony\Component\HttpFoundation\Response;

$response = new Response();
// 填充内容
$response->setContent(json_encode(array(
    'data' => 123,
)));
// 设置头部字段
$response->headers->set('Content-Type', 'application/json');

可以使用工具类JsonResponse,简化我们的操作:

use Symfony\Component\HttpFoundation\JsonResponse;

// 创建JsonResponse对象的同时设置响应的内容属性
$response = new JsonResponse(array('data' => 123));

// 创建一个内容属性为空的JsonResponse对象
$response = new JsonResponse();
// 设置内容属性
$response->setData(array('data' => 123));

// 直接从JSON字符串生成JsonResponse对象
$response = JsonResponse::fromJsonString('{ "data": 123 }');

从上面的过程中我们可以看出,JsonResponse类实际上完成了将Content-Type设置为application/json和将数据编码成JSON格式的操作。

(8)JSONP回调

使用JSONP时,需要设置一个回调函数,在这个回调函数中,将要发送的数据作为参数赋值给回调函数。

$response->setCallback('handleResponse');
handleResponse({'data': 123});

返回给客户端的响应头部中的Content-Type会自动被设置为text/javascript

5.Session

Symfony HttpFoundation Session组件对底层的session存储驱动也进行了封装,支持多种存储方式。Session类实现列SessionInterface借口,提供了对Session的全部操作。

(1)基本操作

如下代码:

use Symfony\Component\HttpFoundation\Session\Session;

$session = new Session();
$session->start();

// 设置session
$session->set('name', 'Drak');

// 读取session
$session->get('name');

// 设置 flash messages
$session->getFlashBag()->add('notice', 'Profile updated');

// 重新读取 messages
foreach ($session->getFlashBag()->get('notice', array()) as $message) {
    echo '
'.$message.'
'; }

注意:应避免使用PHP提供的session_start(),session_regenerate_id(),session_id(),session_name()session_destroy()函数。这些函数只对PHP提供的会话机制有效,对于第三方代理会话系统无效。

(2)会话工作流操作

  • start():启动会话
  • migrate()
  • invalidate():清除全部会话数据和会话ID
  • getId():获取会话ID
  • setId():设置会话ID
  • getName():获取会话name
  • setName():设置会话name

(3)用户会话属性操作

  • set():设置用户会话属性
  • get():读取用户会话属性
  • all():以关联数组的形式读取全部的用户属性
  • has():检测用户会话属性是否存在
  • replace():覆盖指定键名的用户会话属性
  • remove():移除指定键名的用户会话属性
  • clear():清除全部用户存储的会话属性

示例:

use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;

$session = new Session(new NativeSessionStorage(), new AttributeBag());
$session->set('token', 'a6c1e0b6');
// ...
$token = $session->get('token');
// 如果用户会话属性不存在,返回默认值 'default-attribute-value'
$token = $session->get('attribute-name', 'default-attribute-value');
// ...
$session->clear();

你可能感兴趣的:(Symfony,PHP,Symfony,Symfony)