Issues (46)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Connection.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * @author Donii Sergii <[email protected]>
4
 */
5
6
namespace sonrac\Arango;
7
8
use ArangoDBClient\CollectionHandler as ArangoDBCollectionHandler;
9
use ArangoDBClient\Connection as ArangoDBConnection;
10
use ArangoDBClient\ConnectionOptions as ArangoDBConnectionOptions;
11
use ArangoDBClient\Document;
12
use ArangoDBClient\Exception as ArangoException;
13
use ArangoDBClient\Statement;
14
use ArangoDBClient\UpdatePolicy as ArangoDBUpdatePolicy;
15
use Illuminate\Database\Connection as IlluminateConnection;
16
use sonrac\Arango\Query\Grammars\Grammar;
17
use sonrac\Arango\Query\Processors\Processor;
18
use sonrac\Arango\Query\QueryBuilder;
19
20
/**
21
 * Class Connection.
22
 * Arango connection.
23
 *
24
 * @author  Donii Sergii <[email protected]>
25
 */
26
class Connection extends IlluminateConnection
27
{
28
    /**
29
     * Arango.DB Query Builder
30
     *
31
     * @var
32
     *
33
     * @author Donii Sergii <[email protected]>
34
     */
35
    protected $db;
36
37
    protected $database = '_system';
38
39
    /**
40
     * Arango.DB connection
41
     *
42
     * @var \ArangoDBClient\Connection
43
     *
44
     * @author Donii Sergii <[email protected]>
45
     */
46
    protected $arangoConnection;
47
48
    /**
49
     * Connection constructor.
50 11
     *
51
     * @param array $config Connection options
52 11
     *
53
     * @throws ArangoException
54 11
     *
55
     * @author Donii Sergii <[email protected]>
56 11
     */
57 11
    public function __construct(array $config = [])
58
    {
59
        $this->config = $config;
60
61
        $this->arangoConnection = $this->createConnection();
62
63
        $this->db = new ArangoDBCollectionHandler($this->arangoConnection);
64
65
        // We need to initialize a query grammar and the query post processors
66 1
        // which are both very important parts of the database abstractions
67
        // so we initialize these to their default values while starting.
68 1
        $this->useDefaultQueryGrammar();
69
70
        $this->useDefaultPostProcessor();
71
    }
72
73
    /**
74
     * Send AQL request to ArangoDB and return response with flat array
75
     *
76
     * @param string $query
77
     * @param array $bindings
78 1
     * @param bool $useReadPdo
79
     * @return mixed
80 1
     */
81
    public function select($query, $bindings = [], $useReadPdo = true)
82
    {
83
        return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) {
84
            if ($this->pretending()) {
85
                return [];
86
            }
87
88
            $query = $this->prepareBindingsInQuery($query);
89
            $options = [
90
                'query' => $query,
91
                'count' => true,
92 11
                'batchSize' => 1000,
93
                'sanitize'  => true,
94 11
            ];
95
96 11
            if (count($bindings) > 0) {
97
                $options['bindVars'] = $this->prepareBindings($bindings);
98 11
                var_dump($options['bindVars']);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($options['bindVars']); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
99
            }
100
101
            $statement = new Statement($this->getArangoClient(), $options);
102
103
            $cursor = $statement->execute();
104
105
            $resultingDocuments = [];
106
107
            foreach ($cursor as $key => $document) {
0 ignored issues
show
The expression $cursor of type object<ArangoDBClient\Cursor>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
108 11
                /* @var Document $document */
109
                $resultingDocuments[$key] = $document->getAll();
110 11
            }
111
112 11
            return $resultingDocuments;
113
        });
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function query()
120
    {
121
        return new QueryBuilder(
122 11
            $this, $this->getQueryGrammar(), $this->getPostProcessor()
123
        );
124 11
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129 View Code Duplication
    public function statement($query, $bindings = [])
0 ignored issues
show
This method seems to be duplicated in 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
        return $this->run($query, $bindings, function ($query, $bindings) {
132
            if ($this->pretending()) {
133
                return true;
134 11
            }
135
136 11
            $query = $this->prepareBindingsInQuery($query);
137
            $options = [
138
                'query' => $query,
139
                'count' => true,
140
                'batchSize' => 1000,
141
                'sanitize'  => true,
142
            ];
143
144
            if (count($bindings) > 0) {
145
                $options['bindVars'] = $this->prepareBindings($bindings);
146 11
            }
147
148 11
            $statement = new Statement($this->getArangoClient(), $options);
149
150
            return $statement->execute();
151
        });
152
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157 View Code Duplication
    public function affectingStatement($query, $bindings = [])
0 ignored issues
show
This method seems to be duplicated in 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...
158 11
    {
159
        return $this->run($query, $bindings, function ($query, $bindings) {
160 11
            $query = $this->prepareBindingsInQuery($query);
161
162
            $options = [
163
                'query' => $query,
164
                'count' => true,
165
                'batchSize' => 1000,
166
                'sanitize'  => true,
167
            ];
168
169
            if (count($bindings) > 0) {
170 11
                $options['bindVars'] = $this->prepareBindings($bindings);
171
            }
172 11
173
            $statement = new Statement($this->getArangoClient(), $options);
174
175
            return $statement->execute();
176
        });
177
    }
178
179
    /**
180
     * Get Arango.DB
181
     *
182 11
     * @return mixed
183
     *
184 11
     * @author Donii Sergii <[email protected]>
185
     */
186
    public function getArangoDB()
187
    {
188
        return $this->db;
189
    }
190
191
    /**
192
     * Get Arango.DB client
193
     *
194 11
     * @return \ArangoDBClient\Connection
195
     *
196 11
     * @author Donii Sergii <[email protected]>
197
     */
198
    public function getArangoClient()
199
    {
200
        return $this->arangoConnection;
201
    }
202
203
    /**
204
     * Create new arango.db connection.
205
     *
206 11
     * @param array $config Config
207
     *
208 11
     * @return ArangoDBConnection
209
     *
210
     * @throws \ArangoDBClient\Exception
211
     *
212
     * @author Donii Sergii <[email protected]>
213
     */
214
    public function createConnection(array $config = [])
215
    {
216
        $config = $this->config + $config;
217
218 11
        ArangoException::enableLogging();
219
220 11
        return new ArangoDBConnection($this->getMainConnectionOption() + $config);
221
    }
222
223
    /**
224
     * Get database name.
225
     *
226
     * @return string
227
     *
228
     * @author Donii Sergii <[email protected]>
229
     */
230
    public function getDatabaseName()
231
    {
232
        $this->database = $this->getOption(ArangoDBConnectionOptions::OPTION_DATABASE, $this->database);
233 11
234
        return parent::getDatabaseName();
235 11
    }
236 11
237
    /**
238
     * Get arango.db endpoint.
239 11
     *
240
     * @return string
241
     *
242
     * @author Donii Sergii <[email protected]>
243
     */
244
    public function getEndPoint()
245
    {
246
        return $this->getOption(ArangoDBConnectionOptions::OPTION_ENDPOINT, 'tcp://127.0.0.1:8529');
247
    }
248
249 11
    /**
250
     * Get auth type
251
     *
252
     * @return string
253 11
     *
254
     * @author Donii Sergii <[email protected]>
255 11
     */
256
    public function getAuthType()
257 11
    {
258
        return $this->getOption(ArangoDBConnectionOptions::OPTION_AUTH_TYPE, 'Basic');
259 11
    }
260
261 11
    /**
262
     * Get auth type
263 11
     *
264
     * @return string
265 11
     *
266
     * @author Donii Sergii <[email protected]>
267 11
     */
268
    public function getAuthUser()
269 11
    {
270
        return $this->getOption(ArangoDBConnectionOptions::OPTION_AUTH_USER, 'root');
271 11
    }
272
273
    /**
274
     * Get auth type
275
     *
276
     * @return string
277
     *
278
     * @author Donii Sergii <[email protected]>
279
     */
280
    public function getAuthPassword()
281
    {
282
        return $this->getOption(ArangoDBConnectionOptions::OPTION_AUTH_PASSWD, '');
283
    }
284
285
    /**
286
     * Get connection option
287
     *
288
     * @return string
289
     *
290
     * @author Donii Sergii <[email protected]>
291
     */
292
    public function getConnectionOption()
293
    {
294
        return $this->getOption(ArangoDBConnectionOptions::OPTION_CONNECTION, 'Keep-Alive');
295
    }
296
297
    /**
298
     * Get timeout option
299
     *
300
     * @return int
301
     *
302
     * @author Donii Sergii <[email protected]>
303
     */
304
    public function getTimeout()
305
    {
306
        return $this->getOption(ArangoDBConnectionOptions::OPTION_TIMEOUT, 3);
307
    }
308
309
    /**
310
     * Get reconnect option
311
     *
312
     * @return bool
313
     *
314
     * @author Donii Sergii <[email protected]>
315
     */
316
    public function getReconnect()
317
    {
318
        return $this->getOption(ArangoDBConnectionOptions::OPTION_RECONNECT, true);
319
    }
320
321
    /**
322
     * Get create option
323
     *
324
     * @return mixed
325
     *
326
     * @author Donii Sergii <[email protected]>
327
     */
328
    public function getCreate()
329
    {
330
        return $this->getOption(ArangoDBConnectionOptions::OPTION_CREATE, true);
331
    }
332
333
    /**
334
     * Get update policy option
335
     *
336
     * @return string
337
     *
338
     * @author Donii Sergii <[email protected]>
339
     */
340
    public function getUpdatePolicy()
341
    {
342
        return $this->getOption(ArangoDBConnectionOptions::OPTION_UPDATE_POLICY, ArangoDBUpdatePolicy::LAST);
343
    }
344
345
    public function getDefaultQueryGrammar()
346
    {
347
        return new Grammar();
348
    }
349
350
    public function getDefaultPostProcessor()
351
    {
352
        return new Processor();
353
    }
354
355
    protected function prepareBindingsInQuery($query)
356
    {
357
        $query = explode('?', $query);
358
        $result = '';
359
        foreach ($query as $index => $part) {
360
            if ($index === count($query) - 1) {
361
                $result .= $part;
362
                continue;
363
            }
364
            $result .= $part.'@B'.($index + 1);
365
        }
366
        return $result;
367
    }
368
369
    /**
370
     * Reconnect to the database if a PDO connection is missing.
371
     *
372
     * @throws \ArangoDBClient\Exception
373
     * @return void
374
     */
375
    protected function reconnectIfMissingConnection()
376
    {
377
        if (is_null($this->arangoConnection)) {
378
            $this->arangoConnection = $this->createConnection();
379
        }
380
    }
381
382
    /**
383
     * Get option value
384
     *
385
     * @param string $optionName
386
     * @param mixed  $default
387
     *
388
     * @return mixed
389
     *
390
     * @author Donii Sergii <[email protected]>
391
     */
392
    private function getOption($optionName, $default)
393
    {
394
        if (!isset($this->config[$optionName])) {
395
            $this->config[$optionName] = $default;
396
        }
397
398
        return $this->config[$optionName];
399
    }
400
401
    /**
402
     * Get main connection option
403
     *
404
     * @return array
405
     *
406
     * @author Donii Sergii <[email protected]>
407
     */
408
    private function getMainConnectionOption()
409
    {
410
        return [
411
            // database name
412
            ArangoDBConnectionOptions::OPTION_DATABASE      => $this->getDatabaseName(),
413
            // server endpoint to connect to
414
            ArangoDBConnectionOptions::OPTION_ENDPOINT      => $this->getEndPoint(),
415
            // authorization type to use (currently supported: 'Basic')
416
            ArangoDBConnectionOptions::OPTION_AUTH_TYPE     => $this->getAuthType(),
417
            // user for basic authorization
418
            ArangoDBConnectionOptions::OPTION_AUTH_USER     => $this->getAuthUser(),
419
            // password for basic authorization
420
            ArangoDBConnectionOptions::OPTION_AUTH_PASSWD   => $this->getAuthPassword(),
421
            // connection persistence on server. can use either 'Close' (one-time connections) or 'Keep-Alive' (re-used connections)
422
            ArangoDBConnectionOptions::OPTION_CONNECTION    => $this->getConnectionOption(),
423
            // connect timeout in seconds
424
            ArangoDBConnectionOptions::OPTION_TIMEOUT       => $this->getTimeout(),
425
            // whether or not to reconnect when a keep-alive connection has timed out on server
426
            ArangoDBConnectionOptions::OPTION_RECONNECT     => $this->getReconnect(),
427
            // optionally create new collections when inserting documents
428
            ArangoDBConnectionOptions::OPTION_CREATE        => $this->getCreate(),
429
            // optionally create new collections when inserting documents
430
            ArangoDBConnectionOptions::OPTION_UPDATE_POLICY => $this->getUpdatePolicy(),
431
        ];
432
    }
433
}
434