1: <?php
2: /**
3: * Json-capable CHttpRequest.
4: *
5: * The following capabilities are added to Yii::app()->request:
6: * <ol>
7: * <li>Access to request headers: getRequestHeaders() and getRequestHeader()</li>
8: * <li>Access to request raw payload: getRequestRawBody()</li>
9: * </ol>
10: *
11: * @since 1.0
12: * @package Components
13: * @author Konstantinos Filios <konfilios@gmail.com>
14: */
15: class CBHttpRequest extends CHttpRequest
16: {
17: /**
18: * All headers, ucword()ized.
19: * @var array
20: */
21: private $headers = null;
22:
23: /**
24: * Content type of request's body.
25: * @var string
26: */
27: private $requestContentType = null;
28:
29: /**
30: * Normalized array of accepted content types.
31: * @var array
32: */
33: private $acceptContentTypes = array();
34:
35: /**
36: * Initialize content type of request.
37: */
38: public function init()
39: {
40: parent::init();
41:
42: //
43: // What's the content type of the request body?
44: //
45: $this->requestContentType = !isset($_SERVER['CONTENT_TYPE']) ? ''
46: : $this->_truncateAfterSemicolon(strtolower($_SERVER['CONTENT_TYPE']));
47:
48: //
49: // What content types are accepted?
50: //
51: $acceptContentTypes = $this->getAcceptTypes();
52: if (!empty($acceptContentTypes)) {
53: foreach (explode(',', $acceptContentTypes) as $contentType) {
54: $this->acceptContentTypes[] = $this->_truncateAfterSemicolon($contentType);
55: }
56: }
57: }
58:
59: /**
60: * Keep characters up to first semicolon
61: *
62: * @param string $str
63: * @return string
64: */
65: private function _truncateAfterSemicolon($str)
66: {
67: if (($pos = strpos($str, ';')) !== false) {
68: return substr($str, 0, $pos);
69: } else {
70: return $str;
71: }
72: }
73:
74: /**
75: * Returns array of accepted content types.
76: *
77: * @return string[]
78: */
79: public function getAcceptContentTypes()
80: {
81: return $this->acceptContentTypes;
82: }
83:
84: /**
85: * Returns whether this is a JSON request.
86: *
87: * @return boolean
88: */
89: public function getIsJsonRequest()
90: {
91: return ($this->requestContentType == 'application/json');
92: }
93:
94: /**
95: * Get raw body of HTTP request.
96: *
97: * @return string
98: */
99: public function getRequestRawBody()
100: {
101: return file_get_contents('php://input');
102: }
103:
104: /**
105: * Get all request headers.
106: *
107: * @param string $fieldName
108: * @return string Header value or null if header is not set
109: */
110: public function getRequestHeaders()
111: {
112: if ($this->headers === null) {
113: // Fetch $this->headers for first time. Normalize and store
114: $this->headers = array();
115:
116: // Fetch the real headers first.
117: foreach($_SERVER as $key => $value) {
118: $key = strtolower($key);
119:
120: // Headers are $_SERVER variables starting with HTTP_
121: if (substr($key, 0, 5) != 'http_') {
122: continue;
123: }
124:
125: // 1. Replace _ and - with space so ucwords works properly
126: // 2. Trim spaces created at step 1
127: // 3. Lowercase the first letter
128: // Eg. HTTP_CONTENT_TYPE becomes contentType
129: $header = lcfirst(str_replace(' ', '',
130: ucwords(str_replace(array('_', '-'), ' ', substr($key, 5)))));
131:
132: // Add three common forms of header
133: $this->headers[$header] = $value;
134: }
135:
136: if ((defined('YII_DEBUG') && (constant('YII_DEBUG') === true))
137: && isset($_GET['header']) && is_array($_GET['header'])) {
138: // We're in debug mode and GET headers have been passed. Append them
139: foreach ($_GET['header'] as $header=>$value) {
140: $this->headers[$header] = $value;
141: }
142: }
143: }
144:
145: return $this->headers;
146: }
147:
148: /**
149: * Get request header value.
150: *
151: * @param string $fieldName
152: * @return string Header value or null if header is not set
153: */
154: public function getRequestHeader($fieldName)
155: {
156: $headers = $this->getRequestHeaders();
157:
158: return isset($headers[$fieldName]) ? $headers[$fieldName] : null;
159: }
160: }
161: