GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 86dce3...98cf71 )
by Nur
02:40
created

Restful   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 283
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 100
dl 0
loc 283
rs 10
c 0
b 0
f 0
wmc 30

4 Methods

Rating   Name   Duplication   Size   Complexity  
A index() 0 3 1
F __construct() 0 72 14
A sendError() 0 17 5
B sendPayload() 0 64 10
1
<?php
2
/**
3
 * This file is part of the O2System PHP Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Reactor\Http\Controllers;
15
16
// ------------------------------------------------------------------------
17
18
use O2System\Cache\Item;
19
use O2System\Reactor\Http\Controller;
20
use O2System\Psr\Http\Header\ResponseFieldInterface;
21
22
/**
23
 * Class Restful
24
 *
25
 * @package O2System\Reactor\Http\Controllers
26
 */
27
class Restful extends Controller
28
{
29
    /**
30
     * Push headers flag
31
     *
32
     * Used for push default headers by controller.
33
     * Set to FALSE if you want to set default headers on the web-server configuration.
34
     *
35
     * APACHE via .htaccess
36
     * IIS via .webconfig
37
     * Nginx via config
38
     *
39
     * @type string
40
     */
41
    protected $pushDefaultHeaders = false;
42
43
    /**
44
     * Access-Control-Allow-Origin
45
     *
46
     * Used for indicates whether a resource can be shared based by
47
     * returning the value of the Origin request header, "*", or "null" in the response.
48
     *
49
     * @type string
50
     */
51
    protected $accessControlAllowOrigin = '*';
52
53
    /**
54
     * Access-Control-Allow-Credentials
55
     *
56
     * Used for indicates whether the response to request can be exposed when the omit credentials flag is unset.
57
     * When part of the response to a preflight request it indicates that the actual request can include user
58
     * credentials.
59
     *
60
     * @type bool
61
     */
62
    protected $accessControlAllowCredentials = true;
63
64
    /**
65
     * Access-Control-Allow-Methods
66
     *
67
     * Used for indicates, as part of the response to a preflight request,
68
     * which methods can be used during the actual request.
69
     *
70
     * @type array
71
     */
72
    protected $accessControlAllowMethods = [
73
        'GET', // common request
74
        'POST', // used for create, update request
75
        //'PUT', // used for upload files request
76
        //'DELETE', // used for delete request
77
        'OPTIONS', // used for preflight request
78
    ];
79
80
    /**
81
     * Access-Control-Allow-Headers
82
     *
83
     * Used for indicates, as part of the response to a preflight request,
84
     * which header field names can be used during the actual request.
85
     *
86
     * @type int
87
     */
88
    protected $accessControlAllowHeaders = [
89
        'Origin',
90
        'Access-Control-Request-Method',
91
        'Access-Control-Request-Headers',
92
        'X-Api-Authenticate', // API-Authenticate: api_key="xxx", api_secret="xxx", api_signature="xxx"
93
        'X-Api-Token',
94
        'X-Web-Token', // X-Web-Token: xxx (json-web-token)
95
        'X-Csrf-Token',
96
        'X-Xss-Token',
97
        'X-Request-ID',
98
        'X-Requested-With',
99
        'X-Requested-Result',
100
    ];
101
102
    /**
103
     * Access-Control-Allow-Headers
104
     *
105
     * Used for indicates, as part of the response to a preflight request,
106
     * which header field names can be used during the actual request.
107
     *
108
     * @type array
109
     */
110
    protected $accessControlAllowContentTypes = [
111
        'text/html',
112
        'application/json',
113
        'application/xml',
114
    ];
115
116
    /**
117
     * Access-Control-Max-Age
118
     *
119
     * Used for indicates how long the results of a preflight request can be cached in a preflight result cache
120
     *
121
     * @type int
122
     */
123
    protected $accessControlMaxAge = 86400;
124
125
    // ------------------------------------------------------------------------
126
127
    protected $ajaxOnly = false;
128
129
    /**
130
     * Restful::__construct
131
     */
132
    public function __construct()
133
    {
134
        if (o2system()->hasService('presenter')) {
0 ignored issues
show
Bug introduced by
The method hasService() does not exist on O2System\Reactor. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
        if (o2system()->/** @scrutinizer ignore-call */ hasService('presenter')) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
135
            presenter()->theme->set(false);
0 ignored issues
show
Bug introduced by
The function presenter was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

135
            /** @scrutinizer ignore-call */ 
136
            presenter()->theme->set(false);
Loading history...
136
        }
137
138
        if (is_ajax()) {
139
            output()->setContentType('application/json');
0 ignored issues
show
Bug introduced by
The method setContentType() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

139
            output()->/** @scrutinizer ignore-call */ setContentType('application/json');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
140
        } elseif ($this->ajaxOnly === false) {
141
            output()->setContentType('application/json');
142
        } else {
143
            output()->setContentType('text/html');
144
        }
145
146
        if ($contentType = input()->server('HTTP_X_REQUESTED_CONTENT_TYPE')) {
147
            if (in_array($contentType, $this->accessControlAllowContentTypes)) {
148
                output()->setContentType($contentType);
149
            }
150
        }
151
152
        if ($this->pushDefaultHeaders) {
153
154
            $origin = input()->server('HTTP_ORIGIN');
155
156
            /**
157
             * Prepare for preflight modern browser request
158
             *
159
             * Since some server cannot use 'Access-Control-Allow-Origin: *'
160
             * the Access-Control-Allow-Origin will be defined based on requested origin
161
             */
162
            if ($this->accessControlAllowOrigin === '*') {
163
                output()->addHeader(ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_ORIGIN, $origin);
0 ignored issues
show
Bug introduced by
The method addHeader() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

163
                output()->/** @scrutinizer ignore-call */ addHeader(ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_ORIGIN, $origin);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
164
            }
165
166
            // Set response access control allowed credentials
167
            if ($this->accessControlAllowCredentials === false) {
168
                output()->addHeader(ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_CREDENTIALS, 'false');
169
            }
170
171
            // Set response access control allowed methods header
172
            if (count($this->accessControlAllowMethods)) {
173
                output()->addHeader(
174
                    ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_METHODS,
175
                    implode(', ', $this->accessControlAllowMethods)
176
                );
177
            }
178
179
            // Set response access control allowed headers header
180
            if (count($this->accessControlAllowHeaders)) {
0 ignored issues
show
Bug introduced by
$this->accessControlAllowHeaders of type integer is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

180
            if (count(/** @scrutinizer ignore-type */ $this->accessControlAllowHeaders)) {
Loading history...
181
                output()->addHeader(
182
                    ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_HEADERS,
183
                    implode(', ', $this->accessControlAllowHeaders)
0 ignored issues
show
Bug introduced by
$this->accessControlAllowHeaders of type integer is incompatible with the type array expected by parameter $pieces of implode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

183
                    implode(', ', /** @scrutinizer ignore-type */ $this->accessControlAllowHeaders)
Loading history...
184
                );
185
            }
186
187
            // Set response access control allowed content types header
188
            if (count($this->accessControlAllowContentTypes)) {
189
                output()->addHeader(
190
                    ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_CONTENT_TYPES,
191
                    implode(', ', $this->accessControlAllowContentTypes)
192
                );
193
            }
194
195
            // Set response access control max age header
196
            if ($this->accessControlMaxAge > 0) {
197
                output()->addHeader(ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_MAX_AGE,
198
                    $this->accessControlMaxAge);
199
            }
200
        }
201
202
        if (input()->server('REQUEST_METHOD') === 'OPTIONS') {
203
            exit(EXIT_SUCCESS);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
204
        }
205
    }
206
207
    // ------------------------------------------------------------------------
208
209
    /**
210
     * Restful::index
211
     */
212
    public function index()
213
    {
214
        output()->sendError(204);
215
    }
216
217
    // ------------------------------------------------------------------------
218
219
    public function sendError($code, $message = null)
220
    {
221
        if ($this->ajaxOnly === false) {
222
            output()->setContentType('application/json');
223
        }
224
225
        if (is_array($code)) {
226
            if (is_numeric(key($code))) {
227
                $message = reset($code);
228
                $code = key($code);
229
            } elseif (isset($code[ 'code' ])) {
230
                $code = $code[ 'code' ];
231
                $message = $code[ 'message' ];
232
            }
233
        }
234
235
        output()->sendError($code, $message);
236
    }
237
238
    // ------------------------------------------------------------------------
239
240
    /**
241
     * Restful::sendPayload
242
     *
243
     * @param mixed $data        The payload data to-be send.
244
     * @param bool  $longPooling Long pooling flag mode.
245
     */
246
    public function sendPayload($data, $longPooling = false)
247
    {
248
        if ($longPooling === false) {
249
            if ($this->ajaxOnly) {
250
                if (is_ajax()) {
251
                    output()->send($data);
0 ignored issues
show
Bug introduced by
The method send() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

251
                    output()->/** @scrutinizer ignore-call */ send($data);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
252
                } else {
253
                    output()->sendError(403);
254
                }
255
            } else {
256
                output()->send($data);
257
            }
258
        } elseif (is_ajax()) {
259
            /**
260
             * Server-side file.
261
             * This file is an infinitive loop. Seriously.
262
             * It gets the cache created timestamp, checks if this is larger than the timestamp of the
263
             * AJAX-submitted timestamp (time of last ajax request), and if so, it sends back a JSON with the data from
264
             * data.txt (and a timestamp). If not, it waits for one seconds and then start the next while step.
265
             *
266
             * Note: This returns a JSON, containing the content of data.txt and the timestamp of the last data.txt change.
267
             * This timestamp is used by the client's JavaScript for the next request, so THIS server-side script here only
268
             * serves new content after the last file change. Sounds weird, but try it out, you'll get into it really fast!
269
             */
270
271
            // set php runtime to unlimited
272
            set_time_limit(0);
273
274
            $longPoolingCacheKey = 'long-pooling-' . session()->get('id');
0 ignored issues
show
Bug introduced by
Are you sure session()->get('id') of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

274
            $longPoolingCacheKey = 'long-pooling-' . /** @scrutinizer ignore-type */ session()->get('id');
Loading history...
275
            $longPoolingCacheData = null;
276
277
            if ( ! cache()->hasItem($longPoolingCacheKey)) {
278
                cache()->save(new Item($longPoolingCacheKey, $data));
279
            }
280
281
            // main loop
282
            while (true) {
283
                // if ajax request has send a timestamp, then $lastCallTimestamp = timestamp, else $last_call = null
284
                $lastCallTimestamp = (int)input()->getPost('last_call_timestamp');
0 ignored issues
show
Bug introduced by
The method getPost() does not exist on O2System\Kernel\Cli\Input. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

284
                $lastCallTimestamp = (int)input()->/** @scrutinizer ignore-call */ getPost('last_call_timestamp');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
285
286
                // PHP caches file data, like requesting the size of a file, by default. clearstatcache() clears that cache
287
                clearstatcache();
288
289
                if (cache()->hasItem($longPoolingCacheKey)) {
290
                    $longPoolingCacheData = cache()->getItem($longPoolingCacheKey);
291
                }
292
293
                // get timestamp of when file has been changed the last time
294
                $longPoolingCacheMetadata = $longPoolingCacheData->getMetadata();
295
296
                // if no timestamp delivered via ajax or data.txt has been changed SINCE last ajax timestamp
297
                if ($lastCallTimestamp == null || $longPoolingCacheMetadata[ 'ctime' ] > $lastCallTimestamp) {
298
                    output()->send([
299
                        'timestamp' => $longPoolingCacheMetadata,
300
                        'data'      => $data,
301
                    ]);
302
                } else {
303
                    // wait for 1 sec (not very sexy as this blocks the PHP/Apache process, but that's how it goes)
304
                    sleep(1);
305
                    continue;
306
                }
307
            }
308
        } else {
309
            output()->sendError(501);
310
        }
311
    }
312
}