GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (423)

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.

myth/Docs/Search.php (1 issue)

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 namespace Myth\Docs;
2
/**
3
 * Sprint
4
 *
5
 * A set of power tools to enhance the CodeIgniter framework and provide consistent workflow.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 *
25
 * @package     Sprint
26
 * @author      Lonnie Ezell
27
 * @copyright   Copyright 2014-2015, New Myth Media, LLC (http://newmythmedia.com)
28
 * @license     http://opensource.org/licenses/MIT  (MIT)
29
 * @link        http://sprintphp.com
30
 * @since       Version 1.0
31
 */
32
33
use Myth\Docs\DocSearchInterface;
34
35
/**
36
 * Class Search
37
 *
38
 * Implements basic search capabilities for Bonfire docs. Includes application,
39
 * core bonfire, and module docs.
40
 *
41
 * @package Myth\Docs
42
 */
43
class Search implements DocSearchInterface
44
{
45
46
    /**
47
     * Minimum characters that can be submitted for a search.
48
     *
49
     * @var int
50
     */
51
    protected $min_chars = 3;
52
53
    /**
54
     * Maximum characters that can be submitted for a search.
55
     *
56
     * @var int
57
     */
58
    protected $max_chars = 30;
59
60
    /**
61
     * Valid file extensions we can search in.
62
     *
63
     * @var string
64
     */
65
    protected $allowed_file_types = 'html|htm|php|php4|php5|txt|md';
66
67
    /**
68
     * Which files should we skip over during our search?
69
     *
70
     * @var array
71
     */
72
    protected $skip_files = ['.', '..', '_404.md', '_toc.ini'];
73
74
    /**
75
     * How much of each file should we read.
76
     * Use lower values for faster searches.
77
     *
78
     * @var int
79
     */
80
    protected $byte_size = 51200;
81
82
    /**
83
     * Number of words long (approximately)
84
     * the result excerpt should be.
85
     *
86
     * @var int
87
     */
88
    protected $excerpt_length = 60;
89
90
    /**
91
     * The maximum number of results allowed from a single file.
92
     *
93
     * @var int
94
     */
95
    protected $max_per_file = 1;
96
97
    protected $doc_folders = array();
98
99
    protected $formatters = array();
100
101
    //--------------------------------------------------------------------
102
103
    /**
104
     * The entry point for performing a search of the documentation.
105
     *
106
     * @param null $terms
107
     * @param array $folders
108
     *
109
     * @return array|null
110
     */
111
    public function search($terms = null, $folders = [])
112
    {
113
        if (empty($terms) || empty($folders)) {
114
            return null;
115
        }
116
117
        $results = [];
118
        $this->doc_folders = $folders;
119
120
        foreach ($folders as $group => $folder) {
121
            $results = array_merge($results, $this->searchFolder($terms, $folder, $group));
122
        }
123
124
        return $results;
125
    }
126
127
    //--------------------------------------------------------------------
128
129
    //--------------------------------------------------------------------
130
    // Private Methods
131
    //--------------------------------------------------------------------
132
133
134
    /**
135
     * Searches a single directory worth of files.
136
     *
137
     * @param $term
138
     * @param $folder
139
     * @param $group_name
140
     *
141
     * @return array The results.
142
     */
143
    protected function searchFolder($term, $folder, $group_name)
144
    {
145
        $results = [];
146
147
        $map = $this->directory_map($folder, 2);
148
149
        $map = $this->flattenMap($map);
150
151
        // Make sure we have something to work with.
152
        if (! is_array($map) || (is_array($map) && ! count($map))) {
153
            return [];
154
        }
155
156
        // Loop over each file and search the contents for our term.
157
        foreach ($map as $dir => $file) {
158
            $file_count = 0;
159
160
            if (in_array($file, $this->skip_files)) {
161
                continue;
162
            }
163
164
            // Is it a folder?
165
            if (is_array($file) && count($file)) {
166
                $results = array_merge($results, $this->searchFolder($term, $folder . '/' . $dir, $group_name));
167
                continue;
168
            }
169
170
            // Make sure it's the right file type...
171
            if (! preg_match("/({$this->allowed_file_types})/i", $file)) {
172
                continue;
173
            }
174
175
            $path = is_string($dir) ? $folder . '/' . $dir . '/' . $file : $folder . '/' . $file;
176
            $term_html = htmlentities($term);
177
178
            // Read in the file text
179
            $handle = fopen($path, 'r');
180
            $text = fread($handle, $this->byte_size);
181
182
            // Do we have a match in here somewhere?
183
            $found = stristr($text, $term) || stristr($text, $term_html);
184
185
            if (! $found) {
186
                continue;
187
            }
188
189
            // Escape our terms to safely use in a preg_match
190
            $excerpt = strip_tags($text);
191
            $term = preg_quote($term);
192
            $term = str_replace("/", "\/", "{$term}");
193
            $term_html = preg_quote($term_html);
194
            $term_html = str_replace("/", "\/", "{$term_html}");
195
196
            // Add the item to our results with extracts.
197
            if (preg_match_all(
198
                "/((\s\S*){0,3})($term|$term_html)((\s?\S*){0,3})/i",
199
                $excerpt,
200
                $matches,
201
                PREG_OFFSET_CAPTURE | PREG_SET_ORDER
202
            )) {
203
                foreach ($matches as $match) {
204
                    if ($file_count >= $this->max_per_file) {
205
                        continue;
206
                    }
207
                    $result_url = '/docs/' . $group_name . '/' . str_replace('.md', '', $file);
208
209
                    foreach ($this->doc_folders as $alias => $folder) {
210
                        $result_url = str_replace($folder, $alias, $result_url);
211
                    }
212
213
                    $results[] = [
214
                        'title' => $this->extractTitle($excerpt, $file),
215
                        'file' => $folder . '/' . $file,
216
                        'url' => $result_url,
217
                        'extract' => $this->buildExtract($excerpt, $term, $match[0][0])
218
                    ];
219
220
                    $file_count++;
221
                }
222
            }
223
        }
224
225
        return $results;
226
    }
227
228
    //--------------------------------------------------------------------
229
230
    /**
231
     * Stores the name of the callback method to run to convert the source
232
     * files to viewable files. By default, this should be used to register
233
     * a Mardown Extended formatter with the system, but could be used to
234
     * extend the
235
     *
236
     * @param string $callback_name
237
     * @param bool $cascade // If FALSE the formatting of a component ends here. If TRUE, will be passed to next formatter.
238
     * @return $this
239
     */
240
    public function registerFormatter($callback_name = '', $cascade = false)
241
    {
242
        if (empty($callback_name)) return;
243
244
        $this->formatters[] = array($callback_name => $cascade);
245
246
        return $this;
247
    }
248
249
    //--------------------------------------------------------------------
250
251
    /**
252
     * Runs the text through the registered formatters.
253
     *
254
     * @param $str
255
     * @return mixed
256
     */
257 View Code Duplication
    public function format($str)
258
    {
259
        if (! is_array($this->formatters)) return $str;
260
261
        foreach ($this->formatters as $formatter) {
262
            $method = key($formatter);
263
            $cascade = $formatter[$method];
264
265
            $str = call_user_func($method, $str);
266
267
            if (! $cascade) return $str;
268
        }
269
270
        return $str;
271
    }
272
273
    //--------------------------------------------------------------------
274
275
276
    //--------------------------------------------------------------------
277
    // Protected Methods
278
    //--------------------------------------------------------------------
279
280
    /**
281
     * Converts an array generated by directory_map into a flat array of
282
     * folders, removing any nested folders and adding them to the path.
283
     *
284
     * @param $map
285
     * @param $prefix   Used to recursively add the folder name...
286
     * @return mixed
287
     */
288
    protected function flattenMap($map, $prefix = '')
289
    {
290
        if (! is_array($map) || ! count($map)) {
291
            return $map;
292
        }
293
294
        $return = [];
295
296
        foreach ($map as $folder => $files) {
297
298
            // If it's a folder name and an array of files
299
            // then call this method recursively to flatten it out.
300
            if (is_array($files)) {
301
                $return = array_merge($return, $this->flattenMap($files, $prefix . $folder));
302
                continue;
303
            }
304
305
            // Else, add our prefix (if any) to the filename...
306
            $return[] = $prefix . $files;
307
        }
308
309
        return $return;
310
    }
311
312
    //--------------------------------------------------------------------
313
314
    /**
315
     * Handles extracting the text surrounding our match and basic match formatting.
316
     *
317
     * @param $excerpt
318
     * @param $term
319
     * @param $match_string
320
     *
321
     * @return string
322
     */
323
    protected function buildExtract($excerpt, $term, $match_string)
324
    {
325
        // Find the character positions within the string that our match was found at.
326
        // That way we'll know from what positions before and after this we want to grab it in.
327
        $start_offset = stripos($excerpt, $match_string);
328
329
        // Modify the start and end positions based on $this->excerpt_length / 2.
330
        $buffer = floor($this->excerpt_length / 2);
331
332
        // Adjust our start position
333
        $start_offset = $start_offset - $buffer;
334
        if ($start_offset < 0) {
335
            $start_offset = 0;
336
        }
337
338
        $extract = substr($excerpt, $start_offset);
339
340
        $extract = strip_tags($this->format($extract));
341
342
        $extract = $this->firstXWords($extract, $this->excerpt_length);
343
344
        // Wrap the search term in a span we can style.
345
        $extract = str_ireplace($term, '<span class="term-hilight">' . $term . '</span>', $extract);
346
347
        return $extract;
348
    }
349
350
    //--------------------------------------------------------------------
351
352
    /**
353
     * Extracts the title from a bit of markdown formatted text. If it doesn't
354
     * have an h1 or h2, then it uses the filename.
355
     *
356
     * @param $excerpt
357
     * @param $file
358
     * @return string
359
     */
360
    protected function extractTitle($excerpt, $file)
361
    {
362
        $title = '';
363
364
        // Easiest to work if this is split into lines.
365
        $lines = explode("\n", $excerpt);
366
367
        if (is_array($lines) && count($lines)) {
368
            foreach ($lines as $line) {
369
                if (strpos($line, '# ') === 0 || strpos($line, '## ') === 0) {
370
                    $title = trim(str_replace('#', '', $line));
371
                    break;
372
                }
373
            }
374
        }
375
376
        // If it's empty, we'll use the filename.
377
        if (empty($title)) {
378
            $title = str_replace('_', ' ', $file);
379
            $title = str_replace('.md', ' ', $title);
380
            $title = ucwords($title);
381
        }
382
383
        return $title;
384
    }
385
    //--------------------------------------------------------------------
386
387
    /**
388
     * Create a Directory Map
389
     *
390
     * Reads the specified directory and builds an array
391
     * representation of it. Sub-folders contained with the
392
     * directory will be mapped as well.
393
     *
394
     * @param    string $source_dir Path to source
395
     * @param    int $directory_depth Depth of directories to traverse
396
     *                        (0 = fully recursive, 1 = current dir, etc)
397
     * @param    bool $hidden Whether to show hidden files
398
     * @return    array
399
     */
400 View Code Duplication
    protected function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE)
401
    {
402
        if ($fp = @opendir($source_dir)) {
403
            $filedata = array();
404
            $new_depth = $directory_depth - 1;
405
            $source_dir = rtrim($source_dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
406
407
            while (FALSE !== ($file = readdir($fp))) {
408
                // Remove '.', '..', and hidden files [optional]
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
409
                if ($file === '.' OR $file === '..' OR ($hidden === FALSE && $file[0] === '.')) {
410
                    continue;
411
                }
412
413
                is_dir($source_dir . $file) && $file .= DIRECTORY_SEPARATOR;
414
415
                if (($directory_depth < 1 OR $new_depth > 0) && is_dir($source_dir . $file))
416
                {
417
                    $filedata[$file] = $this->directory_map($source_dir . $file, $new_depth, $hidden);
418
                } else
419
                {
420
                    // Replace the directory separator here with a forward slash since
421
                    // Windows uses backward slashes and not all browsers will auto-replace
422
                    // those slashes in URLs.
423
                    $filedata[] = str_replace(DIRECTORY_SEPARATOR, '/', $file);
424
                }
425
            }
426
427
            closedir($fp);
428
            return $filedata;
429
        }
430
431
        return FALSE;
432
    }
433
434
    //--------------------------------------------------------------------
435
436
    /**
437
     * Gets the first 'X' words of a string.
438
     *
439
     * @param $str
440
     * @param int $wordCount
441
     * @return string
442
     */
443
    protected function firstXWords($str, $wordCount = 10)
444
    {
445
        return implode(
446
            '',
447
            array_slice(
448
                preg_split(
449
                    '/([\s,\.;\?\!]+)/',
450
                    $str,
451
                    $wordCount * 2 + 1,
452
                    PREG_SPLIT_DELIM_CAPTURE
453
                ),
454
                0,
455
                $wordCount * 2 - 1
456
            )
457
        );
458
    }
459
460
    //--------------------------------------------------------------------
461
462
}
463