Completed
Push — master ( 1f9686...114e61 )
by Stefano
03:01
created

Response::status()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
dl 0
loc 3
rs 10
c 2
b 1
f 1
cc 2
eloc 2
nc 1
nop 2
1
<?php
2
3
/**
4
 * Response
5
 *
6
 * Handles the HTTP Response for the current execution.
7
 *
8
 * @package core
9
 * @author [email protected]
10
 * @copyright Caffeina srl - 2015 - http://caffeina.it
11
 */
12
13
class Response {
0 ignored issues
show
Coding Style introduced by
The property $force_dl is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
14
    use Module;
15
16
    const TYPE_JSON               = 'application/json',
17
          TYPE_HTML               = 'text/html',
18
          TYPE_TEXT               = 'text/plain',
19
          TYPE_CSS                = 'text/css',
20
          TYPE_XML                = 'text/xml',
21
          TYPE_SVG                = 'image/svg+xml',
22
          TYPE_JS                 = 'application/javascript',
23
          TYPE_BIN                = 'application/octet-stream';
24
25
    protected static $payload     = [],
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
26
                     $status      = 200,
27
                     $charset     = "utf-8",
28
                     $headers     = ['Content-Type' => ['text/html; charset=utf-8']],
29
                     $buffer      = null,
30
                     $force_dl    = false,
31
                     $link        = null,
32
                     $sent        = false;
33
34
35
    public static function charset($charset){
36
        static::$charset = $charset;
37
    }
38
39
    public static function type($mime){
40
        static::header('Content-Type',$mime . (static::$charset ? '; charset='.static::$charset : ''));
41
    }
42
43
    /**
44
     * Force download of Response body
45
     * @param  string/bool $filename Pass a falsy value to disable download or pass a filename for exporting content
0 ignored issues
show
Documentation introduced by
The doc-type string/bool could not be parsed: Unknown type name "string/bool" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
46
     * @return [type]        [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
47
     */
48
    public static function download($filename){
49
        static::$force_dl = $filename;
50
    }
51
52
    /**
53
     * Start capturing output
54
     */
55
    public static function start(){
56
        static::$buffer = ob_start();
57
    }
58
59
    /**
60
     * Enable CORS HTTP headers.
61
     */
62
    public static function enableCORS(){
63
64
        // Allow from any origin
65
        if ($origin = filter_input(INPUT_SERVER,'HTTP_ORIGIN')) {
66
          static::header('Access-Control-Allow-Origin', $origin);
67
          static::header('Access-Control-Allow-Credentials', 'true');
68
          static::header('Access-Control-Max-Age', 86400);
69
        }
70
71
        // Access-Control headers are received during OPTIONS requests
72
        if (filter_input(INPUT_SERVER,'REQUEST_METHOD') == 'OPTIONS') {
73
            static::clean();
74
75
            if (filter_input(INPUT_SERVER,'HTTP_ACCESS_CONTROL_REQUEST_METHOD')) {
76
              static::header('Access-Control-Allow-Methods',
77
                'GET, POST, PUT, DELETE, OPTIONS, HEAD, CONNECT, PATCH, TRACE');
78
            }
79
            if ($req_h = filter_input(INPUT_SERVER,'HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) {
80
              static::header('Access-Control-Allow-Headers',$req_h);
81
            }
82
83
            static::send();
84
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method enableCORS() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
85
        }
86
    }
87
88
    public static function sent() {
89
        return static::$sent;
90
    }
91
92
    /**
93
     * Finish the output buffer capturing.
94
     * @return string The captured buffer
95
     */
96
    public static function end(){
97
        if (static::$buffer){
98
            static::$payload[] = ob_get_contents();
99
            ob_end_clean();
100
            static::$buffer = null;
101
            return end(static::$payload);
102
        }
103
    }
104
105
    /**
106
     * Check if an response output buffering is active.
107
     * @return boolean
108
     */
109
    public static function isBuffering(){
110
        return static::$buffer;
111
    }
112
113
    /**
114
     * Clear the response body
115
     */
116
    public static function clean(){
117
        static::$payload = [];
118
    }
119
120
    /**
121
     * Append a JSON object to the buffer.
122
     * @param  mixed $payload Data to append to the response buffer
123
     */
124
    public static function json($payload){
125
        static::type(static::TYPE_JSON);
126
        static::$payload[] = json_encode($payload, Options::get('core.response.json_flags',JSON_NUMERIC_CHECK));
127
    }
128
129
    /**
130
     * Append a text to the buffer.
131
     * @param  mixed $payload Text to append to the response buffer
132
     */
133
    public static function text(){
134
        static::type(static::TYPE_TEXT);
135
        static::$payload[] = implode('',func_get_args());
136
    }
137
138
    /**
139
     * Append an XML string to the buffer.
140
     * @param  mixed $payload Data to append to the response buffer
141
     */
142
    public static function xml(){
143
        static::type(static::TYPE_XML);
144
        static::$payload[] = implode('',func_get_args());
145
    }
146
147
    /**
148
     * Append a SVG string to the buffer.
149
     * @param  mixed $payload Data to append to the response buffer
150
     */
151
    public static function svg(){
152
        static::type(static::TYPE_SVG);
153
        static::$payload[] = implode('',func_get_args());
154
    }
155
156
    /**
157
     * Append an HTML string to the buffer.
158
     * @param  mixed $payload Data to append to the response buffer
159
     */
160
    public static function html(){
161
        static::type(static::TYPE_HTML);
162
        static::$payload[] = implode('',func_get_args());
163
    }
164
165
    /**
166
     * Append data to the buffer.
167
     *  Rules :
168
     *  - Callables will be called and their results added (recursive)
169
     *  - Views will be rendered
170
     *  - Objects, arrays and bools will be JSON encoded
171
     *  - Strings and numbers will be appendend to the response
172
     *
173
     * @param  mixed $payload Data to append to the response buffer
174
     */
175
    public static function add(){
176
      foreach(func_get_args() as $data){
177
        switch (true) {
178
          case is_callable($data) :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
179
            return static::add($data());
180
          case is_a($data, 'View') :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
181
            return static::$payload[] = "$data";
182
          case is_object($data) || is_array($data) || is_bool($data):
183
            return static::json($data);
184
          default:
185
            return static::$payload[] = $data;
186
        }
187
      }
188
    }
189
190
    public static function status($code,$message=''){
191
        static::header('Status',$message?:$code,$code);
192
    }
193
194
    public static function header($name,$value,$code=null){
195
        static::$headers[$name] = [$value,$code];
196
    }
197
198
    public static function error($code=500,$message='Application Error'){
199
        Event::trigger('core.response.error',$code,$message);
200
        static::status($code,$message);
201
    }
202
203
    public static function body($setBody=null){
204
      if ($setBody) static::$payload = [$setBody];
205
      return Filter::with('core.response.body',
206
                is_array(static::$payload) ? implode('',static::$payload) : static::$payload
207
             );
208
    }
209
210
    public static function headers($setHeaders=null){
211
       if ($setHeaders) static::$headers = $setHeaders;
212
       return static::$headers;
213
    }
214
215
    /**
216
     * Save response as an object, for serialization or cache storage
217
     *
218
     * @method save
219
     *
220
     * @return array Headers and body of the response
221
     */
222
    public static function save(){
223
        return [
224
          'head' => static::$headers,
225
          'body' => static::body(),
226
        ];
227
    }
228
229
    /**
230
     * Load response from a saved state
231
     *
232
     * @method load
233
     *
234
     * @param  array $data head/body saved state
235
     */
236
    public static function load($data){
237
      $data = (object)$data;
238
      if (isset($data->head)) static::headers($data->head);
239
      if (isset($data->body)) static::body($data->body);
240
    }
241
242
    public static function send($force = false){
243
      if (!static::$sent || $force) {
244
        static::$sent = true;
245
        Event::trigger('core.response.send');
246
        if (false === headers_sent()) foreach (static::$headers as $name => $value_code) {
247
248
            if (is_array($value_code)) {
249
                list($value, $code) = (count($value_code) > 1) ? $value_code : [current($value_code), 200];
250
            } else {
251
                $value = $value_code;
252
                $code  = null;
253
            }
254
255
            if ($value == 'Status'){
256
              if (function_exists('http_response_code')){
257
                http_response_code($code);
258
              } else {
259
                header("Status: $code", true, $code);
260
              }
261
262
            } else {
263
                $code
264
                ? header("$name: $value", true, $code)
265
                : header("$name: $value", true);
266
            }
267
        }
268
        if (static::$force_dl) header('Content-Disposition: attachment; filename="'.static::$force_dl.'"');
269
        echo static::body();
270
      }
271
    }
272
273
}
274