Issues (16)

Security Analysis    no request data  

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/Twig/DoctrineExtension.php (5 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
/*
4
 * This file is part of the Doctrine Bundle
5
 *
6
 * The code was originally distributed inside the Symfony framework.
7
 *
8
 * (c) Fabien Potencier <[email protected]>
9
 * (c) Doctrine Project, Benjamin Eberlei <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Saxulum\SaxulumWebProfiler\Twig;
16
17
/**
18
 * This class contains the needed functions in order to do the query highlighting
19
 *
20
 * @author Florin Patan <[email protected]>
21
 * @author Christophe Coevoet <[email protected]>
22
 */
23
class DoctrineExtension extends \Twig_Extension
24
{
25
    /**
26
     * Number of maximum characters that one single line can hold in the interface
27
     *
28
     * @var int
29
     */
30
    private $maxCharWidth = 100;
31
32
    /**
33
     * Define our functions
34
     *
35
     * @return array
36
     */
37
    public function getFilters()
38
    {
39
        return array(
40
            new \Twig_SimpleFilter('doctrine_minify_query', array($this, 'minifyQuery')),
41
            new \Twig_SimpleFilter('doctrine_pretty_query', 'SqlFormatter::format'),
42
            new \Twig_SimpleFilter('doctrine_replace_query_parameters', array($this, 'replaceQueryParameters')),
43
        );
44
    }
45
46
    /**
47
     * Get the possible combinations of elements from the given array
48
     *
49
     * @param array   $elements
50
     * @param integer $combinationsLevel
51
     *
52
     * @return array
53
     */
54
    private function getPossibleCombinations($elements, $combinationsLevel)
55
    {
56
        $baseCount = count($elements);
57
        $result = array();
58
59
        if ($combinationsLevel == 1) {
60
            foreach ($elements as $element) {
61
                $result[] = array($element);
62
            }
63
64
            return $result;
65
        }
66
67
        $nextLevelElements = $this->getPossibleCombinations($elements, $combinationsLevel - 1);
68
69
        foreach ($nextLevelElements as $nextLevelElement) {
70
            $lastElement = $nextLevelElement[$combinationsLevel - 2];
71
            $found = false;
72
73
            foreach ($elements as $key => $element) {
74
                if ($element == $lastElement) {
75
                    $found = true;
76
                    continue;
77
                }
78
79
                if ($found == true && $key < $baseCount) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
80
                    $tmp = $nextLevelElement;
81
                    $newCombination = array_slice($tmp, 0);
82
                    $newCombination[] = $element;
83
                    $result[] = array_slice($newCombination, 0);
84
                }
85
            }
86
        }
87
88
        return $result;
89
    }
90
91
    /**
92
     * Shrink the values of parameters from a combination
93
     *
94
     * @param array $parameters
95
     * @param array $combination
96
     *
97
     * @return string
98
     */
99
    private function shrinkParameters($parameters, $combination)
100
    {
101
        array_shift($parameters);
102
        $result = '';
103
104
        $maxLength = $this->maxCharWidth;
105
        $maxLength -= count($parameters) * 5;
106
        $maxLength = $maxLength / count($parameters);
107
108
        foreach ($parameters as $key => $value) {
109
            $isLarger = false;
110
111
            if (strlen($value) > $maxLength) {
112
                $value = wordwrap($value, $maxLength, "\n", true);
113
                $value = explode("\n", $value);
114
                $value = $value[0];
115
116
                $isLarger = true;
117
            }
118
            $value = self::escapeFunction($value);
119
120
            if (!is_numeric($value)) {
121
                $value = substr($value, 1, -1);
122
            }
123
124
            if ($isLarger) {
125
                $value .= ' [...]';
126
            }
127
128
            $result .= ' ' . $combination[$key] . ' ' . $value;
129
        }
130
131
        return trim($result);
132
    }
133
134
    /**
135
     * Attempt to compose the best scenario minified query so that a user could find it without expanding it
136
     *
137
     * @param string  $query
138
     * @param array   $keywords
139
     * @param integer $required
140
     *
141
     * @return string
142
     */
143
    private function composeMiniQuery($query, $keywords = array(), $required = 1)
144
    {
145
        // Extract the mandatory keywords and consider the rest as optional keywords
146
        $mandatoryKeywords = array_splice($keywords, 0, $required);
147
148
        $combinations = array();
149
        $combinationsCount = count($keywords);
150
151
        // Compute all the possible combinations of keywords to match the query for
152
        while ($combinationsCount > 0) {
153
            $combinations = array_merge($combinations, $this->getPossibleCombinations($keywords, $combinationsCount));
154
            $combinationsCount--;
155
        }
156
157
        // Try and match the best case query pattern
158
        foreach ($combinations as $combination) {
159
            $combination = array_merge($mandatoryKeywords, $combination);
160
161
            $regexp = implode('(.*) ', $combination) . ' (.*)';
162
            $regexp = '/^' . $regexp . '/is';
163
164
            if (preg_match($regexp, $query, $matches)) {
165
166
                $result = $this->shrinkParameters($matches, $combination);
167
168
                return $result;
169
            }
170
        }
171
172
        // Try and match the simplest query form that contains only the mandatory keywords
173
        $regexp = implode(' (.*)', $mandatoryKeywords) . ' (.*)';
174
        $regexp = '/^' . $regexp . '/is';
175
176
        if (preg_match($regexp, $query, $matches)) {
177
            $result = $this->shrinkParameters($matches, $mandatoryKeywords);
178
179
            return $result;
180
        }
181
182
        // Fallback in case we didn't managed to find any good match (can we actually have that happen?!)
183
        $result = substr($query, 0, $this->maxCharWidth);
184
185
        return $result;
186
    }
187
188
    /**
189
     * Minify the query
190
     *
191
     * @param string $query
192
     *
193
     * @return string
194
     */
195
    public function minifyQuery($query)
196
    {
197
        $result = '';
198
        $keywords = array();
199
        $required = 1;
200
201
        // Check if we can match the query against any of the major types
202
        switch (true) {
203 View Code Duplication
            case stripos($query, 'SELECT') !== false:
0 ignored issues
show
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...
204
                $keywords = array('SELECT', 'FROM', 'WHERE', 'HAVING', 'ORDER BY', 'LIMIT');
205
                $required = 2;
206
                break;
207
208 View Code Duplication
            case stripos($query, 'DELETE') !== false :
0 ignored issues
show
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...
209
                $keywords = array('DELETE', 'FROM', 'WHERE', 'ORDER BY', 'LIMIT');
210
                $required = 2;
211
                break;
212
213 View Code Duplication
            case stripos($query, 'UPDATE') !== false :
0 ignored issues
show
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...
214
                $keywords = array('UPDATE', 'SET', 'WHERE', 'ORDER BY', 'LIMIT');
215
                $required = 2;
216
                break;
217
218 View Code Duplication
            case stripos($query, 'INSERT') !== false :
0 ignored issues
show
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...
219
                $keywords = array('INSERT', 'INTO', 'VALUE', 'VALUES');
220
                $required = 2;
221
                break;
222
223
            // If there's no match so far just truncate it to the maximum allowed by the interface
224
            default:
225
                $result = substr($query, 0, $this->maxCharWidth);
226
        }
227
228
        // If we had a match then we should minify it
229
        if ($result == '') {
230
            $result = $this->composeMiniQuery($query, $keywords, $required);
231
        }
232
233
        // Remove unneeded boilerplate HTML
234
        $result = str_replace(array("<pre style='background:white;'", "</pre>"), array("<span", "</span>"), $result);
235
236
        return $result;
237
    }
238
239
    /**
240
     * Escape parameters of a SQL query
241
     * DON'T USE THIS FUNCTION OUTSIDE ITS INTEDED SCOPE
242
     *
243
     * @internal
244
     *
245
     * @param mixed $parameter
246
     *
247
     * @return string
248
     */
249
    public static function escapeFunction($parameter)
250
    {
251
        $result = $parameter;
252
253
        switch (true) {
254
            case is_string($result) :
255
                $result = "'" . addslashes($result) . "'";
256
                break;
257
258
            case is_array($result) :
259
                foreach ($result as &$value) {
260
                    $value = static::escapeFunction($value);
261
                }
262
263
                $result = implode(', ', $result);
264
                break;
265
266
            case is_object($result) :
267
                $result = addslashes((string) $result);
268
                break;
269
        }
270
271
        return $result;
272
    }
273
274
    /**
275
     * Return a query with the parameters replaced
276
     *
277
     * @param string $query
278
     * @param array  $parameters
279
     *
280
     * @return string
281
     */
282
    public function replaceQueryParameters($query, $parameters)
283
    {
284
        $i = 0;
285
286
        $result = preg_replace_callback(
287
            '/\?|(:[a-z0-9_]+)/i',
288
            function ($matches) use ($parameters, &$i) {
289
                $key = substr($matches[0], 1);
290
                if (!isset($parameters[$i]) && !isset($parameters[$key])) {
291
                    return $matches[0];
292
                }
293
294
                $value = isset($parameters[$i]) ? $parameters[$i] : $parameters[$key];
295
                $result = DoctrineExtension::escapeFunction($value);
296
                $i++;
297
298
                return $result;
299
            },
300
            $query
301
        );
302
303
        $result = \SqlFormatter::highlight($result);
304
        $result = str_replace(array("<pre ", "</pre>"), array("<span ", "</span>"), $result);
305
306
        return $result;
307
    }
308
309
    /**
310
     * Get the name of the extension
311
     *
312
     * @return string
313
     */
314
    public function getName()
315
    {
316
        return 'doctrine_extension';
317
    }
318
319
}
320