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 (3)

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.

services/ExportService.php (1 issue)

Labels
Severity

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
namespace Craft;
4
5
/**
6
 * Export service.
7
 *
8
 * Handles common export logics.
9
 *
10
 * @author    Bob Olde Hampsink <[email protected]>
11
 * @copyright Copyright (c) 2015, Bob Olde Hampsink
12
 * @license   MIT
13
 *
14
 * @link      http://github.com/boboldehampsink
15
 */
16
class ExportService extends BaseApplicationComponent
17
{
18
    /**
19
     * Contains the working export service's name.
20
     *
21
     * @var IExportElementType|bool
22
     */
23
    private $_service;
24
25
    /**
26
     * Custom <tr> paths.
27
     *
28
     * @var array
29
     */
30
    public $customTableRowPaths = array();
31
32
    /**
33
     * Whether custom table row paths have been loaded.
34
     *
35
     * @var bool
36
     */
37
    private $_loadedTableRowPaths = false;
38
39
    /**
40
     * Saves an export map to the database.
41
     *
42
     * @param array $settings
43
     * @param array $map
44
     */
45 2
    public function saveMap(array $settings, array $map)
46
    {
47
        // Unset non-map settings
48 2
        unset($settings['limit'], $settings['offset']);
49 2
        ksort($settings);
50
51
        // Set criteria
52 2
        $criteria = new \CDbCriteria();
53 2
        $criteria->condition = 'settings = :settings';
54 2
        $criteria->params = array(
55 2
            ':settings' => JsonHelper::encode($settings),
56
        );
57
58
        // Check if we have a map already
59 2
        $mapRecord = $this->findMap($criteria);
60
61 2
        if (!count($mapRecord) || $mapRecord->settings != $settings) {
62
63
            // Save settings and map to database
64 1
            $mapRecord = $this->getNewMap();
65 1
            $mapRecord->settings = $settings;
66 1
        }
67
68
        // Save new map to db
69 2
        $mapRecord->map = $map;
70 2
        $mapRecord->save(false);
71 2
    }
72
73
    /**
74
     * @codeCoverageIgnore
75
     *
76
     * @param \CDbCriteria $criteria
77
     *
78
     * @return Export_MapRecord|array|null
79
     */
80
    public function findMap(\CDbCriteria $criteria)
81
    {
82
        return Export_MapRecord::model()->find($criteria);
83
    }
84
85
    /**
86
     * @codeCoverageIgnore
87
     *
88
     * @return Export_MapRecord
89
     */
90
    protected function getNewMap()
91
    {
92
        return new Export_MapRecord();
93
    }
94
95
    /**
96
     * Download the export csv.
97
     *
98
     * @param array $settings
99
     *
100
     * @return string
101
     *
102
     * @throws Exception
103
     */
104 7
    public function download(array $settings)
105
    {
106
        // Get max power
107 7
        craft()->config->maxPowerCaptain();
108
109
        // Check what service we're gonna need
110 7
        if (!($this->_service = $this->getService($settings['type']))) {
111 1
            throw new Exception(Craft::t('Unknown Element Type Service called.'));
112
        }
113
114
        // Get delimiter
115 6
        $delimiter = craft()->plugins->callFirst('registerExportCsvDelimiter');
116 6
        $delimiter = is_null($delimiter) ? ',' : $delimiter;
117
118
        // Open output buffer
119 6
        ob_start();
120
121
        // Write to output stream
122 6
        $export = fopen('php://output', 'w');
123
124
        // Get data
125 6
        $data = $this->getData($settings);
126
127
        // If there is data, process
128 6
        if (is_array($data) && count($data)) {
129
130
            // Put down columns
131 3
            fputcsv($export, $this->parseColumns($settings), $delimiter);
132
133
            // Loop through data
134 3
            foreach ($data as $element) {
0 ignored issues
show
The expression $data of type array|string 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...
135
136
                // Fetch element in case of element id
137 3
                if (is_numeric($element)) {
138 2
                    $element = craft()->elements->getElementById($element, $settings['type']);
139 2
                }
140
141
                // Get fields
142 3
                $fields = $this->parseFields($settings, $element);
143
144
                // Gather row data
145 3
                $rows = array();
146
147
                // Loop trough the fields
148 3
                foreach ($fields as $handle => $data) {
149
150
                    // Parse element data
151 3
                    $data = $this->parseElementData($handle, $data);
152
153
                    // Parse field data
154 3
                    $data = $this->parseFieldData($handle, $data);
155
156
                    // Encode and add to rows
157 3
                    $rows[] = StringHelper::convertToUTF8($data);
158 3
                }
159
160
                // Add rows to export
161 3
                fputcsv($export, $rows, $delimiter);
162 3
            }
163 3
        }
164
165
        // Close buffer and return data
166 6
        fclose($export);
167 6
        $data = ob_get_clean();
168
169
        // Use windows friendly newlines
170 6
        $data = str_replace("\n", "\r\n", $data);
171
172
        // Return the data to controller
173 6
        return $data;
174
    }
175
176
    /**
177
     * Get service to use for exporting.
178
     *
179
     * @param string $elementType
180
     *
181
     * @return object|bool
182
     */
183 4
    public function getService($elementType)
184
    {
185
        // Check if there's a service for this element type elsewhere
186 4
        $service = craft()->plugins->callFirst('registerExportService', array(
187 4
            'elementType' => $elementType,
188 4
        ));
189
190
        // If not, do internal check
191 4
        if ($service == null) {
192
193
            // Get from right elementType
194 4
            $service = 'export_'.strtolower($elementType);
195 4
        }
196
197
        // Check if elementtype can be imported
198 4
        if (isset(craft()->$service) && craft()->$service instanceof IExportElementType) {
199
200
            // Return this service
201 3
            return craft()->$service;
202
        }
203
204 1
        return false;
205
    }
206
207
    /**
208
     * Get path to fieldtype's custom <tr> template.
209
     *
210
     * @param string $fieldHandle
211
     *
212
     * @return string|bool
213
     */
214 2
    public function getCustomTableRow($fieldHandle)
215
    {
216
        // If table row paths haven't been loaded
217 2
        if (!$this->_loadedTableRowPaths) {
218
219
            // Call hook for all plugins
220 2
            $responses = craft()->plugins->call('registerExportTableRowPaths');
221
222
            // Loop through responses from each plugin
223 2
            foreach ($responses as $customPaths) {
224
225
                // Append custom paths to master list
226 1
                $this->customTableRowPaths = array_merge($this->customTableRowPaths, $customPaths);
227 2
            }
228
229
            // Table row paths have been loaded
230 2
            $this->_loadedTableRowPaths = true;
231 2
        }
232
233
        // If fieldtype has been registered and is not falsey
234 2
        if (array_key_exists($fieldHandle, $this->customTableRowPaths) && $this->customTableRowPaths[$fieldHandle]) {
235
236
            // Return specified custom path
237 1
            return $this->customTableRowPaths[$fieldHandle];
238
        }
239
240 1
        return false;
241
    }
242
243
    /**
244
     * Get data from sources.
245
     *
246
     * @param array $settings
247
     *
248
     * @return array
249
     */
250 6
    protected function getData(array $settings)
251
    {
252
        // Get other sources
253 6
        $sources = craft()->plugins->call('registerExportSource', array($settings));
254
255
        // Loop through sources, see if we can get any data
256 6
        $data = array();
257 6
        foreach ($sources as $plugin) {
258 1
            if (is_array($plugin)) {
259 1
                foreach ($plugin as $source) {
260 1
                    $data[] = $source;
261 1
                }
262 1
            }
263 6
        }
264
265
        // Cut up data from source
266 6
        if (array_key_exists('offset', $settings) && is_numeric($settings['offset'])) {
267 2
            $data = array_slice($data, $settings['offset'], $settings['limit']);
268 2
        }
269
270
        // If no data from source, get data by ourselves
271 6
        if (!count($data)) {
272
273
            // Find data
274 5
            $criteria = $this->_service->setCriteria($settings);
275
276
            // Gather element ids
277 5
            $data = $criteria->ids();
278 5
        }
279
280 6
        return $data;
281
    }
282
283
    /**
284
     * Parse fields.
285
     *
286
     * @param array $settings
287
     * @param mixed $element
288
     *
289
     * @return array
290
     */
291 3
    protected function parseFields(array $settings, $element)
292
    {
293 3
        $fields = array();
294
295
        // Only get element attributes and content attributes
296 3
        $attributes = $element;
297 3
        if ($element instanceof BaseElementModel) {
298
299
            // Get service
300 2
            $attributes = $this->_service->getAttributes($settings['map'], $element);
301 2
        }
302
303
        // Loop through the map
304 3
        foreach ($settings['map'] as $handle => $data) {
305
306
            // Only get checked fields
307 3
            if ($data['checked'] == '1' && (array_key_exists($handle, $attributes) || array_key_exists(substr($handle, 0, 5), $attributes))) {
308
309
                // Fill them with data
310 3
                $fields[$handle] = $attributes[$handle];
311 3
            }
312 3
        }
313
314 3
        return $fields;
315
    }
316
317
    /**
318
     * Parse column names.
319
     *
320
     * @param array $settings
321
     *
322
     * @return string
323
     */
324 3
    protected function parseColumns(array $settings)
325
    {
326 3
        $columns = array();
327
328
        // Loop through map
329 3
        foreach ($settings['map'] as $handle => $data) {
330
331
            // If checked
332 3
            if ($data['checked'] == 1) {
333
334
                // Add column
335 3
                $columns[] = StringHelper::convertToUTF8($data['label']);
336 3
            }
337 3
        }
338
339 3
        return $columns;
340
    }
341
342
    /**
343
     * Parse reserved element values.
344
     *
345
     * @param string $handle
346
     * @param string $data
347
     *
348
     * @return string
349
     */
350 3
    protected function parseElementData($handle, $data)
351
    {
352
        switch ($handle) {
353
354
            // Get username of author
355 3
            case ExportModel::HandleAuthor:
356 1
                return craft()->users->getUserById($data)->username;
357
358
            // Make data human readable
359 3
            case ExportModel::HandleEnabled:
360 2
                return $data == '0' ? Craft::t('No') : Craft::t('Yes');
361
362 3
            case ExportModel::HandlePostDate:
363 3
            case ExportModel::HandleExpiryDate:
364 1
                return (string) $data;
365
366
        }
367
368 3
        return $data;
369
    }
370
371
    /**
372
     * Parse field values.
373
     *
374
     * @param string $handle
375
     * @param mixed  $data
376
     *
377
     * @return string
378
     */
379 11
    public function parseFieldData($handle, $data)
380
    {
381
382
        // Do we have any data at all
383 11
        if (!is_null($data)) {
384
385
            // Get field info
386 11
            $field = craft()->fields->getFieldByHandle($handle);
387
388
            // If it's a field ofcourse
389 11
            if (!is_null($field)) {
390
391
                // For some fieldtypes the're special rules
392 11
                switch ($field->type) {
393
394 11
                    case ExportModel::FieldTypeEntries:
395 11
                    case ExportModel::FieldTypeCategories:
396 11
                    case ExportModel::FieldTypeAssets:
397 11
                    case ExportModel::FieldTypeUsers:
398
                        // Show names
399 1
                        $data = $data instanceof ElementCriteriaModel ? implode(', ', $data->find()) : $data;
400 1
                        break;
401
402 10
                    case ExportModel::FieldTypeLightswitch:
403
                        // Make data human readable
404
                        switch ($data) {
405
406 2
                            case '0':
407 1
                                $data = Craft::t('No');
408 1
                                break;
409
410 1
                            case '1':
411 1
                                $data = Craft::t('Yes');
412 1
                                break;
413
414
                        }
415 2
                        break;
416
417 8
                    case ExportModel::FieldTypeTable:
418
                        // Parse table checkboxes
419 1
                        $table = array();
420 1
                        if (is_array($data)) {
421 1
                            foreach ($data as $row) {
422
423
                                // Keep track of column #
424 1
                                $i = 1;
425
426
                                // Loop through columns
427 1
                                foreach ($row as $column => $value) {
428
429
                                    // Get column
430 1
                                    $column = isset($field->settings['columns'][$column]) ? $field->settings['columns'][$column] : (isset($field->settings['columns']['col'.$i]) ? $field->settings['columns']['col'.$i] : array('type' => 'dummy'));
431
432
                                    // Keep track of column #
433 1
                                    ++$i;
434
435
                                    // Parse
436 1
                                    $table[] = $column['type'] == 'checkbox' ? ($value == 1 ? Craft::t('Yes') : Craft::t('No')) : $value;
437 1
                                }
438 1
                            }
439 1
                        }
440
441
                        // Return parsed data as array
442 1
                        $data = $table;
443 1
                        break;
444
445 7
                    case ExportModel::FieldTypeRichText:
446 7
                    case ExportModel::FieldTypeDate:
447 7
                    case ExportModel::FieldTypeRadioButtons:
448 7
                    case ExportModel::FieldTypeDropdown:
449
                        // Resolve to string
450 1
                        $data = (string) $data;
451 1
                        break;
452
453 6
                    case ExportModel::FieldTypeCheckboxes:
454 6
                    case ExportModel::FieldTypeMultiSelect:
455
                        // Parse multi select values
456 1
                        $multi = array();
457 1
                        if (is_array($data)) {
458 1
                            foreach ($data as $row) {
459 1
                                $multi[] = $row->value;
460 1
                            }
461 1
                        }
462
463
                        // Return parsed data as array
464 1
                        $data = $multi;
465 1
                        break;
466
467 11
                }
468 11
            }
469
470
            // Get other operations
471 11
            craft()->plugins->call('registerExportOperation', array(&$data, $handle));
472 11
        } else {
473
474
            // Don't return null, return empty
475 1
            $data = '';
476
        }
477
478
        // If it's an object or an array, make it a string
479 11
        if (is_array($data)) {
480 2
            $data = StringHelper::arrayToString(ArrayHelper::filterEmptyStringsFromArray(ArrayHelper::flattenArray($data)), ', ');
481 2
        }
482
483
        // If it's an object, make it a string
484 11
        if (is_object($data)) {
485 1
            $data = StringHelper::arrayToString(ArrayHelper::filterEmptyStringsFromArray(ArrayHelper::flattenArray(get_object_vars($data))), ', ');
486 1
        }
487
488 11
        return $data;
489
    }
490
}
491