Issues (31)

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/Serializers/ResourceSerializer.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
2
3
namespace Huntie\JsonApi\Serializers;
4
5
use Illuminate\Support\Collection;
6
7
class ResourceSerializer extends JsonApiSerializer
8
{
9
    /**
10
     * The model instance to transform.
11
     *
12
     * @var \Illuminate\Database\Eloquent\Model
13
     */
14
    protected $record;
15
16
    /**
17
     * The subset of attributes to return on each resource type.
18
     *
19
     * @var array
20
     */
21
    protected $fields;
22
23
    /**
24
     * The relationship paths to match for included resources.
25
     *
26
     * @var array
27
     */
28
    protected $include;
29
30
    /**
31
     * The named relationships to list against this resource.
32
     *
33
     * @var array
34
     */
35
    protected $relationships;
36
37
    /**
38
     * Create a new JSON API resource serializer.
39
     *
40
     * @param \Illuminate\Database\Eloquent\Model $record        The model instance to serialise
41
     * @param array|null                          $fields        The subset of fields to return on each resource type
42
     * @param array|null                          $include       The paths of relationships to include
43
     * @param array|null                          $relationships Additional named relationships to list
44
     */
45
    public function __construct($record, array $fields = [], array $include = [], array $relationships = [])
46
    {
47
        parent::__construct();
48
49
        $this->record = $record;
50
        $this->fields = array_unique($fields);
51
        $this->include = array_unique($include);
52
53
        $this->relationships = array_unique(
54
            array_merge(
55
                $relationships,
56
                array_keys($record->getRelations()),
57
                array_map(function ($path) {
58
                    return explode('.', $path, 2)[0];
59
                }, $include)
60
            )
61
        );
62
    }
63
64
    /**
65
     * Limit which relations can be included.
66
     *
67
     * @param array $include
68
     */
69
    public function scopeIncludes($include)
70
    {
71
        $this->include = array_intersect($this->include, $include);
72
    }
73
74
    /**
75
     * Return a JSON API resource identifier object for the primary record.
76
     *
77
     * @return array
78
     */
79
    public function toResourceIdentifier()
80
    {
81
        return [
82
            'type' => $this->getResourceType(),
83
            'id' => $this->getPrimaryKey(),
84
        ];
85
    }
86
87
    /**
88
     * Return a base JSON API resource object for the primary record containing
89
     * only immediate attributes.
90
     *
91
     * @return array
92
     */
93
    public function toBaseResourceObject()
94
    {
95
        return array_merge($this->toResourceIdentifier(), [
96
            'attributes' => $this->transformRecordAttributes(),
97
        ]);
98
    }
99
100
    /**
101
     * Return a full JSON API resource object for the primary record.
102
     *
103
     * @return array
104
     */
105
    public function toResourceObject()
106
    {
107
        return array_filter(array_merge($this->toBaseResourceObject(), [
108
            'relationships' => $this->transformRecordRelations()->toArray(),
109
        ]));
110
    }
111
112
    /**
113
     * Return primary data for the JSON API document.
114
     *
115
     * @return mixed
116
     */
117
    protected function getPrimaryData()
118
    {
119
        return $this->toResourceObject();
120
    }
121
122
    /**
123
     * Return any secondary included resource objects.
124
     *
125
     * @throws \Huntie\JsonApi\Exceptions\InvalidRelationPathException
126
     *
127
     * @return \Illuminate\Support\Collection
128
     */
129
    public function getIncluded()
130
    {
131
        $included = collect();
132
133
        foreach ($this->getIncludePaths() as $path) {
134
            $resolved = $this->record;
135
136
            if (!($resolved instanceof Collection)) {
137
                $resolved = collect([$resolved])->filter();
138
            }
139
140
            while (!empty($path)) {
141
                list($relation, $path) = array_pad(explode('.', $path, 2), 2, null);
142
                $nextRelation = preg_replace('/\..*/', '', $path);
143
144
                foreach ($resolved as $record) {
145
                    $records = (new RelationshipSerializer($record, $relation, $this->fields, array_filter([$nextRelation])))
0 ignored issues
show
This line exceeds maximum limit of 120 characters; contains 125 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
146
                        ->toResourceCollection();
147
148
                    if ($records instanceof Collection) {
149
                        $included = $included->merge($records);
150
                    } else if (!empty($records)) {
151
                        $included->push($records);
152
                    }
153
                }
154
155
                $resolved = $resolved
156
                    ->map(function ($record) use ($relation) {
157
                        return $record->{$relation};
158
                    })
159
                    ->flatten()
160
                    ->filter();
161
            }
162
        }
163
164
        return $this->filterUnique($included);
165
    }
166
167
    /**
168
     * Return the primary resource type name.
169
     */
170
    protected function getResourceType(): string
171
    {
172
        $modelName = collect(explode('\\', get_class($this->record)))->last();
173
174
        if (config('jsonapi.singular_type_names') !== true) {
175
            $modelName = str_plural($modelName);
176
        }
177
178
        return snake_case($modelName, '-');
179
    }
180
181
    /**
182
     * Return the primary key value for the resource.
183
     *
184
     * @return int|string
185
     */
186
    protected function getPrimaryKey()
187
    {
188
        $value = $this->record->getKey();
189
190
        return is_int($value) ? $value : (string) $value;
191
    }
192
193
    /**
194
     * Return the attribute subset requested for the primary resource type.
195
     */
196
    protected function getRequestedFields(): array
197
    {
198
        $fields = array_get($this->fields, $this->getResourceType());
199
200
        return is_array($fields) ? $fields : preg_split('/,/', $fields, null, PREG_SPLIT_NO_EMPTY);
201
    }
202
203
    /**
204
     * Return the deepest relationship paths that should be used to resolve
205
     * all included relations.
206
     */
207
    protected function getIncludePaths(): array
208
    {
209
        return array_diff(
210
            $this->include,
211
            array_filter(array_map(function ($path) {
212
                preg_match('/(.*)\..+$/', $path, $matches);
213
214
                return $matches[1] ?? null;
215
            }, $this->include))
216
        );
217
    }
218
219
    /**
220
     * Return the attribute object data for the primary record.
221
     */
222
    protected function transformRecordAttributes(): array
223
    {
224
        $attributes = array_except($this->record->attributesToArray(), ['id']);
225
        $fields = $this->getRequestedFields();
226
227
        if (!empty($fields)) {
228
            $attributes = array_only($attributes, $fields);
229
        }
230
231
        return $attributes;
232
    }
233
234
    /**
235
     * Return a collection of JSON API resource identifier objects by each
236
     * relation on the primary record.
237
     *
238
     * @throws \Huntie\JsonApi\Exceptions\InvalidRelationPathException
239
     *
240
     * @return \Illuminate\Support\Collection
241
     */
242
    protected function transformRecordRelations()
243
    {
244
        return collect($this->relationships)->combine(array_map(function ($relation) {
245
            return [
246
                'data' => (new RelationshipSerializer($this->record, $relation))->toResourceLinkage(),
247
            ];
248
        }, $this->relationships));
249
    }
250
}
251