Completed
Push — master ( ab9622...fc618d )
by Patrick
05:38
created

FlipREST::getJsonBody()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
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 = array_change_key_case($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 View Code Duplication
            if(is_array($first))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 create_excel(&$array)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
181
    {
182
        require_once dirname(__FILE__) . '/libs/PHPExcel/Classes/PHPExcel.php';
183
        $ssheat = new PHPExcel();
184
        $sheat = $ssheat->setActiveSheetIndex(0);
185
        if(is_array($array))
186
        {
187
            $first = reset($array);
188
            $keys = false;
189 View Code Duplication
            if(is_array($first))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
190
            {
191
                $keys = array_keys($first);
192
            }
193
            else if(is_object($first))
194
            {
195
                $keys = array_keys(get_object_vars($first));
196
            }
197
            $col_count = count($keys);
198
            for($i = 0; $i < $col_count; $i++)
199
            {
200
                $sheat->setCellValueByColumnAndRow($i, 1, $keys[$i]);
201
            }
202
            $row_count = count($array);
203
            for($i = 0; $i < $row_count; $i++)
204
            {
205
                $row = $array[$i];
206
                if(is_object($row))
207
                {
208
                    $row = get_object_vars($row);
209
                }
210
                for($j = 0; $j < $col_count; $j++)
211
                {
212
                    $colName = $keys[$j];
213
                    if(isset($row[$colName]))
214
                    {
215
                        $value = $row[$colName];
216 View Code Duplication
                        if(is_object($value))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
                        {
218
                            switch($colName)
219
                            {
220
                                case '_id':
221
                                    $value = $value->{'$id'};
222
                                default:
223
                                    $value = json_encode($value);
224
                                    break;
225
                            }
226
                        }
227
                        else if(is_array($value))
228
                        {
229
                            $value = implode(',', $value);
230
                        }
231
                        $sheat->setCellValueByColumnAndRow($j, 2+$i, $value);
232
                    }
233
                }
234
            }
235
        }
236
        $writer = PHPExcel_IOFactory::createWriter($ssheat, 'Excel2007');
237
        ob_start();
238
        $writer->save('php://output');
239
        return ob_get_clean();
240
    }
241
242
    private function createXML(&$array)
243
    {
244
        $obj = new SerializableObject($array);
245
        return $obj->xmlSerialize();
246
    }
247
248
    private function serializeData()
249
    {
250
        $data = json_decode($this->app->response->getBody());
251
        switch($this->app->fmt)
252
        {
253
            case 'data-table':
254
                $this->app->response->headers->set('Content-Type', 'application/json');
255
                return json_encode(array('data'=>$data));
256
            case 'csv':
257
                $this->app->response->headers->set('Content-Type', 'text/csv');
258
                $path = $this->app->request->getPathInfo();
259
                $path = strrchr($path, '/');
260
                $path = substr($path, 1);
261
                $this->app->response->headers->set('Content-Disposition', 'attachment; filename='.$path.'.csv');
262
                return $this->createCSV($data);
263
            case 'xml':
264
                $this->app->response->headers->set('Content-Type', 'application/xml');
265
                return $this->createXML($data);
266
            case 'passthru':
267
                return $this->app->response->getBody();
268
            default:
269
                return 'Unknown fmt '.$this->app->fmt;
270
        }
271
    }
272
273
    private function getFormatFromHeader()
274
    {
275
        $mimeType = $this->app->request->headers->get('Accept');
276
        if(strstr($mimeType, 'odata.streaming=true'))
277
        {
278
            $this->app->response->setStatus(406);
279
            return 'json';
280
        }
281
        switch($mimeType)
282
        {
283
            case 'text/csv':
284
                return 'csv';
285
            case 'text/x-vCard':
286
                return 'vcard';
287
            default:
288
                return 'json';
289
        }
290
    }
291
292
    private function getFormat($params)
293
    {
294
        $fmt = null;
295
        if(isset($params['fmt']))
296
        {
297
            $fmt = $params['fmt'];
298
        }
299
        if($fmt === null && isset($params['$format']))
300
        {
301
            $fmt = $params['$format'];
302
            if(strstr($fmt, 'odata.streaming=true'))
303
            {
304
                $this->app->response->setStatus(406);
305
                return false;
306
            }
307
        }
308
        if($fmt === null)
309
        {
310
            $fmt = $this->getFormatFromHeader();
311
        }
312
        return $fmt;
313
    }
314
315
    public function call()
316
    {
317
        if($this->app->request->isOptions())
318
        {
319
            return;
320
        }
321
        $params = $this->app->request->params();
322
        $fmt = $this->getFormat($params);
323
        if($fmt === false)
324
        {
325
            return;
326
        }
327
328
        $this->app->fmt     = $fmt;
329
        $this->app->odata   = new ODataParams($params);
330
331
        $this->app->isLocal = false;
332
        if($_SERVER['SERVER_ADDR'] === $_SERVER['REMOTE_ADDR'])
333
        {
334
            $this->app->isLocal = true;
335
        }
336
337
        $this->next->call();
338
339
        if($this->app->response->getStatus() == 200 && $this->app->fmt !== 'json')
340
        {
341
            $text = $this->serializeData();
342
            $this->app->response->setBody($text);
343
        }
344
        else if($this->app->response->getStatus() == 200)
345
        {
346
            $this->app->response->headers->set('Content-Type', 'application/json;odata.metadata=none');
347
        }
348
    }
349
}
350
351
class FlipREST extends \Slim\Slim
352
{
353
    public function __construct()
354
    {
355
        parent::__construct();
356
        $this->config('debug', false);
357
        $headers = array();
358
        if(php_sapi_name() !== "cli")
359
        {
360
            $headers = apache_request_headers();
361
        }
362
        $this->add(new OAuth2Auth($headers));
363
        $this->add(new FlipRESTFormat());
364
        $errorHandler = array($this, 'errorHandler');
365
        $this->error($errorHandler);
366
    }
367
368
    public function get_json_body($array = false)
369
    {
370
        return $this->getJsonBody($array);
371
    }
372
373
    public function getJsonBody($array = false)
374
    {
375
        $body = $this->request->getBody();
376
        return json_decode($body, $array);
377
    }
378
379
    public function errorHandler($exception)
380
    {
381
        $error = array(
382
            'code' => $exception->getCode(),
383
            'message' => $exception->getMessage(),
384
            'file' => $exception->getFile(),
385
            'line' => $exception->getLine(),
386
        );
387
        $this->response->headers->set('Content-Type', 'application/json');
388
        error_log(print_r($error, true));
389
        echo json_encode($error);
390
    }
391
392
    function not_found_handler()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
393
    {
394
        $accept = $this->request->headers->get('Accept');
395
        if(strcmp($accept, 'application/json') == 0)
396
        {
397
            $error = array(
398
                'code' => 404,
399
                'message' => 'Not Found'
400
            );
401
            $this->response->headers->set('Content-Type', 'application/json');
402
            $this->response->setStatus(404);
403
            echo json_encode($error);
404
        }
405
        else
406
        {
407
            $this->defaultNotFound();
408
        }
409
    }
410
}
411
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
412