Passed
Push — master ( c5754d...1955b9 )
by Darío
07:59 queued 02:30
created

Tools::getIdentity()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 3
nop 0
dl 0
loc 28
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
namespace Connections\Controller;
4
5
use Auth\Model\User as UserModel;
6
use Connections\Model\Authentication;
7
use Workarea\Model\ConnectionType;
8
use Workarea\Model\ConnectionTypeField;
9
use Workarea\Model\Identifiers;
10
use Workarea\Model\UserConnection;
11
use Workarea\Model\UserConnectionsTable;
12
use Workarea\Model\UserConnectionDetails;
13
use Drone\Db\TableGateway\EntityAdapter;
14
use Drone\Db\TableGateway\TableGateway;
15
use Drone\Dom\Element\Form;
16
use Drone\Mvc\AbstractionController;
17
use Drone\Network\Http;
18
use Drone\Validator\FormValidator;
19
use Utils\Model\Entity as EntityMd;
20
use Drone\Error\Errno;
21
22
class Tools extends AbstractionController
23
{
24
    use \Drone\Error\ErrorTrait;
25
26
    /**
27
     * @var integer
28
     */
29
    private $identity;
0 ignored issues
show
introduced by
The private property $identity is not used, and could be removed.
Loading history...
30
31
    /**
32
     * @var EntityAdapter
33
     */
34
    private $usersEntity;
35
36
    /**
37
     * @var EntityAdapter
38
     */
39
    private $identifiersEntity;
40
41
    /**
42
     * @var EntityAdapter
43
     */
44
    private $connectionTypesEntity;
45
46
    /**
47
     * @var EntityAdapter
48
     */
49
    private $connectionFieldsEntity;
50
51
    /**
52
     * @var EntityAdapter
53
     */
54
    private $userConnectionEntity;
55
56
    /**
57
     * @var EntityAdapter
58
     */
59
    private $userConnectionDetailsEntity;
60
61
    /**
62
     * @return integer
63
     */
64
    private function getIdentity()
0 ignored issues
show
Unused Code introduced by
The method getIdentity() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
65
    {
66
        $config = include 'module/Auth/config/user.config.php';
67
        $method = $config["authentication"]["method"];
68
        $key    = $config["authentication"]["key"];
69
70
        switch ($method)
71
        {
72
            case '_COOKIE':
73
74
                $user = $this->getUsersEntity()->select([
75
                    "USERNAME" => $_COOKIE[$key]
76
                ]);
77
78
                break;
79
80
            case '_SESSION':
81
82
                $user = $this->getUsersEntity()->select([
83
                    "USERNAME" => $_SESSION[$key]
84
                ]);
85
86
                break;
87
        }
88
89
        $user = array_shift($user);
90
91
        return $user->USER_ID;
92
    }
93
94
    /**
95
     * @return UsersEntity
0 ignored issues
show
Bug introduced by
The type Connections\Controller\UsersEntity was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
96
     */
97
    private function getUsersEntity()
98
    {
99
        if (!is_null($this->usersEntity))
100
            return $this->usersEntity;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->usersEntity returns the type Drone\Db\TableGateway\EntityAdapter which is incompatible with the documented return type Connections\Controller\UsersEntity.
Loading history...
101
102
        $this->usersEntity = new EntityAdapter(new TableGateway(new UserModel()));
103
104
        return $this->usersEntity;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->usersEntity returns the type Drone\Db\TableGateway\EntityAdapter which is incompatible with the documented return type Connections\Controller\UsersEntity.
Loading history...
105
    }
106
107
    /**
108
     * @return UsersEntity
109
     */
110
    private function getIdentifiersEntity()
111
    {
112
        if (!is_null($this->identifiersEntity))
113
            return $this->identifiersEntity;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->identifiersEntity returns the type Drone\Db\TableGateway\EntityAdapter which is incompatible with the documented return type Connections\Controller\UsersEntity.
Loading history...
114
115
        $this->identifiersEntity = new EntityAdapter(new TableGateway(new Identifiers()));
116
117
        return $this->identifiersEntity;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->identifiersEntity returns the type Drone\Db\TableGateway\EntityAdapter which is incompatible with the documented return type Connections\Controller\UsersEntity.
Loading history...
118
    }
119
120
    /**
121
     * @return EntityAdapter
122
     */
123
    private function getConnectionTypesEntity()
0 ignored issues
show
Unused Code introduced by
The method getConnectionTypesEntity() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
124
    {
125
        if (!is_null($this->connectionTypesEntity))
126
            return $this->connectionTypesEntity;
127
128
        $this->connectionTypesEntity = new EntityAdapter(new TableGateway(new ConnectionType()));
129
130
        return $this->connectionTypesEntity;
131
    }
132
133
    /**
134
     * @return EntityAdapter
135
     */
136
    private function getConnectionFieldsEntity()
0 ignored issues
show
Unused Code introduced by
The method getConnectionFieldsEntity() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
137
    {
138
        if (!is_null($this->connectionFieldsEntity))
139
            return $this->connectionFieldsEntity;
140
141
        $this->connectionFieldsEntity = new EntityAdapter(new TableGateway(new ConnectionTypeField()));
142
143
        return $this->connectionFieldsEntity;
144
    }
145
146
    /**
147
     * @return EntityAdapter
148
     */
149
    private function getUserConnectionEntity()
150
    {
151
        if (!is_null($this->userConnectionEntity))
152
            return $this->userConnectionEntity;
153
154
        $this->userConnectionEntity = new EntityAdapter(new UserConnectionsTable(new UserConnection()));
155
156
        return $this->userConnectionEntity;
157
    }
158
159
    /**
160
     * @return EntityAdapter
161
     */
162
    private function getUserConnectionDetailsEntity()
163
    {
164
        if (!is_null($this->userConnectionDetailsEntity))
165
            return $this->userConnectionDetailsEntity;
166
167
        $this->userConnectionDetailsEntity = new EntityAdapter(new TableGateway(new UserConnectionDetails()));
168
169
        return $this->userConnectionDetailsEntity;
170
    }
171
172
    /**
173
     * Tests a connection
174
     *
175
     * @return array
176
     */
177
    public function testConnection()
178
    {
179
        clearstatcache();
180
        session_write_close();
181
182
        # data to send
183
        $data = [];
184
185
        # environment settings
186
        $post = $this->getPost();           # catch $_POST
187
        $this->setTerminal(true);           # set terminal
188
189
        # TRY-CATCH-BLOCK
190
        try {
191
192
            # STANDARD VALIDATIONS [check method]
193
            if (!$this->isPost())
194
            {
195
                $http = new Http();
196
                $http->writeStatus($http::HTTP_METHOD_NOT_ALLOWED);
197
198
                die('Error ' . $http::HTTP_METHOD_NOT_ALLOWED .' (' . $http->getStatusText($http::HTTP_METHOD_NOT_ALLOWED) . ')!!');
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...
199
            }
200
201
            $idenfiers = $this->getIdentifiersEntity()->select([]);
202
            $dbconfig = [];
203
204
            if (array_key_exists('conn_id', $post))
205
            {
206
                # STANDARD VALIDATIONS [check needed arguments]
207
                $needles = ['conn_id'];
208
209
                array_walk($needles, function(&$item) use ($post) {
210
                    if (!array_key_exists($item, $post))
211
                    {
212
                        $http = new Http();
213
                        $http->writeStatus($http::HTTP_BAD_REQUEST);
214
215
                        die('Error ' . $http::HTTP_BAD_REQUEST .' (' . $http->getStatusText($http::HTTP_BAD_REQUEST) . ')!!');
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...
216
                    }
217
                });
218
219
                $id = $post["conn_id"];
220
221
                $details = $this->getUserConnectionDetailsEntity()->select([
222
                    "USER_CONN_ID" => $id
223
                ]);
224
225
                foreach ($details as $field)
226
                {
227
                    foreach ($idenfiers as $identifier)
228
                    {
229
                        if ($field->CONN_IDENTI_ID == $identifier->CONN_IDENTI_ID)
230
                            $dbconfig[$identifier->CONN_IDENTI_NAME] = $field->FIELD_VALUE;
231
                    }
232
                }
233
            }
234
            else
235
            {
236
                # STANDARD VALIDATIONS [check needed arguments]
237
                $needles = ['type', 'aliasname'];
238
239
                array_walk($needles, function(&$item) use ($post) {
240
                    if (!array_key_exists($item, $post))
241
                    {
242
                        $http = new Http();
243
                        $http->writeStatus($http::HTTP_BAD_REQUEST);
244
245
                        die('Error ' . $http::HTTP_BAD_REQUEST .' (' . $http->getStatusText($http::HTTP_BAD_REQUEST) . ')!!');
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...
246
                    }
247
                });
248
249
                $components = [
250
                    "attributes" => [
251
                        "type" => [
252
                            "required"  => true,
253
                        ],
254
                        "aliasname" => [
255
                            "required"  => true,
256
                        ]
257
                    ],
258
                ];
259
260
                $options = [
261
                    "type" => [
262
                        "label" => "Value of connection parameter"
263
                    ],
264
                    "aliasname" => [
265
                        "label" => "Type of connection parameter"
266
                    ]
267
                ];
268
269
                $form = new Form($components);
270
                $form->fill($post);
271
272
                $validator = new FormValidator($form, $options);
273
                $validator->validate();
274
275
                $data["validator"] = $validator;
276
277
                # STANDARD VALIDATIONS [check argument constraints]
278
                if (!$validator->isValid())
279
                {
280
                    $data["messages"] = $validator->getMessages();
281
                    throw new \Drone\Exception\Exception("Form validation errors");
282
                }
283
284
                $id = 0;
285
286
                foreach ($post['field'][$post["type"]] as $field_number => $field_value)
287
                {
288
                    foreach ($idenfiers as $identifier)
289
                    {
290
                        if ($field_number == $identifier->CONN_IDENTI_ID)
291
                            $dbconfig[$identifier->CONN_IDENTI_NAME] = $field_value;
292
                    }
293
                }
294
            }
295
296
            try
297
            {
298
                $entity = new EntityMd([]);
299
                $entity->setConnectionIdentifier("CONN" . $id);
300
301
                $driverAdapter = new \Drone\Db\Driver\DriverAdapter($dbconfig, false);
302
                $driverAdapter->getDb()->connect();
303
            }
304
            catch (\Exception $e)
305
            {
306
                # SUCCESS-MESSAGE
307
                $data["process"] = "error";
308
                $data["message"] = $e->getMessage();
309
310
                return $data;
311
            }
312
313
            # SUCCESS-MESSAGE
314
            $data["process"] = "success";
315
        }
316
        catch (\Drone\Exception\Exception $e)
317
        {
318
            # ERROR-MESSAGE
319
            $data["process"] = "warning";
320
            $data["message"] = $e->getMessage();
321
        }
322
        catch (\Exception $e)
323
        {
324
            $file = str_replace('\\', '', __CLASS__);
325
            $storage = new \Drone\Exception\Storage("cache/$file.json");
326
327
            # stores the error code
328
            if (($errorCode = $storage->store($e)) === false)
0 ignored issues
show
introduced by
The condition $errorCode = $storage->store($e) === false is always true.
Loading history...
329
            {
330
                $errors = $storage->getErrors();
331
332
                # if error storing is not possible, handle it (internal app error)
333
                $this->handleErrors($errors, __METHOD__);
334
            }
335
336
            $data["code"]    = $errorCode;
337
            $data["message"] = $e->getMessage();
338
339
            $config = include 'config/application.config.php';
340
            $data["dev_mode"] = $config["environment"]["dev_mode"];
341
342
            # redirect view
343
            $this->setMethod('error');
344
345
            return $data;
346
        }
347
348
        return $data;
349
    }
350
351
    /**
352
     * Puts a worksheet
353
     *
354
     * @return array
355
     */
356
    public function worksheet()
357
    {
358
        # STANDARD VALIDATIONS [check method]
359
        if (!$this->isPost())
360
        {
361
            $http = new Http();
362
            $http->writeStatus($http::HTTP_METHOD_NOT_ALLOWED);
363
364
            die('Error ' . $http::HTTP_METHOD_NOT_ALLOWED .' (' . $http->getStatusText($http::HTTP_METHOD_NOT_ALLOWED) . ')!!');
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...
365
        }
366
367
        # data to send
368
        $data = [];
369
370
        $this->setTerminal(true);           # set terminal
371
        $post = $this->getPost();           # catch $_POST
372
373
        $data["id"]   = $post["id"];
374
        $data["conn"] = $post["conn"];
375
376
        return $data;
377
    }
378
379
    /**
380
     * Executes a statement
381
     *
382
     * @return array
383
     */
384
    public function execute()
385
    {
386
        clearstatcache();
387
        session_write_close();
388
389
        # data to send
390
        $data = [];
391
392
        # environment settings
393
        $post = $this->getPost();           # catch $_POST
394
        $this->setTerminal(true);           # set terminal
395
396
        # TRY-CATCH-BLOCK
397
        try {
398
399
            # STANDARD VALIDATIONS [check method]
400
            if (!$this->isPost())
401
            {
402
                $http = new Http();
403
                $http->writeStatus($http::HTTP_METHOD_NOT_ALLOWED);
404
405
                die('Error ' . $http::HTTP_METHOD_NOT_ALLOWED .' (' . $http->getStatusText($http::HTTP_METHOD_NOT_ALLOWED) . ')!!');
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...
406
            }
407
408
            # STANDARD VALIDATIONS [check needed arguments]
409
            $needles = ['conn', 'worksheet'];
410
411
            array_walk($needles, function(&$item) use ($post) {
412
                if (!array_key_exists($item, $post))
413
                {
414
                    $http = new Http();
415
                    $http->writeStatus($http::HTTP_BAD_REQUEST);
416
417
                    die('Error ' . $http::HTTP_BAD_REQUEST .' (' . $http->getStatusText($http::HTTP_BAD_REQUEST) . ')!!');
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...
418
                }
419
            });
420
421
            $data["worksheet"] = $post["worksheet"];
422
423
            $id = $post["conn"];
424
            $data["conn"] = $id;
425
426
            $connection = $this->getUserConnectionEntity()->select([
427
                "USER_CONN_ID" => $id
428
            ]);
429
430
            if (!count($connection))
431
                throw new \Exception("The Connection does not exists");
432
433
            $connection = array_shift($connection);
434
435
            if ($connection->STATE == 'I')
436
                throw new \Drone\Exception\Exception("This connection was deleted", 300);
437
438
            $details = $this->getUserConnectionDetailsEntity()->select([
439
                "USER_CONN_ID" => $id
440
            ]);
441
442
            $idenfiers = $this->getIdentifiersEntity()->select([]);
443
444
            $dbconfig = [];
445
446
            foreach ($details as $field)
447
            {
448
                foreach ($idenfiers as $identifier)
449
                {
450
                    if ($field->CONN_IDENTI_ID == $identifier->CONN_IDENTI_ID)
451
                        $dbconfig[$identifier->CONN_IDENTI_NAME] = $field->FIELD_VALUE;
452
                }
453
            }
454
455
            /* identifies if sql is base64 encoded */
456
            if (array_key_exists('base64', $post))
457
            {
458
                if ((bool) $post["base64"])
459
                    $post["sql"] = base64_decode($post["sql"]);
460
            }
461
462
            $data["sql"] = base64_encode($post["sql"]);
463
464
            $sql_text = $post["sql"];
465
466
            /*
467
             * SQL parsing
468
             */
469
            $sql_text = trim($sql_text);
470
471
            if (empty($sql_text))
472
                throw new \Drone\Exception\Exception("Empty statement");
473
474
            $pos = strpos($sql_text, ';');
475
476
            if ($pos !== false)
477
            {
478
                $end_stament = strstr($sql_text, ';');
479
480
                if ($end_stament == ';')
481
                    $sql_text = strstr($sql_text, ';', true);
482
            }
483
484
             # clean comments and other characters
485
486
            // (/**/)
487
            $clean_code = preg_replace('/(\s)*\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\//', '', $sql_text);
488
489
            // (--)
490
            $clean_code = preg_replace('/(\s)*--.*\n/', "", $clean_code);
491
492
            # clean other characters starting senteces
493
            $clean_code = preg_replace('/^[\n\t\s]*/', "", $clean_code);
494
495
            # indicates if SQL is a selection statement
496
            $isSelectStm = $data["selectStm"] = (preg_match('/^SELECT/i', $clean_code));
497
498
            # indicates if SQL is a show statement
499
            $isShowStm   = $data["showStm"]   = (preg_match('/^SHOW/i', $clean_code));
500
501
            # detect selection
502
            if ($isSelectStm || $isShowStm)
503
            {
504
                $step = 10;
505
506
                $row_start = 0;
507
                $row_end   = $step;
508
509
                if (array_key_exists('row_start', $post) && array_key_exists('row_end', $post))
510
                {
511
                    $components = [
512
                        "attributes" => [
513
                            "row_start" => [
514
                                "required" => true,
515
                                "type"     => "number",
516
                                "min"      => 0
517
                            ],
518
                            "row_end" => [
519
                                "required" => true,
520
                                "type"     => "number",
521
                                "min"      => 0
522
                            ],
523
                        ],
524
                    ];
525
526
                    $options = [
527
                        "row_start" => [
528
                            "label" => "Start row",
529
                        ],
530
                        "row_end" => [
531
                            "label" => "End row",
532
                        ],
533
                    ];
534
535
                    $form = new Form($components);
536
                    $form->fill($post);
537
538
                    $validator = new FormValidator($form, $options);
539
                    $validator->validate();
540
541
                    # STANDARD VALIDATIONS [check argument constraints]
542
                    if (!$validator->isValid())
543
                    {
544
                        $http = new Http();
545
                        $http->writeStatus($http::HTTP_BAD_REQUEST);
546
547
                        die('Error ' . $http::HTTP_BAD_REQUEST .' (' . $http->getStatusText($http::HTTP_BAD_REQUEST) . ')!!');
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...
548
                    }
549
550
                    $row_start = $post["row_start"] + $step;
551
                    $row_end   = $post["row_end"] + $step;
552
                }
553
554
                switch (strtolower($dbconfig["driver"]))
555
                {
556
                    case 'mysqli':
557
558
                        # show statement cannot be a subquery
559
                        if (!$isShowStm)
560
                            $sql_text = "SELECT (@ROW_NUM:=@ROW_NUM + 1) AS ROW_NUM, V.* FROM (
561
                                            " . $sql_text . "
562
                                        ) V LIMIT $row_start, $step";
563
                        break;
564
565
                    case 'oci8':
566
567
                        $start = $row_start + 1;
568
569
                        $sql_text = "SELECT * FROM (
570
                                        SELECT ROWNUM ROW_NUM, V.* FROM (" . $sql_text . ") V
571
                                    ) VV WHERE VV.ROW_NUM BETWEEN $start AND $row_end";
572
                        break;
573
574
                    case 'sqlsrv':
575
576
                        $start = $row_start + 1;
577
578
                        $sql_text = "SELECT VV.*
579
                                    FROM (
580
                                        SELECT ROW_NUMBER() OVER(ORDER BY (
581
                                            SELECT TOP 1 NAME
582
                                            FROM SYS.DM_EXEC_DESCRIBE_FIRST_RESULT_SET('$sql_text', NULL, 0))
583
                                        ) AS ROW_NUM, V.*
584
                                        FROM ( $sql_text ) V
585
                                    ) VV
586
                                    WHERE VV.ROW_NUM BETWEEN $start AND $row_end";
587
                        break;
588
589
                    default:
590
                        # code...
591
                        break;
592
                }
593
594
                $data["row_start"] = $row_start;
595
                $data["row_end"]   = $row_end;
596
            }
597
598
            try {
599
600
                $connError = false;
601
602
                $entity = new EntityMd([]);
603
                $entity->setConnectionIdentifier("CONN" . $id);
604
605
                $driverAdapter = new \Drone\Db\Driver\DriverAdapter($dbconfig, false);
606
607
                # start time to compute execution
608
                $startTime = microtime(true);
609
610
                $driverAdapter->getDb()->connect();
611
612
                $auth = $driverAdapter;
613
614
                $data["results"] = $auth->getDb()->execute($sql_text);
615
            }
616
            # encapsulate real connection error!
617
            catch (\Drone\Db\Driver\Exception\ConnectionException $e)
618
            {
619
                $connError = true;
620
621
                $file = str_replace('\\', '', __CLASS__);
622
                $storage = new \Drone\Exception\Storage("cache/$file.json");
623
624
                if (($errorCode = $storage->store($e)) === false)
0 ignored issues
show
introduced by
The condition $errorCode = $storage->store($e) === false is always true.
Loading history...
625
                {
626
                    $errors = $storage->getErrors();
627
                    $this->handleErrors($errors, __METHOD__);
628
                }
629
630
                $data["code"]    = $errorCode;
631
                $data["message"] = "Could not connect to database!";
632
633
                # to identify development mode
634
                $config = include 'config/application.config.php';
635
                $data["dev_mode"] = $config["environment"]["dev_mode"];
636
637
                # redirect view
638
                $this->setMethod('error');
639
            }
640
            catch (\Exception $e)
641
            {
642
                # SUCCESS-MESSAGE
643
                $data["process"] = "error";
644
                $data["message"] = $e->getMessage();
645
646
                return $data;
647
            }
648
649
            # end time to compute execution
650
            $endTime = microtime(true);
651
            $elapsed_time = $endTime - $startTime;
652
653
            $data["time"] = round($elapsed_time, 4);
654
655
            if (!$connError)
656
            {
657
                $data["num_rows"]      = $auth->getDb()->getNumRows();
658
                $data["num_fields"]    = $auth->getDb()->getNumFields();
659
                $data["rows_affected"] = $auth->getDb()->getRowsAffected();
660
661
                # cumulative results
662
                if ($isSelectStm && array_key_exists('num_rows', $post) && array_key_exists('time', $post))
663
                {
664
                    $data["num_rows"] += $post["num_rows"];
665
                    $data["time"]     += $post["time"];
666
                }
667
668
                $data["data"] = [];
669
670
                # redirect view
671
                if ($isSelectStm || $isShowStm)
672
                {
673
                    $rows = $auth->getDb()->getArrayResult();
674
675
                    $k = 0;
676
677
                    # columns with errors in a select statement
678
                    $column_errors = [];
679
680
                    # data parsing
681
                    foreach ($rows as $key => $row)
682
                    {
683
                        $k++;
684
685
                        $data["data"][$key] = [];
686
687
                        if ($isShowStm)
688
                        {
689
                            $data["data"][$key]["ROW_NUM"] = $k;
690
                            $data["data"][$key][0] = $k;
691
                        }
692
693
                        foreach ($row as $column => $value)
694
                        {
695
                            if ($isShowStm)
696
                                $column++;
697
698
                            if (gettype($value) == 'object')
699
                            {
700
                                if  (get_class($value) == 'OCI-Lob')
701
                                {
702
                                    if (($val = @$value->load()) === false)
703
                                    {
704
                                        $val = null;   # only for default, this value is not used
705
                                        $column_errors[] = $column;
706
                                    }
707
708
                                    $data["data"][$key][$column] = $val;
709
                                }
710
                                else
711
                                    $data["data"][$key][$column] = $value;
712
                            }
713
                            else {
714
                                $data["data"][$key][$column] = $value;
715
                            }
716
                        }
717
                    }
718
719
                    $data["column_errors"] = $column_errors;
720
721
                    if ($row_start > 1)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $row_start does not seem to be defined for all execution paths leading up to this point.
Loading history...
722
                        $this->setMethod('nextResults');
723
                }
724
725
                if (array_key_exists('id', $post))
726
                    $data["id"] = $post["id"];
727
728
                # SUCCESS-MESSAGE
729
                $data["process"] = "success";
730
            }
731
        }
732
        catch (\Drone\Exception\Exception $e)
733
        {
734
            # ERROR-MESSAGE
735
            $data["process"] = "warning";
736
            $data["message"] = $e->getMessage();
737
        }
738
        catch (\Exception $e)
739
        {
740
            $file = str_replace('\\', '', __CLASS__);
741
            $storage = new \Drone\Exception\Storage("cache/$file.json");
742
743
            # stores the error code
744
            if (($errorCode = $storage->store($e)) === false)
0 ignored issues
show
introduced by
The condition $errorCode = $storage->store($e) === false is always true.
Loading history...
745
            {
746
                $errors = $storage->getErrors();
747
748
                # if error storing is not possible, handle it (internal app error)
749
                $this->handleErrors($errors, __METHOD__);
750
            }
751
752
            $data["code"]    = $errorCode;
753
            $data["message"] = $e->getMessage();
754
755
            $config = include 'config/application.config.php';
756
            $data["dev_mode"] = $config["environment"]["dev_mode"];
757
758
            # redirect view
759
            $this->setMethod('error');
760
761
            return $data;
762
        }
763
764
        return $data;
765
    }
766
767
    /**
768
     * Exports a statement
769
     *
770
     * @return array
771
     */
772
    public function export()
773
    {
774
        clearstatcache();
775
        session_write_close();
776
777
        # data to send
778
        $data = [];
779
780
        # environment settings
781
        $post = $this->getPost();           # catch $_POST
782
        $this->setTerminal(true);           # set terminal
783
784
        # TRY-CATCH-BLOCK
785
        try {
786
787
            # STANDARD VALIDATIONS [check method]
788
            if (!$this->isPost())
789
            {
790
                $http = new Http();
791
                $http->writeStatus($http::HTTP_METHOD_NOT_ALLOWED);
792
793
                die('Error ' . $http::HTTP_METHOD_NOT_ALLOWED .' (' . $http->getStatusText($http::HTTP_METHOD_NOT_ALLOWED) . ')!!');
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...
794
            }
795
796
            # STANDARD VALIDATIONS [check needed arguments]
797
            $needles = ['conn', 'sql', 'type', 'filename'];
798
799
            array_walk($needles, function(&$item) use ($post) {
800
                if (!array_key_exists($item, $post))
801
                {
802
                    $http = new Http();
803
                    $http->writeStatus($http::HTTP_BAD_REQUEST);
804
805
                    die('Error ' . $http::HTTP_BAD_REQUEST .' (' . $http->getStatusText($http::HTTP_BAD_REQUEST) . ')!!');
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...
806
                }
807
            });
808
809
            $components = [
810
                "attributes" => [
811
                    "conn" => [
812
                        "required"  => true,
813
                        "type"      => "number"
814
                    ],
815
                    "sql" => [
816
                        "required"  => true,
817
                        "type"      => "text"
818
                    ],
819
                    "type" => [
820
                        "required"  => true,
821
                        "type"      => "text"
822
                    ],
823
                    "filename" => [
824
                        "required"  => true,
825
                        "type"      => "text"
826
                    ]
827
                ],
828
            ];
829
830
            $options = [
831
                "conn" => [
832
                    "label" => "Connection",
833
                ],
834
                "sql" => [
835
                    "label" => "SQL",
836
                    "validators" => [
837
                        "Alnum"  => ["allowWhiteSpace" => false]
838
                    ]
839
                ],
840
                "type" => [
841
                    "label" => "Type",
842
                    "validators" => [
843
                        "InArray" => ["haystack" => ['excel', 'csv']]
844
                    ]
845
                ],
846
                "filename" => [
847
                    "label" => "Filename"
848
                ]
849
            ];
850
851
            $form = new Form($components);
852
            $form->fill($post);
853
854
            $validator = new FormValidator($form, $options);
855
            $validator->validate();
856
857
            $data["validator"] = $validator;
858
859
            # form validation
860
            if (!$validator->isValid())
861
            {
862
                $data["messages"] = $validator->getMessages();
863
                throw new \Drone\Exception\Exception("Form validation errors", 300);
864
            }
865
866
            $id = $post["conn"];
867
868
            $connection = $this->getUserConnectionEntity()->select([
869
                "USER_CONN_ID" => $id
870
            ]);
871
872
            if (!count($connection))
873
                throw new \Exception("The Connection does not exists");
874
875
            $connection = array_shift($connection);
876
877
            if ($connection->STATE == 'I')
878
                throw new \Drone\Exception\Exception("This connection was deleted", 300);
879
880
            $details = $this->getUserConnectionDetailsEntity()->select([
881
                "USER_CONN_ID" => $id
882
            ]);
883
884
            $idenfiers = $this->getIdentifiersEntity()->select([]);
885
886
            $dbconfig = [];
887
888
            foreach ($details as $field)
889
            {
890
                foreach ($idenfiers as $identifier)
891
                {
892
                    if ($field->CONN_IDENTI_ID == $identifier->CONN_IDENTI_ID)
893
                        $dbconfig[$identifier->CONN_IDENTI_NAME] = $field->FIELD_VALUE;
894
                }
895
            }
896
897
            /* identifies if sql is base64 encoded */
898
            if (array_key_exists('base64', $post))
899
            {
900
                if ((bool) $post["base64"])
901
                    $post["sql"] = base64_decode($post["sql"]);
902
            }
903
904
            $data["sql"] = base64_encode($post["sql"]);
905
906
            $sql_text = $post["sql"];
907
908
            /*
909
             * SQL parsing
910
             */
911
            $sql_text = trim($sql_text);
912
913
            if (empty($sql_text))
914
                throw new \Drone\Exception\Exception("Empty statement");
915
916
            $pos = strpos($sql_text, ';');
917
918
            if ($pos !== false)
919
            {
920
                $end_stament = strstr($sql_text, ';');
921
922
                if ($end_stament == ';')
923
                    $sql_text = strstr($sql_text, ';', true);
924
            }
925
926
             # clean comments and other characters
927
928
            // (/**/)
929
            $clean_code = preg_replace('/(\s)*\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\//', '', $sql_text);
930
931
            // (--)
932
            $clean_code = preg_replace('/(\s)*--.*\n/', "", $clean_code);
933
934
            # clean other characters starting senteces
935
            $clean_code = preg_replace('/^[\n\t\s]*/', "", $clean_code);
936
937
            # indicates if SQL is a selection statement
938
            $isSelectStm = $data["selectStm"] = (preg_match('/^SELECT/i', $clean_code));
939
940
            # indicates if SQL is a show statement
941
            $isShowStm   = $data["showStm"]   = (preg_match('/^SHOW/i', $clean_code));
942
943
            # detect selection
944
            if (!$isSelectStm && !$isShowStm)
945
                throw new \Exception("You can't export a non-selection statement!");
946
947
            try {
948
949
                $connError = false;
950
951
                $entity = new EntityMd([]);
952
                $entity->setConnectionIdentifier("CONN" . $id);
953
954
                $driverAdapter = new \Drone\Db\Driver\DriverAdapter($dbconfig, false);
955
956
                # start time to compute execution
957
                $startTime = microtime(true);
958
959
                $driverAdapter->getDb()->connect();
960
961
                $auth = $driverAdapter;
962
963
                $data["results"] = $auth->getDb()->execute($sql_text);
964
            }
965
            # encapsulate real connection error!
966
            catch (\Drone\Db\Driver\Exception\ConnectionException $e)
967
            {
968
                $connError = true;
969
970
                $file = str_replace('\\', '', __CLASS__);
971
                $storage = new \Drone\Exception\Storage("cache/$file.json");
972
973
                # stores the error code
974
                if (($errorCode = $storage->store($e)) === false)
0 ignored issues
show
introduced by
The condition $errorCode = $storage->store($e) === false is always true.
Loading history...
975
                {
976
                    $errors = $storage->getErrors();
977
978
                    # if error storing is not possible, handle it (internal app error)
979
                    $this->handleErrors($errors, __METHOD__);
980
                }
981
982
                $data["code"]    = $errorCode;
983
                $data["message"] = "Could not connect to database";
984
985
                # to identify development mode
986
                $config = include 'config/application.config.php';
987
                $data["dev_mode"] = $config["environment"]["dev_mode"];
988
989
                # redirect view
990
                $this->setMethod('error');
991
            }
992
            catch (\Exception $e)
993
            {
994
                # SUCCESS-MESSAGE
995
                $data["process"] = "error";
996
                $data["message"] = $e->getMessage();
997
998
                return $data;
999
            }
1000
1001
            # end time to compute execution
1002
            $endTime = microtime(true);
1003
            $elapsed_time = $endTime - $startTime;
1004
1005
            $data["time"] = round($elapsed_time, 4);
1006
1007
            if (!$connError)
1008
            {
1009
                $data["num_rows"]      = $auth->getDb()->getNumRows();
1010
                $data["num_fields"]    = $auth->getDb()->getNumFields();
1011
                $data["rows_affected"] = $auth->getDb()->getRowsAffected();
1012
1013
                $rows = $auth->getDb()->getArrayResult();
1014
1015
                # columns with errors in a select statement
1016
                $column_errors = [];
1017
1018
                switch ($post["type"])
1019
                {
1020
                    case 'excel':
1021
                        $ext = '.xls';
1022
                        break;
1023
                    case 'csv':
1024
                        $ext = '.csv';
1025
                        break;
1026
                    default:
1027
                        $ext = '.txt';
1028
                        break;
1029
                }
1030
1031
                $filename = $post["filename"] . $ext;
1032
1033
                $file_hd = @fopen("cache/" . $filename, "w+");
1034
1035
                if (!$file_hd)
0 ignored issues
show
introduced by
$file_hd is of type resource|false, thus it always evaluated to false.
Loading history...
1036
                {
1037
                    $this->error(Errno::FILE_PERMISSION_DENIED, "cache/" . $filename);
1038
                    throw new \Exception("The file could not be created!");
1039
                }
1040
1041
                $contents = "";
1042
1043
                $data["data"] = [];
1044
1045
                switch ($post["type"])
1046
                {
1047
                    case 'excel':
1048
1049
                        $table = "<html xmlns:v='urn:schemas-microsoft-com:vml' \r\n\txmlns:o='urn:schemas-microsoft-com:office:office'\r\n";
1050
                        $table .= "\txmlns:x='urn:schemas-microsoft-com:office:excel'\r\n";
1051
                        $table .= "\txmlns='http://www.w3.org/TR/REC-html40'>\r\n";
1052
1053
                        $table .= "<head>\r\n";
1054
                        $table .= "\t<meta name='Excel Workbook Frameset'><meta http-equiv='Content-Type' content='text/html; charset='utf-8'>\r\n";
1055
                        $table .= "</head>\r\n\r\n";
1056
1057
                        $table .= "<body>\r\n<table border=1>\r\n";
1058
1059
                        $column_names = [];
1060
1061
                        foreach ($rows[0] as $column_name => $row)
1062
                        {
1063
                            if (!is_numeric($column_name))
1064
                                $column_names[] = $column_name;
1065
                        }
1066
1067
                        $table .= "\t<thead>\r\n\t\t<tr>\r\n";
1068
1069
                        foreach ($column_names as $column_name)
1070
                        {
1071
                            $table .= "\t\t\t<th>$column_name</th>\r\n";
1072
                        }
1073
1074
                        $table .= "\t\t</tr>\r\n\t</thead>\r\n\t<tbody>";
1075
1076
                        # data parsing
1077
                        foreach ($rows as $key => $row)
1078
                        {
1079
                            $data["data"][$key] = [];
1080
1081
                            foreach ($row as $column => $value)
1082
                            {
1083
                                if ($isShowStm)
1084
                                    $column++;
1085
1086
                                if (gettype($value) == 'object')
1087
                                {
1088
                                    if  (get_class($value) == 'OCI-Lob')
1089
                                    {
1090
                                        if (($val = @$value->load()) === false)
1091
                                        {
1092
                                            $val = null;   # only for default, this value is not used
1093
                                            $column_errors[] = $column;
1094
                                        }
1095
1096
                                        $data["data"][$key][$column] = $val;
1097
                                    }
1098
                                    else
1099
                                        $data["data"][$key][$column] = $value;
1100
                                }
1101
                                else {
1102
                                    $data["data"][$key][$column] = $value;
1103
                                }
1104
                            }
1105
1106
                        }
1107
1108
                        foreach ($data["data"] as $row)
1109
                        {
1110
                            $table .= "\t\t<tr>\r\n";
1111
1112
                            foreach ($column_names as $column_name)
1113
                            {
1114
                                $table .= "\t\t\t<td>". $row[$column_name] ."</td>\r\n";
1115
                            }
1116
1117
                            $table .= "\t\t</tr>\r\n";
1118
                        }
1119
1120
                        $table .= "\t</tbody>\r\n</table>\r\n</body>\r\n</html>";
1121
                        $contents = $table;
1122
1123
                        break;
1124
1125
                    case 'csv':
1126
1127
                        $text = "";
1128
1129
                        $column_names = [];
1130
1131
                        foreach ($rows[0] as $column_name => $row)
1132
                        {
1133
                            if (!is_numeric($column_name))
1134
                                $column_names[] = $column_name;
1135
                        }
1136
1137
                        foreach ($column_names as $column_name)
1138
                        {
1139
                            $text .= "$column_name;";
1140
                        }
1141
1142
                        $text .= "\r\n";
1143
1144
                        # data parsing
1145
                        foreach ($rows as $key => $row)
1146
                        {
1147
                            $data["data"][$key] = [];
1148
1149
                            foreach ($row as $column => $value)
1150
                            {
1151
                                if ($isShowStm)
1152
                                    $column++;
1153
1154
                                if (gettype($value) == 'object')
1155
                                {
1156
                                    if  (get_class($value) == 'OCI-Lob')
1157
                                    {
1158
                                        if (($val = @$value->load()) === false)
1159
                                        {
1160
                                            $val = null;   # only for default, this value is not used
1161
                                            $column_errors[] = $column;
1162
                                        }
1163
1164
                                        $data["data"][$key][$column] = $val;
1165
                                    }
1166
                                    else
1167
                                        $data["data"][$key][$column] = $value;
1168
                                }
1169
                                else {
1170
                                    $data["data"][$key][$column] = $value;
1171
                                }
1172
                            }
1173
                        }
1174
1175
                        foreach ($data["data"] as $row)
1176
                        {
1177
                            foreach ($column_names as $column_name)
1178
                            {
1179
                                $text .= $row[$column_name] . ";";
1180
                            }
1181
1182
                            $text .= "\r\n";
1183
                        }
1184
1185
                        $contents = $text;
1186
1187
                        break;
1188
1189
                    default:
1190
                        # code...
1191
                        break;
1192
                }
1193
1194
                if (!@fwrite($file_hd, $contents))
1195
                {
1196
                    $this->error(Errno::FILE_PERMISSION_DENIED, "cache/" . $filename);
1197
                    throw new \Exception("The file could not be generated!");
1198
                }
1199
1200
                @fclose($file_hd);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

1200
                /** @scrutinizer ignore-unhandled */ @fclose($file_hd);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1201
1202
                $data["column_errors"] = $column_errors;
1203
1204
                $data["filename"] = $filename;
1205
1206
                if (array_key_exists('id', $post))
1207
                    $data["id"] = $post["id"];
1208
1209
                # SUCCESS-MESSAGE
1210
                $data["process"] = "success";
1211
            }
1212
        }
1213
        catch (\Drone\Exception\Exception $e)
1214
        {
1215
            # ERROR-MESSAGE
1216
            $data["process"] = "warning";
1217
            $data["message"] = $e->getMessage();
1218
        }
1219
        catch (\Exception $e)
1220
        {
1221
            $file = str_replace('\\', '', __CLASS__);
1222
            $storage = new \Drone\Exception\Storage("cache/$file.json");
1223
1224
            # stores the error code
1225
            if (($errorCode = $storage->store($e)) === false)
0 ignored issues
show
introduced by
The condition $errorCode = $storage->store($e) === false is always true.
Loading history...
1226
            {
1227
                $errors = $storage->getErrors();
1228
1229
                # if error storing is not possible, handle it (internal app error)
1230
                $this->handleErrors($errors, __METHOD__);
1231
            }
1232
1233
            # errors retrived by the use of ErrorTrait
1234
            if (count($this->getErrors()))
1235
                $this->handleErrors($this->getErrors(), __METHOD__);
1236
1237
            $data["code"]    = $errorCode;
1238
            $data["message"] = $e->getMessage();
1239
1240
            $config = include 'config/application.config.php';
1241
            $data["dev_mode"] = $config["environment"]["dev_mode"];
1242
1243
            # redirect view
1244
            $this->setMethod('error');
1245
1246
            return $data;
1247
        }
1248
1249
        return $data;
1250
    }
1251
1252
    private function handleErrors(Array $errors, $method)
1253
    {
1254
        if (count($errors))
1255
        {
1256
            $errorInformation = "";
1257
1258
            foreach ($errors as $errno => $error)
1259
            {
1260
                $errorInformation .=
1261
                    "<strong style='color: #a94442'>".
1262
                        $method
1263
                            . "</strong>: <span style='color: #e24f4c'>{$error}</span> \n<br />";
1264
            }
1265
1266
            $hd = @fopen('cache/errors.txt', "a");
1267
1268
            if (!$hd || !@fwrite($hd, $errorInformation))
0 ignored issues
show
introduced by
$hd is of type resource|false, thus it always evaluated to false.
Loading history...
1269
            {
1270
                # error storing are not mandatory!
1271
            }
1272
            else
1273
                @fclose($hd);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for fclose(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

1273
                /** @scrutinizer ignore-unhandled */ @fclose($hd);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1274
1275
            $config = include 'config/application.config.php';
1276
            $dev = $config["environment"]["dev_mode"];
1277
1278
            if ($dev)
1279
                echo $errorInformation;
1280
        }
1281
    }
1282
}