This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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 Soupmix; |
||
4 | |||
5 | |||
6 | use MongoDB\BSON\ObjectID; |
||
7 | |||
8 | final class MongoDB implements Base |
||
9 | { |
||
10 | protected $conn = null; |
||
11 | |||
12 | private $dbName = null; |
||
13 | |||
14 | private $database = null; |
||
15 | |||
16 | 2 | public function __construct($config, \MongoDB\Client $client) |
|
17 | { |
||
18 | 2 | $this->dbName = $config['db_name']; |
|
19 | 2 | $this->conn = $client; |
|
20 | 2 | $this->database = $this->conn->{$this->dbName}; |
|
21 | 2 | } |
|
22 | |||
23 | public function getConnection() |
||
24 | { |
||
25 | return $this->conn; |
||
26 | } |
||
27 | |||
28 | public function create(string $collection, array $fields) |
||
29 | { |
||
30 | return $this->database->createCollection($collection); |
||
31 | } |
||
32 | |||
33 | public function drop(string $collection) |
||
34 | { |
||
35 | return $this->database->dropCollection($collection); |
||
36 | } |
||
37 | |||
38 | public function truncate(string $collection) |
||
39 | { |
||
40 | $this->database->dropCollection($collection); |
||
41 | return $this->database->createCollection($collection); |
||
42 | } |
||
43 | |||
44 | public function createIndexes(string $collection, array $indexes) |
||
45 | { |
||
46 | $collection = $this->database->selectCollection($collection); |
||
47 | return $collection->createIndexes($indexes); |
||
48 | } |
||
49 | |||
50 | 2 | public function insert(string $collection, array $values) |
|
51 | { |
||
52 | 2 | $collection = $this->database->selectCollection($collection); |
|
53 | 2 | $result = $collection->insertOne($values); |
|
54 | 2 | $docId = $result->getInsertedId(); |
|
55 | 2 | if (is_object($docId)) { |
|
56 | 2 | return (string) $docId; |
|
57 | } |
||
58 | return null; |
||
59 | } |
||
60 | |||
61 | 1 | public function get(string $collection, $docId) |
|
62 | { |
||
63 | 1 | if (gettype($docId) === 'array') { |
|
64 | 1 | return $this->multiGet($collection, $docId); |
|
65 | } |
||
66 | return $this->singleGet($collection, (string) $docId); |
||
67 | 1 | } |
|
68 | |||
69 | private function singleGet(string $collection, $docId) |
||
70 | 1 | { |
|
71 | $collection = $this->database->selectCollection($collection); |
||
72 | $options = [ |
||
73 | 1 | 'typeMap' => ['root' => 'array', 'document' => 'array'], |
|
74 | 1 | ]; |
|
75 | 1 | $filter = ['_id' => new ObjectID($docId)]; |
|
76 | 1 | $result = $collection->findOne($filter, $options); |
|
77 | 1 | if ($result!==null) { |
|
78 | 1 | $result['id'] = (string) $result['_id']; |
|
79 | 1 | unset($result['_id']); |
|
80 | 1 | } |
|
81 | 1 | return $result; |
|
82 | } |
||
83 | |||
84 | private function multiGet(string $collection, array $docIds) |
||
85 | { |
||
86 | $options = [ |
||
87 | 'typeMap' => ['root' => 'array', 'document' => 'array'], |
||
88 | ]; |
||
89 | $idList = []; |
||
90 | foreach ($docIds as $itemId) { |
||
91 | $idList[]=['_id'=>new ObjectID($itemId)]; |
||
92 | } |
||
93 | $filter = ['$or'=>$idList]; |
||
94 | $cursor = $collection->find($filter, $options); |
||
0 ignored issues
–
show
|
|||
95 | $iterator = new \IteratorIterator($cursor); |
||
96 | $iterator->rewind(); |
||
97 | $results=[]; |
||
98 | while ($doc = $iterator->current()) { |
||
99 | if (isset($doc['_id'])) { |
||
100 | $doc['id'] = (string) $doc['_id']; |
||
101 | unset($doc['_id']); |
||
102 | } |
||
103 | $results[$doc['id']] = $doc; |
||
104 | $iterator->next(); |
||
105 | } |
||
106 | return $results; |
||
107 | } |
||
108 | |||
109 | public function update(string $collection, array $filters, array $values) |
||
110 | { |
||
111 | $collection = $this->database->selectCollection($collection); |
||
112 | if (isset($filters['id'])) { |
||
113 | $filters['_id'] = new ObjectID($filters['id']); |
||
114 | unset($filters['id']); |
||
115 | } |
||
116 | $query_filters = []; |
||
117 | if ($filters != null) { |
||
118 | $query_filters = ['$and' => self::buildFilter($filters)]; |
||
119 | } |
||
120 | $values_set = ['$set' => $values]; |
||
121 | try{ |
||
122 | $result = $collection->updateMany($query_filters, $values_set); |
||
123 | |||
124 | } catch (\Exception $e){ |
||
125 | throw new \Exception($e->getMessage()); |
||
126 | } |
||
127 | |||
128 | |||
129 | return $result->getModifiedCount(); |
||
130 | } |
||
131 | |||
132 | 2 | public function delete(string $collection, array $filter) |
|
133 | { |
||
134 | 2 | $collection = $this->database->selectCollection($collection); |
|
135 | 2 | ||
136 | 2 | $filters = ['$and' => self::buildFilter($filter)]; |
|
137 | 2 | ||
138 | 2 | if (isset($filter['id'])) { |
|
139 | 2 | $filter['_id'] = new ObjectID($filter['id']); |
|
140 | 2 | unset($filter['id']); |
|
141 | 2 | } |
|
142 | $result = $collection->deleteMany($filter); |
||
143 | return $result->getDeletedCount(); |
||
144 | 1 | } |
|
145 | |||
146 | 1 | public function find(string $collection, ?array $filters, ?array $fields = null, ?array $sort = null, ?int $start = 0, ?int $limit = 25) |
|
147 | 1 | { |
|
148 | $collection = $this->database->selectCollection($collection); |
||
149 | if (isset($filters['id'])) { |
||
150 | $filters['_id'] = new ObjectID($filters['id']); |
||
151 | 1 | unset($filters['id']); |
|
152 | 1 | } |
|
153 | 1 | $query_filters = []; |
|
154 | 1 | if ($filters != null) { |
|
155 | 1 | $query_filters = ['$and' => self::buildFilter($filters)]; |
|
156 | 1 | } |
|
157 | 1 | $count = $collection->count($query_filters); |
|
158 | if ($count > 0) { |
||
159 | 1 | $results = []; |
|
160 | 1 | $options = [ |
|
161 | 1 | 'limit' => (int) $limit, |
|
162 | 1 | 'skip' => (int) $start, |
|
163 | 1 | 'typeMap' => ['root' => 'array', 'document' => 'array'], |
|
164 | ]; |
||
165 | if ($fields!==null) { |
||
166 | $projection = []; |
||
167 | foreach ($fields as $field) { |
||
168 | if ($field=='id') { |
||
169 | $field = '_id'; |
||
170 | } |
||
171 | $projection[$field] = true; |
||
172 | } |
||
173 | 1 | $options['projection'] = $projection; |
|
174 | } |
||
175 | if ($sort!==null) { |
||
176 | foreach ($sort as $sort_key => $sort_dir) { |
||
177 | $sort[$sort_key] = ($sort_dir=='desc') ? -1 : 1; |
||
178 | if ($sort_key=='id') { |
||
179 | $sort['_id'] = $sort[$sort_key]; |
||
180 | unset($sort['id']); |
||
181 | } |
||
182 | } |
||
183 | $options['sort'] = $sort; |
||
184 | 1 | } |
|
185 | 1 | ||
186 | 1 | $cursor = $collection->find($query_filters, $options); |
|
187 | 1 | $iterator = new \IteratorIterator($cursor); |
|
188 | 1 | $iterator->rewind(); |
|
189 | 1 | while ($doc = $iterator->current()) { |
|
190 | 1 | if (isset($doc['_id'])) { |
|
191 | 1 | $doc['id'] = (string) $doc['_id']; |
|
192 | 1 | unset($doc['_id']); |
|
193 | 1 | } |
|
194 | 1 | $results[] = $doc; |
|
195 | 1 | $iterator->next(); |
|
196 | } |
||
197 | return ['total' => $count, 'data' => $results]; |
||
198 | } |
||
199 | return ['total' => 0, 'data' => null]; |
||
200 | } |
||
201 | |||
202 | public function query(string $collection) |
||
203 | { |
||
204 | return new MongoDBQueryBuilder($collection, $this); |
||
205 | 2 | } |
|
206 | |||
207 | 2 | public static function buildFilter($filter) |
|
208 | 2 | { |
|
209 | $filters = []; |
||
210 | 2 | foreach ($filter as $key => $value) { |
|
211 | 1 | ||
212 | if (strpos($key, '__')!==false) { |
||
213 | 2 | $filters[] = self::buildFilterForKeys($key, $value); |
|
214 | 1 | //$filters = self::mergeFilters($filters, $tmpFilters); |
|
215 | 1 | } elseif (strpos($key, '__') === false && is_array($value)) { |
|
216 | 2 | $filters[]['$or'] = self::buildFilterForOr($value); |
|
217 | } else { |
||
218 | 2 | $filters[][$key] = $value; |
|
219 | 2 | } |
|
220 | } |
||
221 | return $filters; |
||
222 | 1 | } |
|
223 | |||
224 | 1 | public static function buildFilterForOr($orValues) |
|
225 | 1 | { |
|
226 | 1 | $filters = []; |
|
227 | 1 | foreach ($orValues as $filter) { |
|
228 | 1 | $subKey = array_keys($filter)[0]; |
|
229 | 1 | $subValue = $filter[$subKey]; |
|
230 | if (strpos($subKey, '__')!==false) { |
||
231 | 1 | $filters[] = self::buildFilterForKeys($subKey, $subValue); |
|
232 | // $filters = self::mergeFilters($filters, $tmpFilters); |
||
233 | } else { |
||
234 | 1 | $filters[][$subKey] = $subValue; |
|
235 | 1 | } |
|
236 | } |
||
237 | return $filters; |
||
238 | } |
||
239 | |||
240 | private static function mergeFilters ($filters, $tmpFilters){ |
||
241 | |||
242 | foreach ($tmpFilters as $fKey => $fVals) { |
||
243 | if (isset($filters[$fKey])) { |
||
244 | foreach ($fVals as $fVal) { |
||
245 | $filters[$fKey][] = $fVal; |
||
246 | } |
||
247 | } else { |
||
248 | $filters[$fKey] = $fVals; |
||
249 | } |
||
250 | } |
||
251 | return $filters; |
||
252 | 1 | } |
|
253 | |||
254 | 1 | private static function buildFilterForKeys($key, $value) |
|
255 | 1 | { |
|
256 | preg_match('/__(.*?)$/i', $key, $matches); |
||
257 | 1 | $operator = $matches[1]; |
|
258 | switch ($operator) { |
||
259 | case '!in': |
||
260 | 1 | $operator = 'nin'; |
|
261 | break; |
||
262 | case 'not': |
||
263 | 1 | $operator = 'ne'; |
|
264 | 1 | break; |
|
265 | case 'wildcard': |
||
266 | $operator = 'regex'; |
||
267 | 1 | $value = str_replace(array('?'), array('.'), $value); |
|
268 | break; |
||
269 | case 'prefix': |
||
270 | $operator = 'regex'; |
||
271 | $value = $value.'*'; |
||
272 | 1 | break; |
|
273 | 1 | } |
|
274 | 1 | $key = str_replace($matches[0], '', $key); |
|
275 | $filters= [$key => ['$'.$operator => $value]]; |
||
276 | return $filters; |
||
277 | } |
||
278 | |||
279 | } |
||
280 |
Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.