diff --git a/docs/guide-zh-CN/README.md b/docs/guide-zh-CN/README.md index 31ae463..0a9d686 100644 --- a/docs/guide-zh-CN/README.md +++ b/docs/guide-zh-CN/README.md @@ -62,7 +62,7 @@ Yii 2.0 权威指南 * **已定稿** [行为(Behavior)](concept-behaviors.md) * **已定稿** [配置(Configurations)](concept-configurations.md) * **已定稿** [类自动加载(Autoloading)](concept-autoloading.md) -* **已定稿** [别名(Alias)](concept-alias.md) +* **已定稿** [别名(Alias)](concept-aliases.md) * **已定稿** [服务定位器(Service Locator)](concept-service-locator.md) * **已定稿** [依赖注入容器(DI Container)](concept-di-container.md) diff --git a/docs/guide-zh-CN/rest-quick-start.md b/docs/guide-zh-CN/rest-quick-start.md index 16d7820..17e5717 100644 --- a/docs/guide-zh-CN/rest-quick-start.md +++ b/docs/guide-zh-CN/rest-quick-start.md @@ -1,24 +1,24 @@ 快速入门 =========== -Yii 提供了一整套用来简化实现RESTful风格的Web Service服务的API。 -特别是,Yii支持以下关于RESTful风格的API: +Yii 提供了一整套用来简化实现 RESTful 风格的 Web Service 服务的 API。 +特别是,Yii 支持以下关于 RESTful 风格的 API: -* 支持 [Active Record](db-active-record.md) 类的通用API的快速原型; -* 涉及的响应格式(在默认情况下支持JSON 和 XML); -* 支持可选输出字段的 可定制对象序列化; -* 适当的格式的数据采集和验证错误; -* 支持 [HATEOAS](http://en.wikipedia.org/wiki/HATEOAS); -* 有适当HTTP动词检查的高效的路由; -* 内置`OPTIONS`和`HEAD`动词的支持; -* 认证和授权; -* 数据缓存和HTTP缓存; -* 速率限制; +* 支持 [Active Record](db-active-record.md) 类的通用API的快速原型 +* 涉及的响应格式(在默认情况下支持 JSON 和 XML) +* 支持可选输出字段的定制对象序列化 +* 适当的格式的数据采集和验证错误 +* 支持 [HATEOAS](http://en.wikipedia.org/wiki/HATEOAS) +* 有适当HTTP动词检查的高效的路由 +* 内置`OPTIONS`和`HEAD`动词的支持 +* 认证和授权 +* 数据缓存和HTTP缓存 +* 速率限制 如下, 我们用一个例子来说明如何用最少的编码来建立一套RESTful风格的API。 -假设你想通过RESTful风格的API来展示用户数据。用户数据被存储在用户DB表, +假设你想通过 RESTful 风格的 API 来展示用户数据。用户数据被存储在用户DB表, 你已经创建了 [[yii\db\ActiveRecord|ActiveRecord]] 类 `app\models\User` 来访问该用户数据. @@ -56,26 +56,26 @@ class UserController extends ActiveController ] ``` -上面的配置主要是为`user`控制器增加一个URL规则。这样, -用户的数据就能通过美化的URL和有意义的http动词进行访问和操作。 +上面的配置主要是为`user`控制器增加一个 URL 规则。这样, +用户的数据就能通过美化的 URL 和有意义的 http 动词进行访问和操作。 ## 尝试 <a name="trying-it-out"></a> 随着以上所做的最小的努力,你已经完成了创建用于访问用户数据 -的RESTful风格的API。您所创建的API包括: +的 RESTful 风格的 API。你所创建的 API 包括: -* `GET /users`: 逐页列出所有用户; -* `HEAD /users`: 显示用户列表的概要信息; -* `POST /users`: 创建一个新用户; -* `GET /users/123`: 返回用户为123的详细信息; -* `HEAD /users/123`: 显示用户 123 的概述信息; -* `PATCH /users/123` and `PUT /users/123`: 更新用户123; -* `DELETE /users/123`: 删除用户123; -* `OPTIONS /users`: 显示关于末端 `/users` 支持的动词; -* `OPTIONS /users/123`: 显示有关末端 `/users/123` 支持的动词。 +* `GET /users`: 逐页列出所有用户 +* `HEAD /users`: 显示用户列表的概要信息 +* `POST /users`: 创建一个新用户 +* `GET /users/123`: 返回用户 123 的详细信息 +* `HEAD /users/123`: 显示用户 123 的概述信息 +* `PATCH /users/123` and `PUT /users/123`: 更新用户123 +* `DELETE /users/123`: 删除用户123 +* `OPTIONS /users`: 显示关于末端 `/users` 支持的动词 +* `OPTIONS /users/123`: 显示有关末端 `/users/123` 支持的动词 -> Info: Yii将在末端使用的控制器的名称自动变为复数。 +> 补充:Yii 将在末端使用的控制器的名称自动变为复数。(译注:个人感觉这里应该变为注意) 你可以访问你的API用`curl`命令如下, @@ -109,7 +109,7 @@ Content-Type: application/json; charset=UTF-8 ] ``` -试着改变可接受的内容类型为`application/xml`,你会看到结果以XML格式返回: +试着改变可接受的内容类型为`application/xml`,你会看到结果以 XML 格式返回: ``` $ curl -i -H "Accept:application/xml" "http://localhost/users" @@ -142,33 +142,32 @@ Content-Type: application/xml </response> ``` -> Tip: 您还可以通过Web浏览器中输入URL `http://localhost/users` 来访问你的API。 - 尽管如此,你可能需要一些浏览器插件来发送特定的headers请求。 +> 技巧:你还可以通过 Web 浏览器中输入 URL `http://localhost/users` 来访问你的 API。 + 尽管如此,你可能需要一些浏览器插件来发送特定的 headers 请求。 -如你所见, 在headers响应, 有关于总数,页数的信息,等等。 -还有一些链接,让您导航到其他页面的数据. 例如, `http://localhost/users?page=2` +如你所见,在 headers 响应,有关于总数,页数的信息,等等。 +还有一些链接,让你导航到其他页面的数据。例如: `http://localhost/users?page=2` 会给你的用户数据的下一个页面。 -使用 `fields` 和 `expand` 参数, 您也可以指定哪些字段应该包含在结果内。 -例如, URL `http://localhost/users?fields=id,email` 将只返回 `id` 和 `email` 字段。 +使用 `fields` 和 `expand` 参数,你也可以指定哪些字段应该包含在结果内。 +例如:URL `http://localhost/users?fields=id,email` 将只返回 `id` 和 `email` 字段。 -> Info: 您可能已经注意到了 `http://localhost/users` 的结果包括一些敏感字段, -> 例如 `password_hash`, `auth_key`。 你肯定不希望这些出现在你的API结果中。 -> 你应该在 [Response Formatting](rest-response-formatting.md) 部分中过滤掉这些字段。 +> 补充:你可能已经注意到了 `http://localhost/users` 的结果包括一些敏感字段, +> 例如 `password_hash`, `auth_key` 你肯定不希望这些出现在你的 API 结果中。 +> 你应该在 [响应格式](rest-response-formatting.md) 部分中过滤掉这些字段。 ## 总结 <a name="summary"></a> -使用Yii框架的RESTful风格的API, 在控制器的操作中实现API末端, 使用 +使用 Yii 框架的 RESTful 风格的 API, 在控制器的操作中实现API末端,使用 控制器来组织末端接口为一个单一的资源类型。 从 [[yii\base\Model]] 类扩展的资源被表示为数据模型。 -如果你在使用(关系或非关系)数据库,推荐您使用 [[yii\db\ActiveRecord|ActiveRecord]] +如果你在使用(关系或非关系)数据库,推荐你使用 [[yii\db\ActiveRecord|ActiveRecord]] 来表示资源。 -你可以使用 [[yii\rest\UrlRule]] 简化路由到你的API末端。 +你可以使用 [[yii\rest\UrlRule]] 简化路由到你的 API 末端。 -虽然不是必须的,为了方便维护您的WEB前端和后端, -建议您开发接口作为一个单独的应用程序。 +为了方便维护你的WEB前端和后端,建议你开发接口作为一个单独的应用程序,虽然这不是必须的。 diff --git a/docs/guide-zh-CN/runtime-responses.md b/docs/guide-zh-CN/runtime-responses.md new file mode 100644 index 0000000..5098ad0 --- /dev/null +++ b/docs/guide-zh-CN/runtime-responses.md @@ -0,0 +1,233 @@ +响应 +========= + +当应用完成处理一个[请求](runtime-requests.md)后, 会生成一个[[yii\web\Response|response]]响应对象并发送给终端用户 +响应对象包含的信息有HTTP状态码,HTTP头和主体内容等, 网页应用开发的最终目的本质上就是根据不同的请求构建这些响应对象。 + +在大多是情况下主要处理继承自 [[yii\web\Response]] 的 `response` [应用组件](structure-application-components.md), +尽管如此,Yii也允许你创建你自己的响应对象并发送给终端用户,这方面后续会阐述。 + +在本节,将会描述如何构建响应和发送给终端用户。 + + +## 状态码 <a name="status-code"></a> + +构建响应时,最先应做的是标识请求是否成功处理的状态,可通过设置 +[[yii\web\Response::statusCode]] 属性,该属性使用一个有效的 +[HTTP 状态码](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)。例如,为标识处理已被处理成功, +可设置状态码为200,如下所示: + +```php +Yii::$app->response->statusCode = 200; +``` + +尽管如此,大多数情况下不需要明确设置状态码,因为 [[yii\web\Response::statusCode]] 状态码默认为200, +如果需要指定请求失败,可抛出对应的HTTP异常,如下所示: + +```php +throw new \yii\web\NotFoundHttpException; +``` + +当[错误处理器](runtime-handling-errors.md) 捕获到一个异常,会从异常中提取状态码并赋值到响应, +对于上述的 [[yii\web\NotFoundHttpException]] 对应HTTP 404状态码,以下为Yii预定义的HTTP异常: + +* [[yii\web\BadRequestHttpException]]: status code 400. +* [[yii\web\ConflictHttpException]]: status code 409. +* [[yii\web\ForbiddenHttpException]]: status code 403. +* [[yii\web\GoneHttpException]]: status code 410. +* [[yii\web\MethodNotAllowedHttpException]]: status code 405. +* [[yii\web\NotAcceptableHttpException]]: status code 406. +* [[yii\web\NotFoundHttpException]]: status code 404. +* [[yii\web\ServerErrorHttpException]]: status code 500. +* [[yii\web\TooManyRequestsHttpException]]: status code 429. +* [[yii\web\UnauthorizedHttpException]]: status code 401. +* [[yii\web\UnsupportedMediaTypeHttpException]]: status code 415. + +如果想抛出的异常不在如上列表中,可创建一个[[yii\web\HttpException]]异常,带上状态码抛出,如下: + +```php +throw new \yii\web\HttpException(402); +``` + + +## HTTP 头部 <a name="http-headers"></a> + +可在 `response` 组件中操控[[yii\web\Response::headers|header collection]]来发送HTTP头部信息,例如: + +```php +$headers = Yii::$app->response->headers; + +// 增加一个 Pragma 头,已存在的Pragma 头不会被覆盖。 +$headers->add('Pragma', 'no-cache'); + +// 设置一个Pragma 头. 任何已存在的Pragma 头都会被丢弃 +$headers->set('Pragma', 'no-cache'); + +// 删除Pragma 头并返回删除的Pragma 头的值到数组 +$values = $headers->remove('Pragma'); +``` + +> 补充: 头名称是大小写敏感的,在[[yii\web\Response::send()]]方法调用前新注册的头信息并不会发送给用户。 + + +## 响应主体 <a name="response-body"></a> + +大多是响应应有一个主体存放你想要显示给终端用户的内容。 + +如果已有格式化好的主体字符串,可赋值到响应的[[yii\web\Response::content]]属性,例如: + +```php +Yii::$app->response->content = 'hello world!'; +``` + +如果在发送给终端用户之前需要格式化,应设置 +[[yii\web\Response::format|format]] 和 [[yii\web\Response::data|data]] 属性,[[yii\web\Response::format|format]] +属性指定[[yii\web\Response::data|data]]中数据格式化后的样式,例如: + +```php +$response = Yii::$app->response; +$response->format = \yii\web\Response::FORMAT_JSON; +$response->data = ['message' => 'hello world']; +``` + +Yii支持以下可直接使用的格式,每个实现了[[yii\web\ResponseFormatterInterface|formatter]] 类, +可自定义这些格式器或通过配置[[yii\web\Response::formatters]] 属性来增加格式器。 + +* [[yii\web\Response::FORMAT_HTML|HTML]]: 通过 [[yii\web\HtmlResponseFormatter]] 来实现. +* [[yii\web\Response::FORMAT_XML|XML]]: 通过 [[yii\web\XmlResponseFormatter]]来实现. +* [[yii\web\Response::FORMAT_JSON|JSON]]: 通过 [[yii\web\JsonResponseFormatter]]来实现. +* [[yii\web\Response::FORMAT_JSONP|JSONP]]: 通过 [[yii\web\JsonResponseFormatter]]来实现. + +上述响应主体可明确地被设置,但是在大多数情况下是通过 [操作](structure-controllers.md) 方法的返回值隐式地设置,常用场景如下所示: + +```php +public function actionIndex() +{ + return $this->render('index'); +} +``` + +上述的 `index` 操作返回 `index` 视图渲染结果,返回值会被 `response` 组件格式化后发送给终端用户。 + +因为响应格式默认为[[yii\web\Response::FORMAT_HTML|HTML]], 只需要在操作方法中返回一个字符串, +如果想使用其他响应格式,应在返回数据前先设置格式,例如: + +```php +public function actionInfo() +{ + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + return [ + 'message' => 'hello world', + 'code' => 100, + ]; +} +``` + +如上所述,触雷使用默认的 `response` 应用组件,也可创建自己的响应对象并发送给终端用户,可在操作方法中返回该响应对象,如下所示: + +```php +public function actionInfo() +{ + return \Yii::createObject([ + 'class' => 'yii\web\Response', + 'format' => \yii\web\Response::FORMAT_JSON, + 'data' => [ + 'message' => 'hello world', + 'code' => 100, + ], + ]); +} +``` + +> 注意: 如果创建你自己的响应对象,将不能在应用配置中设置 `response` 组件,尽管如此, + 可使用 [依赖注入](concept-di-container.md) 应用通用配置到你新的响应对象。 + + +## 浏览器跳转 <a name="browser-redirection"></a> + +浏览器跳转依赖于发送一个`Location` HTTP 头,因为该功能通常被使用,Yii提供对它提供了特别的支持。 + +可调用[[yii\web\Response::redirect()]] 方法将用户浏览器跳转到一个URL地址,该方法设置合适的 +带指定URL的 `Location` 头并返回它自己为响应对象,在操作的方法中,可调用缩写版[[yii\web\Controller::redirect()]],例如: + +```php +public function actionOld() +{ + return $this->redirect('http://example.com/new', 301); +} +``` + +在如上代码中,操作的方法返回`redirect()` 方法的结果,如前所述,操作的方法返回的响应对象会被当总响应发送给终端用户。 + +除了操作方法外,可直接调用[[yii\web\Response::redirect()]] 再调用 +[[yii\web\Response::send()]] 方法来确保没有其他内容追加到响应中。 + +```php +\Yii::$app->response->redirect('http://example.com/new', 301)->send(); +``` + +> 补充: [[yii\web\Response::redirect()]] 方法默认会设置响应状态码为302,该状态码会告诉浏览器请求的资源 + *临时* 放在另一个URI地址上,可传递一个301状态码告知浏览器请求的资源已经 *永久* 重定向到新的URId地址。 + +如果当前请求为AJAX 请求,发送一个 `Location` 头不会自动使浏览器跳转,为解决这个问题, +[[yii\web\Response::redirect()]] 方法设置一个值为要跳转的URL的`X-Redirect` 头, +在客户端可编写JavaScript 代码读取该头部值然后让浏览器跳转对应的URL。 + +> 补充: Yii 配备了一个`yii.js` JavaScript 文件提供常用JavaScript功能,包括基于`X-Redirect`头的浏览器跳转, + 因此,如果你使用该JavaScript 文件(通过[[yii\web\YiiAsset]] 资源包注册),就不需要编写AJAX跳转的代码。 + + +## 发送文件 <a name="sending-files"></a> + +和浏览器跳转类似,文件发送是另一个依赖指定HTTP头的功能,Yii提供方法集合来支持各种文件发送需求,它们对HTTP头都有内置的支持。 + +* [[yii\web\Response::sendFile()]]: 发送一个已存在的文件到客户端 +* [[yii\web\Response::sendContentAsFile()]]: 发送一个文本字符串作为文件到客户端 +* [[yii\web\Response::sendStreamAsFile()]]: 发送一个已存在的文件流作为文件到客户端 + +这些方法都将响应对象作为返回值,如果要发送的文件非常大,应考虑使用 +[[yii\web\Response::sendStreamAsFile()]] 因为它更节约内存,以下示例显示在控制器操作中如何发送文件: + +```php +public function actionDownload() +{ + return \Yii::$app->response->sendFile('path/to/file.txt'); +} +``` + +如果不是在操作方法中调用文件发送方法,在后面还应调用 [[yii\web\Response::send()]] 没有其他内容追加到响应中。 + +```php +\Yii::$app->response->sendFile('path/to/file.txt')->send(); +``` + +一些浏览器提供特殊的名为*X-Sendfile*的文件发送功能,原理为将请求跳转到服务器上的文件, +Web应用可在服务器发送文件前结束,为使用该功能,可调用[[yii\web\Response::xSendFile()]], +如下简要列出一些常用Web服务器如何启用`X-Sendfile` 功能: + +- Apache: [X-Sendfile](http://tn123.org/mod_xsendfile) +- Lighttpd v1.4: [X-LIGHTTPD-send-file](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file) +- Lighttpd v1.5: [X-Sendfile](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file) +- Nginx: [X-Accel-Redirect](http://wiki.nginx.org/XSendfile) +- Cherokee: [X-Sendfile and X-Accel-Redirect](http://www.cherokee-project.com/doc/other_goodies.html#x-sendfile) + + +## 发送响应 <a name="sending-response"></a> + +在[[yii\web\Response::send()]] 方法调用前响应中的内容不会发送给用户,该方法默认在[[yii\base\Application::run()]] +结尾自动调用,尽管如此,可以明确调用该方法强制立即发送响应。 + +[[yii\web\Response::send()]] 方法使用以下步骤来发送响应: + +1. 触发 [[yii\web\Response::EVENT_BEFORE_SEND]] 事件. +2. 调用 [[yii\web\Response::prepare()]] 来格式化 [[yii\web\Response::data|response data]] 为 + [[yii\web\Response::content|response content]]. +3. 触发 [[yii\web\Response::EVENT_AFTER_PREPARE]] 事件. +4. 调用 [[yii\web\Response::sendHeaders()]] 来发送注册的HTTP头 +5. 调用 [[yii\web\Response::sendContent()]] 来发送响应主体内容 +6. 触发 [[yii\web\Response::EVENT_AFTER_SEND]] 事件. + +一旦[[yii\web\Response::send()]] 方法被执行后,其他地方调用该方法会被忽略, +这意味着一旦响应发出后,就不能再追加其他内容。 + +如你所见[[yii\web\Response::send()]] 触发了几个实用的事件,通过响应这些事件可调整或包装响应。 diff --git a/docs/guide-zh-CN/runtime-sessions-cookies.md b/docs/guide-zh-CN/runtime-sessions-cookies.md new file mode 100644 index 0000000..28c74dc --- /dev/null +++ b/docs/guide-zh-CN/runtime-sessions-cookies.md @@ -0,0 +1,314 @@ +Sessions 和 Cookies +==================== + +[译注:Session中文翻译为会话,Cookie有些翻译成小甜饼,不贴切,两个单词保留英文] Sessions 和 cookies 允许数据在多次请求中保持, +在纯PHP中,可以分别使用全局变量`$_SESSION` 和`$_COOKIE` 来访问,Yii将session和cookie封装成对象并增加一些功能, +可通过面向对象方式访问它们。 + + +## Sessions <a name="sessions"></a> + +和 [请求](runtime-requests.md) 和 [响应](runtime-responses.md)类似, +默认可通过为[[yii\web\Session]] 实例的`session` [应用组件](structure-application-components.md) 来访问sessions。 + + +### 开启和关闭 Sessions <a name="opening-closing-sessions"></a> + +可使用以下代码来开启和关闭session。 + +```php +$session = Yii::$app->session; + +// 检查session是否开启 +if ($session->isActive) ... + +// 开启session +$session->open(); + +// 关闭session +$session->close(); + +// 销毁session中所有已注册的数据 +$session->destroy(); +``` + +多次调用[[yii\web\Session::open()|open()]] 和[[yii\web\Session::close()|close()]] 方法并不会产生错误, +因为方法内部会先检查session是否已经开启。 + + +### 访问Session数据 <a name="access-session-data"></a> + +To access the data stored in session, you can do the following: +可使用如下方式访问session中的数据: + +```php +$session = Yii::$app->session; + +// 获取session中的变量值,以下用法是相同的: +$language = $session->get('language'); +$language = $session['language']; +$language = isset($_SESSION['language']) ? $_SESSION['language'] : null; + +// 设置一个session变量,以下用法是相同的: +$session->set('language', 'en-US'); +$session['language'] = 'en-US'; +$_SESSION['language'] = 'en-US'; + +// 删除一个session变量,以下用法是相同的: +$session->remove('language'); +unset($session['language']); +unset($_SESSION['language']); + +// 检查session变量是否已存在,以下用法是相同的: +if ($session->has('language')) ... +if (isset($session['language'])) ... +if (isset($_SESSION['language'])) ... + +// 遍历所有session变量,以下用法是相同的: +foreach ($session as $name => $value) ... +foreach ($_SESSION as $name => $value) ... +``` + +> 补充: 当使用`session`组件访问session数据时候,如果session没有开启会自动开启, +这和通过`$_SESSION`不同,`$_SESSION`要求先执行`session_start()`。 + +当session数据为数组时,`session`组件会限制你直接修改数据中的单元项,例如: + +```php +$session = Yii::$app->session; + +// 如下代码不会生效 +$session['captcha']['number'] = 5; +$session['captcha']['lifetime'] = 3600; + +// 如下代码会生效: +$session['captcha'] = [ + 'number' => 5, + 'lifetime' => 3600, +]; + +// 如下代码也会生效: +echo $session['captcha']['lifetime']; +``` + +可使用以下任意一个变通方法来解决这个问题: + +```php +$session = Yii::$app->session; + +// 直接使用$_SESSION (确保Yii::$app->session->open() 已经调用) +$_SESSION['captcha']['number'] = 5; +$_SESSION['captcha']['lifetime'] = 3600; + +// 先获取session数据到一个数组,修改数组的值,然后保存数组到session中 +$captcha = $session['captcha']; +$captcha['number'] = 5; +$captcha['lifetime'] = 3600; +$session['captcha'] = $captcha; + +// 使用ArrayObject 数组对象代替数组 +$session['captcha'] = new \ArrayObject; +... +$session['captcha']['number'] = 5; +$session['captcha']['lifetime'] = 3600; + +// 使用带通用前缀的键来存储数组 +$session['captcha.number'] = 5; +$session['captcha.lifetime'] = 3600; +``` + +为更好的性能和可读性,推荐最后一种方案,也就是不用存储session变量为数组, +而是将每个数组项变成有相同键前缀的session变量。 + + +### 自定义Session存储 <a name="custom-session-storage"></a> + +[[yii\web\Session]] 类默认存储session数据为文件到服务器上,Yii提供以下session类实现不同的session存储方式: + +* [[yii\web\DbSession]]: 存储session数据在数据表中 +* [[yii\web\CacheSession]]: 存储session数据到缓存中,缓存和配置中的[缓存组件](caching-data.md#cache-components)相关 +* [[yii\redis\Session]]: 存储session数据到以[redis](http://redis.io/) 作为存储媒介中 +* [[yii\mongodb\Session]]: 存储session数据到[MongoDB](http://www.mongodb.org/). + +所有这些session类支持相同的API方法集,因此,切换到不同的session存储介质不需要修改项目使用session的代码。 + +> 注意: 如果通过`$_SESSION`访问使用自定义存储介质的session,需要确保session已经用[[yii\web\Session::open()]] 开启, + 这是因为在该方法中注册自定义session存储处理器。 + +学习如何配置和使用这些组件类请参考它们的API文档,如下为一个示例 +显示如何在应用配置中配置[[yii\web\DbSession]]将数据表作为session存储介质。 + +```php +return [ + 'components' => [ + 'session' => [ + 'class' => 'yii\web\DbSession', + // 'db' => 'mydb', // 数据库连接的应用组件ID,默认为'db'. + // 'sessionTable' => 'my_session', // session 数据表名,默认为'session'. + ], + ], +]; +``` + +也需要创建如下数据库表来存储session数据: + +```sql +CREATE TABLE session +( + id CHAR(40) NOT NULL PRIMARY KEY, + expire INTEGER, + data BLOB +) +``` + +其中'BLOB' 对应你选择的数据库管理系统的BLOB-type类型,以下一些常用数据库管理系统的BLOB类型: + +- MySQL: LONGBLOB +- PostgreSQL: BYTEA +- MSSQL: BLOB + +> 注意: 根据php.ini 设置的 `session.hash_function`,你需要调整`id`列的长度, + 例如,如果 `session.hash_function=sha256` ,应使用长度为64而不是40的char类型。 + + +### Flash 数据 <a name="flash-data"></a> + +Flash数据是一种特别的session数据,它一旦在某个请求中设置后,只会在下次请求中有效,然后该数据就会自动被删除。 +常用于实现只需显示给终端用户一次的信息,如用户提交一个表单后显示确认信息。 + +可通过`session`应用组件设置或访问`session`,例如: + +```php +$session = Yii::$app->session; + +// 请求 #1 +// 设置一个名为"postDeleted" flash 信息 +$session->setFlash('postDeleted', 'You have successfully deleted your post.'); + +// 请求 #2 +// 显示名为"postDeleted" flash 信息 +echo $session->getFlash('postDeleted'); + +// 请求 #3 +// $result 为 false,因为flash信息已被自动删除 +$result = $session->hasFlash('postDeleted'); +``` + +和普通session数据类似,可将任意数据存储为flash数据。 + +当调用[[yii\web\Session::setFlash()]]时, 会自动覆盖相同名的已存在的任何数据, +为将数据追加到已存在的相同名flash中,可改为调用[[yii\web\Session::addFlash()]]。 +例如: + +```php +$session = Yii::$app->session; + +// 请求 #1 +// 在名称为"alerts"的flash信息增加数据 +$session->addFlash('alerts', 'You have successfully deleted your post.'); +$session->addFlash('alerts', 'You have successfully added a new friend.'); +$session->addFlash('alerts', 'You are promoted.'); + +// 请求 #2 +// $alerts 为名为'alerts'的flash信息,为数组格式 +$alerts = $session->getFlash('alerts'); +``` + +> 注意: 不要在相同名称的flash数据中使用[[yii\web\Session::setFlash()]] 的同时也使用[[yii\web\Session::addFlash()]], + 因为后一个防范会自动将flash信息转换为数组以使新的flash数据可追加进来,因此, + 当你调用[[yii\web\Session::getFlash()]]时,会发现有时获取到一个数组,有时获取到一个字符串, + 取决于你调用这两个方法的顺序。 + + +## Cookies <a name="cookies"></a> + +Yii使用 [[yii\web\Cookie]]对象来代表每个cookie,[[yii\web\Request]] 和 [[yii\web\Response]] +通过名为'cookies'的属性维护一个cookie集合,前者的cookie 集合代表请求提交的cookies, +后者的cookie集合表示发送给用户的cookies。 + + +### 读取 Cookies <a name="reading-cookies"></a> + +当前请求的cookie信息可通过如下代码获取: + +```php +// 从 "request"组件中获取cookie集合(yii\web\CookieCollection) +$cookies = Yii::$app->request->cookies; + +// 获取名为 "language" cookie 的值,如果不存在,返回默认值"en" +$language = $cookies->getValue('language', 'en'); + +// 另一种方式获取名为 "language" cookie 的值 +if (($cookie = $cookies->get('language')) !== null) { + $language = $cookie->value; +} + +// 可将 $cookies当作数组使用 +if (isset($cookies['language'])) { + $language = $cookies['language']->value; +} + +// 判断是否存在名为"language" 的 cookie +if ($cookies->has('language')) ... +if (isset($cookies['language'])) ... +``` + + +### 发送 Cookies <a name="sending-cookies"></a> + +You can send cookies to end users using the following code: +可使用如下代码发送cookie到终端用户: + +```php +// 从"response"组件中获取cookie 集合(yii\web\CookieCollection) +$cookies = Yii::$app->response->cookies; + +// 在要发送的响应中添加一个新的cookie +$cookies->add(new \yii\web\Cookie([ + 'name' => 'language', + 'value' => 'zh-CN', +])); + +// 删除一个cookie +$cookies->remove('language'); +// 等同于以下删除代码 +unset($cookies['language']); +``` + +除了上述例子定义的 [[yii\web\Cookie::name|name]] 和 [[yii\web\Cookie::value|value]] 属性 +[[yii\web\Cookie]] 类也定义了其他属性来实现cookie的各种信息,如 +[[yii\web\Cookie::domain|domain]], [[yii\web\Cookie::expire|expire]] +可配置这些属性到cookie中并添加到响应的cookie集合中。 + +> 注意: 为安全起见[[yii\web\Cookie::httpOnly]] 被设置为true,这可减少客户端脚本访问受保护cookie(如果浏览器支持)的风险, +更多详情可阅读 [httpOnly wiki article](https://www.owasp.org/index.php/HttpOnly) for more details. + + +### Cookie验证 <a name="cookie-validation"></a> + +在上两节中,当通过`request` 和 `response` 组件读取和发送cookie时,你会喜欢扩展的cookie验证的保障安全功能,它能 +使cookie不被客户端修改。该功能通过给每个cookie签发一个哈希字符串来告知服务端cookie是否在客户端被修改, +如果被修改,通过`request`组件的[[yii\web\Request::cookies|cookie collection]]cookie集合访问不到该cookie。 + +> 注意: Cookie验证只保护cookie值被修改,如果一个cookie验证失败,仍然可以通过`$_COOKIE`来访问该cookie, +因为这是第三方库对未通过cookie验证自定义的操作方式。 + +Cookie验证默认启用,可以设置[[yii\web\Request::enableCookieValidation]]属性为false来禁用它,尽管如此,我们强烈建议启用它。 + +> 注意: 直接通过`$_COOKIE` 和 `setcookie()` 读取和发送的Cookie不会被验证。 + +当使用cookie验证,必须指定[[yii\web\Request::cookieValidationKey]],它是用来生成s上述的哈希值, +可通过在应用配置中配置`request` 组件。 + +```php +return [ + 'components' => [ + 'request' => [ + 'cookieValidationKey' => 'fill in a secret key here', + ], + ], +]; +``` + +> 补充: [[yii\web\Request::cookieValidationKey|cookieValidationKey]] 对你的应用安全很重要, + 应只被你信任的人知晓,请不要将它放入版本控制中。 diff --git a/docs/guide-zh-CN/structure-assets.md b/docs/guide-zh-CN/structure-assets.md index e3018ee..431d65a 100644 --- a/docs/guide-zh-CN/structure-assets.md +++ b/docs/guide-zh-CN/structure-assets.md @@ -246,7 +246,7 @@ return [ ### 资源部署 <a name="asset-mapping"></a> 有时你想"修复" 多个资源包中资源文件的错误/不兼容,例如包A使用1.11.1版本的`jquery.min.js`, -包B使用2.1.1版本的`jquery.js`,可自定义每个包来解决这个问题,更好的方式是使用*资源部署*特性来不熟不正确的资源为想要的, +包B使用2.1.1版本的`jquery.js`,可自定义每个包来解决这个问题,更好的方式是使用*资源部署*特性来部署不正确的资源为想要的, 为此,配置[[yii\web\AssetManager::assetMap]]属性,如下所示: ```php @@ -347,7 +347,7 @@ Yii使用文件扩展名来表示资源使用哪种扩展语法,默认可以� - [CoffeeScript](http://coffeescript.org/): `.coffee` - [TypeScript](http://www.typescriptlang.org/): `.ts` -Yii依靠安装的预处理公斤来转换资源,例如,为使用[LESS](http://lesscss.org/),应安装`lessc` 预处理命令。 +Yii依靠安装的预处理工具来转换资源,例如,为使用[LESS](http://lesscss.org/),应安装`lessc` 预处理命令。 可配置[[yii\web\AssetManager::converter]]自定义预处理命令和支持的扩展语法,如下所示: diff --git a/docs/guide-zh-CN/structure-models.md b/docs/guide-zh-CN/structure-models.md index eaffbd4..3864670 100644 --- a/docs/guide-zh-CN/structure-models.md +++ b/docs/guide-zh-CN/structure-models.md @@ -276,7 +276,6 @@ public function rules() ## 块赋值 <a name="massive-assignment"></a> -## Massive Assignment <a name="massive-assignment"></a> 块赋值只用一行代码将用户所有输入填充到一个模型,非常方便, 它直接将输入数据对应填充到 [[yii\base\Model::attributes]] 属性。 diff --git a/docs/guide-zh-CN/structure-modules.md b/docs/guide-zh-CN/structure-modules.md index 889108c..6ad4217 100644 --- a/docs/guide-zh-CN/structure-modules.md +++ b/docs/guide-zh-CN/structure-modules.md @@ -30,7 +30,7 @@ forum/ ### 模块类 <a name="module-classes"></a> 每个模块都有一个继承[[yii\base\Module]]的模块类,该类文件直接放在模块的[[yii\base\Module::basePath|base path]]目录下, -并且能被 [自动加载](concept-autoloading.md)。当一个模块被访问,和 [application instances](structure-applications.md) +并且能被 [自动加载](concept-autoloading.md)。当一个模块被访问,和 [应用主体实例](structure-applications.md) 类似会创建该模块类唯一实例,模块实例用来帮模块内代码共享数据和组件。 以下示例一个模块类大致定义: diff --git a/docs/internals/translation-teams.md b/docs/internals/translation-teams.md index 61604b5..cf12849 100644 --- a/docs/internals/translation-teams.md +++ b/docs/internals/translation-teams.md @@ -12,7 +12,6 @@ China - **Paris Qian Sen 东方孤思子,[@qiansen1386](https://github.com/qiansen1386),qiansen1386@gmail.com** - [@AbrahamGreyson 刘阳](https://github.com/AbrahamGreyson) -- [@Aliciamiao](https://github.com/aliciamiao) - [@fmalee](https://github.com/fmalee) - [@funson86 花生](https://github.com/funson86) - [@ivantree 长兴苗木](https://github.com/ivantree)