Completed
Push — master ( 9b3c62...f39199 )
by Patrick
03:29
created

FlipRESTFormat::getFormat()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 12
c 1
b 0
f 0
nc 10
nop 1
dl 0
loc 22
rs 8.6737
1
<?php
2
require_once('class.FlipSession.php');
3
require_once('libs/Slim/Slim/Slim.php');
4
require_once('Autoload.php');
5
\Slim\Slim::registerAutoloader();
6
7
const SUCCESS = 0;
8
const UNRECOGNIZED_METHOD = 1;
9
const INVALID_PARAM = 2;
10
const ALREADY_LOGGED_IN = 3;
11
const INVALID_LOGIN = 4;
12
const ACCESS_DENIED = 5;
13
const INTERNAL_ERROR = 6;
14
15
const UNKNOWN_ERROR = 255;
16
17
class OAuth2Auth extends \Slim\Middleware
18
{
19
    protected $headers = array();
20
21
    public function __construct($headers)
22
    {
23
        $this->headers = $headers;
24
    }
25
26
    private function getUserFromSession()
27
    {
28
        if(FlipSession::isLoggedIn())
29
        {
30
            return FlipSession::getUser();
31
        }
32
        return false;
33
    }
34
35
    /*
36
     * @SuppressWarnings("Superglobals")
37
     * @SuppressWarnings("StaticAccess")
38
     */
39
    private function getUserFromBasicAuth($header)
40
    {
41
        $auth = \AuthProvider::getInstance();
42
        $auth->login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
43
        $user = FlipSession::getUser();
44
        if($user === false)
45
        {
46
            $data = substr($header, 6);
47
            $userpass = explode(':', base64_decode($data));
48
            $user = $auth->getUserByLogin($userpass[0], $userpass[1]);
49
        }
50
        return $user;
51
    }
52
53
    /*
54
     * @SuppressWarnings("StaticAccess")
55
     */
56
    private function getUserFromToken($header)
57
    {
58
        $auth = \AuthProvider::getInstance();
59
        $key = substr($header, 7);
60
        return $auth->getUserByAccessCode($key);
61
    }
62
63
    private function getUserFromHeader($header)
64
    {
65
        if(strncmp($header, 'Basic', 5) == 0)
66
        {
67
            return $this->getUserFromBasicAuth($header);
68
        }
69
        return $this->getUserFromToken($header);
70
    }
71
72
    public function call()
73
    {
74
        // no auth header
75
        if(!isset($this->headers['Authorization']))
76
        {
77
            $this->app->user = $this->getUserFromSession();
78
        }
79
        else
80
        {
81
            $header = $this->headers['Authorization'];
82
            $this->app->user = $this->getUserFromHeader($header);
83
        }
84
85
        if($this->app->user === false)
86
        {
87
            $this->app->getLog()->error("No user found for call");
88
        }
89
90
        // this line is required for the application to proceed
91
        $this->next->call();
92
    }
93
}
94
95
class FlipRESTFormat extends \Slim\Middleware
96
{
97
    private function fix_encoded_element($key, $value, &$array, $prefix = '')
98
    {
99
        if(is_array($value))
100
        {
101
            $array[$key] = implode(';', $value);
102
        }
103
        else if($key === '_id' && is_object($value))
104
        {
105
            $array[$key] = $value->{'$id'};
106
        }
107
        else if(is_object($value))
108
        {
109
            $array[$key] = $this->app->request->getUrl().$this->app->request->getPath().$prefix.'/'.$key;
110
        }
111
        else if(strncmp($value, 'data:', 5) === 0)
112
        {
113
            $array[$key] = $this->app->request->getUrl().$this->app->request->getPath().$prefix.'/'.$key;
114
        }
115
    }
116
117
    private function createCSV(&$array)
118
    {
119
        if(count($array) == 0)
120
        {
121
            return null;
122
        }
123
        ob_start();
124
        $df = fopen("php://output", 'w');
125
        if(is_array($array))
126
        {
127
            $first = reset($array);
128
            $keys = FALSE;
129
            if(is_array($first))
130
            {
131
                $keys = array_keys($first);
132
            }
133
            else if(is_object($first))
134
            {
135
                $keys = array_keys(get_object_vars($first));
136
            }
137
            fputcsv($df, $keys);
138
            foreach($array as $row)
139
            {
140
                if(is_array($row))
141
                {
142
                    $id = $row[$keys[0]];
143
                    foreach($row as $key=>$value)
144
                    {
145
                        $this->fix_encoded_element($key, $value, $row, '/'.$id);
146
                    }
147
                    fputcsv($df, $row);
148
                }
149
                else if(is_object($row))
150
                {
151
                    $keyName = $keys[0];
152
                    $id = $row->$keyName;
153
                    if(is_object($id))
154
                    {
155
                        $id = $id->{'$id'};
156
                    }
157
                    $values = get_object_vars($row);
158
                    foreach($values as $key=>$value)
159
                    {
160
                        $this->fix_encoded_element($key, $value, $values, '/'.$id);
161
                    }
162
                    fputcsv($df, $values);
163
                }
164
            }
165
        }
166
        else
167
        {
168
            $array = get_object_vars($array);
169
            fputcsv($df, array_keys($array));
170
            foreach($array as $key=>$value)
171
            {
172
                $this->fix_encoded_element($key, $value, $array);
173
            }
174
            fputcsv($df, $array);
175
        }
176
        fclose($df);
177
        return ob_get_clean();
178
    }
179
180
    private function createXML(&$array)
181
    {
182
        $obj = new SerializableObject($array);
183
        return $obj->xmlSerialize();
184
    }
185
186
    private function serializeData()
187
    {
188
        $data = json_decode($this->app->response->getBody());
189
        switch($this->app->fmt)
190
        {
191
            case 'data-table':
192
                $this->app->response->headers->set('Content-Type', 'application/json');
193
                return json_encode(array('data'=>$data));
194
            case 'csv':
195
                $this->app->response->headers->set('Content-Type', 'text/csv');
196
                $path = $this->app->request->getPathInfo();
197
                $path = strrchr($path, '/');
198
                $path = substr($path, 1);
199
                $this->app->response->headers->set('Content-Disposition', 'attachment; filename='.$path.'.csv');
200
                return $this->createCSV($data);
201
            case 'xml':
202
                $this->app->response->headers->set('Content-Type', 'application/xml');
203
                return $this->createXML($data);
204
            case 'passthru':
205
                return $this->app->response->getBody();
206
            default:
207
                return 'Unknown fmt '.$this->app->fmt;
208
        }
209
    }
210
211
    private function getFormatFromHeader()
212
    {
213
        $mimeType = $this->app->request->headers->get('Accept');
214
        if(strstr($mimeType, 'odata.streaming=true'))
215
        {
216
            $this->app->response->setStatus(406);
217
            return 'json';
218
        }
219
        switch($mimeType)
220
        {
221
            case 'text/csv':
222
                return 'csv';
223
            case 'text/x-vCard':
224
                return 'vcard';
225
            default:
226
                return 'json';
227
        }
228
    }
229
230
    private function getFormat($params)
231
    {
232
        $fmt = null;
233
        if(isset($params['fmt']))
234
        {
235
            $fmt = $params['fmt'];
236
        }
237
        if($fmt === null && isset($params['$format']))
238
        {
239
            $fmt = $params['$format'];
240
            if(strstr($fmt, 'odata.streaming=true'))
241
            {
242
                $this->app->response->setStatus(406);
243
                return false;
244
            }
245
        }
246
        if($fmt === null)
247
        {
248
            $fmt = $this->getFormatFromHeader();
249
        }
250
        return $fmt;
251
    }
252
253
    public function call()
254
    {
255
        if($this->app->request->isOptions())
256
        {
257
            return;
258
        }
259
        $params = $this->app->request->params();
260
        $fmt = $this->getFormat($params);
261
        if($fmt === false)
262
        {
263
            return;
264
        }
265
266
        $this->app->fmt     = $fmt;
267
        $this->app->odata   = new ODataParams($params);
268
269
        $this->app->isLocal = false;
270
        if($_SERVER['SERVER_ADDR'] === $_SERVER['REMOTE_ADDR'])
271
        {
272
            $this->app->isLocal = true;
273
        }
274
275
        $this->next->call();
276
277
        if($this->app->response->getStatus() == 200 && $this->app->fmt !== 'json')
278
        {
279
            $text = $this->serializeData();
280
            $this->app->response->setBody($text);
281
        }
282
        else if($this->app->response->getStatus() == 200)
283
        {
284
            $this->app->response->headers->set('Content-Type', 'application/json;odata.metadata=none');
285
        }
286
    }
287
}
288
289
class FlipREST extends \Slim\Slim
290
{
291
    public function __construct()
292
    {
293
        parent::__construct();
294
        $this->config('debug', false);
295
        $headers = array();
296
        if(php_sapi_name() !== "cli")
297
        {
298
            $headers = apache_request_headers();
299
        }
300
        $this->add(new OAuth2Auth($headers));
301
        $this->add(new FlipRESTFormat());
302
        $errorHandler = array($this, 'errorHandler');
303
        $this->error($errorHandler);
304
    }
305
306
    public function get_json_body($array = false)
307
    {
308
        return $this->getJsonBody($array);
309
    }
310
311
    public function getJsonBody($array = false)
312
    {
313
        $body = $this->request->getBody();
314
        return json_decode($body, $array);
315
    }
316
317
    public function errorHandler($exception)
318
    {
319
        $error = array(
320
            'code' => $exception->getCode(),
321
            'message' => $exception->getMessage(),
322
            'file' => $exception->getFile(),
323
            'line' => $exception->getLine(),
324
        );
325
        $this->response->headers->set('Content-Type', 'application/json');
326
        error_log(print_r($error, true));
327
        echo json_encode($error);
328
    }
329
}
330
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
331