Completed
Push — master ( d5a137...e65df8 )
by Iurii
01:27
created

Api::setParamsApi()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 4
nop 1
dl 0
loc 25
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @package API
5
 * @author Iurii Makukh <[email protected]>
6
 * @copyright Copyright (c) 2018, Iurii Makukh
7
 * @license https://www.gnu.org/licenses/gpl.html GNU/GPLv3
8
 */
9
10
namespace gplcart\modules\api\controllers;
11
12
use Exception;
13
use gplcart\core\controllers\frontend\Controller;
14
use gplcart\modules\api\models\Api as ApiModel;
15
use gplcart\modules\api\models\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, gplcart\modules\api\controllers\User.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
16
use RuntimeException;
17
use UnexpectedValueException;
18
19
/**
20
 * Handles incoming requests and outputs data related to API requests
21
 */
22
class Api extends Controller
23
{
24
25
    /**
26
     * Api model class instance
27
     * @var \gplcart\modules\api\models\Api $api
28
     */
29
    protected $api;
30
31
    /**
32
     * User model class instance
33
     * @var \gplcart\modules\api\models\User $apiuser
34
     */
35
    protected $apiuser;
36
37
    /**
38
     * The current API user
39
     * @var array
40
     */
41
    protected $data_user = array();
42
43
    /**
44
     * An array of arguments from URL
45
     * @var array
46
     */
47
    protected $data_params = array();
48
49
    /**
50
     * An array of API data to output
51
     * @var array
52
     */
53
    protected $data_response;
54
55
    /**
56
     * @param User $user
57
     * @param ApiModel $api
58
     */
59
    public function __construct(User $user, ApiModel $api)
60
    {
61
        parent::__construct();
62
63
        $this->api = $api;
64
        $this->apiuser = $user;
65
    }
66
67
    /**
68
     * Page callback
69
     * @param string $arguments
70
     */
71
    public function callbackApi($arguments = null)
72
    {
73
        try {
74
            $this->controlAccessApi();
75
            $this->setUserApi();
76
            $this->outputTokenApi();
77
            $this->setParamsApi($arguments);
78
            $this->setResponseApi();
79
        } catch (Exception $ex) {
80
            $code = $ex->getCode() ?: 403;
81
            $this->response->outputStatus($code);
82
        }
83
84
        $this->response->outputStatus(501);
85
    }
86
87
    /**
88
     * Controls access to API
89
     * @throws RuntimeException
90
     */
91
    protected function controlAccessApi()
92
    {
93
        if (!$this->api->getStatus()) {
94
            throw new RuntimeException('API is disabled', 403);
95
        }
96
    }
97
98
    /**
99
     * Sets the user data
100
     */
101
    protected function setUserApi()
102
    {
103
        $this->data_user = array();
104
105
        $client_id = $this->getPosted('client_id');
106
        $client_secret = $this->getPosted('client_secret');
107
108
        if (isset($client_id) && isset($client_secret)) {
109
110
            $condition = array(
111
                'secret' => $client_secret,
112
                'api_user_id' => $client_id
113
            );
114
115
            $this->data_user = $this->apiuser->get($condition);
116
117
            if (empty($this->data_user['status'])) {
118
                throw new RuntimeException('API user is disabled or not found', 403);
119
            }
120
121
            if (empty($this->data_user['user_status'])) {
122
                throw new RuntimeException('System user is disabled or not found', 403);
123
            }
124
125
            if (!empty($this->data_user['data']['ip']) && !in_array($this->getIp(), $this->data_user['data']['ip'])) {
126
                throw new RuntimeException('IP is not allowed for this API user', 403);
127
            }
128
        }
129
    }
130
131
    /**
132
     * Output JWT token
133
     */
134
    protected function outputTokenApi()
135
    {
136
        if (isset($this->data_user['api_user_id'])) {
137
            $token = $this->api->getToken($this->data_user['api_user_id']);
138
            $this->outputJson($token);
139
        }
140
    }
141
142
    /**
143
     * Output API response
144
     */
145
    protected function setResponseApi()
146
    {
147
        $this->data_response = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $data_response.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
148
149
        $token = $this->getTokenFromHeaderApi();
150
151
        if (isset($token)) {
152
153
            try {
154
                $this->data_user = $this->api->getUserFromToken($token);
155
            } catch (Exception $ex) {
156
                throw new RuntimeException($ex->getMessage(), 401);
157
            }
158
159
            $this->hook->attach('module.api.process', $this->data_params, $this->data_user, $this->data_response, $this);
160
161
            if (!isset($this->data_response)) {
162
                throw new RuntimeException('Not content to output', 204);
163
            }
164
165
            $this->hook->attach('module.api.output', $this->data_params, $this->data_user, $this->data_response, $this);
166
            $this->outputJson($this->data_response);
167
        }
168
    }
169
170
    /**
171
     * Returns a JWT token from the request header
172
     * @return null|string
173
     * @throws UnexpectedValueException
174
     */
175
    protected function getTokenFromHeaderApi()
176
    {
177
        $header = $this->server->header('Authorization');
178
179
        if (!isset($header)) {
180
            return null;
181
        }
182
183
        $parts = explode(' ', $header);
184
185
        if (count($parts) != 2) {
186
            throw new UnexpectedValueException('Invalid authorization header value', 400);
187
        }
188
189
        if (empty($parts[1])) {
190
            throw new UnexpectedValueException('Empty authorization token', 400);
191
        }
192
193
        return $parts[1];
194
    }
195
196
    /**
197
     * Sets an array of parameters to be used as arguments in processors
198
     * @param string $path
199
     * @throws UnexpectedValueException
200
     */
201
    protected function setParamsApi($path)
202
    {
203
        $this->data_params = array(
204
            'version' => null,
205
            'arguments' => array_filter(explode('/', trim($path, '/'))));
206
207
        if (empty($this->data_params['arguments'])) {
208
            throw new UnexpectedValueException('Invalid number of arguments passed', 400);
209
        }
210
211
        $this->data_params['get'] = $this->getQuery(null, array(), 'array');
212
        $this->data_params['post'] = $this->getPosted(null, array(), true, 'array');
213
214
        if (isset($this->data_params['get']['version'])) {
215
216
            $this->data_params['version'] = $this->data_params['get']['version'];
217
            unset($this->data_params['get']['version']);
218
219
            if (version_compare($this->data_params['version'], '0.0.1', '>=') < 0) {
220
                throw new UnexpectedValueException('Version has invalid value', 400);
221
            }
222
        }
223
224
        $this->hook->attach('module.api.parameters', $this->data_params, $this);
225
    }
226
227
}
228