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 | * @package Fuel\Common |
||
4 | * @version 2.0 |
||
5 | * @author Fuel Development Team |
||
6 | * @license MIT License |
||
7 | * @copyright 2010 - 2015 Fuel Development Team |
||
8 | * @link http://fuelphp.com |
||
9 | */ |
||
10 | |||
11 | namespace Fuel\Common; |
||
12 | |||
13 | /** |
||
14 | * Help convert between various formats such as XML, JSON, CSV, etc. |
||
15 | * |
||
16 | * @package Fuel\Common |
||
17 | * |
||
18 | * @since 1.0 |
||
19 | */ |
||
20 | class Format |
||
21 | { |
||
22 | /** |
||
23 | * @var array|mixed Input data to convert |
||
24 | */ |
||
25 | protected $data = array(); |
||
26 | |||
27 | /** |
||
28 | * @var array|mixed Configuration for this Format instance |
||
29 | */ |
||
30 | protected $config = array(); |
||
31 | |||
32 | /** |
||
33 | * @var bool whether to ignore namespaces when parsing xml |
||
34 | */ |
||
35 | protected $xmlIgnoreNamespaces = true; |
||
36 | |||
37 | /** |
||
38 | * @var Fuel\Common\Datacontainer Input Container |
||
39 | */ |
||
40 | protected $input; |
||
41 | |||
42 | /** |
||
43 | * @var Fuel\Common\Inflector Inflector object |
||
44 | */ |
||
45 | protected $inflector; |
||
46 | |||
47 | /** |
||
48 | * @param mixed $data Input data to format or convert |
||
49 | * @param mixed $from_type The data type of the input data |
||
50 | * |
||
51 | * @throws InvalidArgumentException if the from_type isn't a known type |
||
52 | */ |
||
53 | public function __construct($data = null, $from_type = null, Array $config = array(), $input = null, $inflector = null) |
||
54 | { |
||
55 | // If the provided data is already formatted we should probably convert it to an array |
||
56 | if ($from_type !== null) |
||
57 | { |
||
58 | if ($from_type == 'xml:ns') |
||
59 | { |
||
60 | $this->xmlIgnoreNamespaces = false; |
||
61 | $from_type = 'xml'; |
||
62 | } |
||
63 | |||
64 | if (method_exists($this, $method = '_from'.ucfirst($from_type))) |
||
65 | { |
||
66 | $data = call_user_func(array($this, $method), $data); |
||
67 | } |
||
68 | else |
||
69 | { |
||
70 | throw new \InvalidArgumentException('Format class does not support conversion from "' . $from_type . '".'); |
||
71 | } |
||
72 | } |
||
73 | |||
74 | // store the passed data and config |
||
75 | $this->data = $data; |
||
76 | $this->config = $config; |
||
77 | |||
78 | // store the injected objects |
||
79 | $this->input = $input; |
||
80 | $this->inflector = $inflector; |
||
81 | } |
||
82 | |||
83 | // FORMATING OUTPUT --------------------------------------------------------- |
||
84 | |||
85 | /** |
||
86 | * To array conversion |
||
87 | * |
||
88 | * Goes through the input and makes sure everything is either a scalar value or array |
||
89 | * |
||
90 | * @param mixed $data |
||
91 | * @return array |
||
92 | */ |
||
93 | public function toArray($data = null) |
||
94 | { |
||
95 | if ($data === null) |
||
96 | { |
||
97 | $data = $this->data; |
||
98 | } |
||
99 | |||
100 | $array = array(); |
||
101 | |||
102 | if (is_object($data) and ! $data instanceof \Iterator) |
||
103 | { |
||
104 | $data = get_object_vars($data); |
||
105 | } |
||
106 | |||
107 | if (empty($data)) |
||
108 | { |
||
109 | return array(); |
||
110 | } |
||
111 | |||
112 | foreach ($data as $key => $value) |
||
0 ignored issues
–
show
|
|||
113 | { |
||
114 | if (is_object($value) or is_array($value)) |
||
115 | { |
||
116 | $array[$key] = $this->toArray($value); |
||
117 | } |
||
118 | else |
||
119 | { |
||
120 | $array[$key] = $value; |
||
121 | } |
||
122 | } |
||
123 | |||
124 | return $array; |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * To XML conversion |
||
129 | * |
||
130 | * @param mixed $data |
||
131 | * @param null $structure |
||
132 | * @param null|string $basenode |
||
133 | * @param null|bool whether to use CDATA in nodes |
||
134 | * @return string |
||
135 | */ |
||
136 | public function toXml($data = null, $structure = null, $basenode = null, $usecdata = null) |
||
137 | { |
||
138 | if ($data === null) |
||
139 | { |
||
140 | $data = $this->data; |
||
141 | } |
||
142 | |||
143 | if ($basenode === null) |
||
144 | { |
||
145 | $basenode = Arr::get($this->config, 'xml.basenode', 'xml'); |
||
146 | } |
||
147 | |||
148 | if ($usecdata === null) |
||
149 | { |
||
150 | $usecdata = Arr::get($this->config, 'xml.usecdata', false); |
||
151 | } |
||
152 | |||
153 | if ($structure === null) |
||
154 | { |
||
155 | $structure = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$basenode />"); |
||
156 | } |
||
157 | |||
158 | // Force it to be something useful |
||
159 | if ( ! is_array($data) and ! is_object($data)) |
||
160 | { |
||
161 | $data = (array) $data; |
||
162 | } |
||
163 | |||
164 | foreach ($data as $key => $value) |
||
165 | { |
||
166 | // replace anything not alpha numeric |
||
167 | $key = preg_replace('/[^a-z_\-0-9]/i', '', $key); |
||
168 | |||
169 | // no numeric keys in our xml please! |
||
170 | if (is_numeric($key)) |
||
171 | { |
||
172 | // make string key... |
||
173 | $key = ($this->inflector->singularize($basenode) != $basenode) ? $this->inflector->singularize($basenode) : 'item'; |
||
174 | } |
||
175 | |||
176 | // if there is another array found recrusively call this function |
||
177 | if (is_array($value) or is_object($value)) |
||
178 | { |
||
179 | $node = $structure->addChild($key); |
||
0 ignored issues
–
show
It seems like
$structure is not always an object, but can also be of type null . Maybe add an additional type check?
If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe: function someFunction(A $objectMaybe = null)
{
if ($objectMaybe instanceof A) {
$objectMaybe->doSomething();
}
}
Loading history...
|
|||
180 | |||
181 | // recursive call if value is not empty |
||
182 | if( ! empty($value)) |
||
183 | { |
||
184 | $this->toXml($value, $node, $key, $usecdata); |
||
185 | } |
||
186 | } |
||
187 | |||
188 | else |
||
189 | { |
||
190 | // add single node. |
||
191 | $encoded = htmlspecialchars(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8'); |
||
192 | |||
193 | if ($usecdata and ($encoded !== (string) $value)) |
||
194 | { |
||
195 | $dom = dom_import_simplexml($structure->addChild($key)); |
||
196 | $owner = $dom->ownerDocument; |
||
197 | $dom->appendChild($owner->createCDATASection($value)); |
||
198 | } |
||
199 | else |
||
200 | { |
||
201 | $structure->addChild($key, $encoded); |
||
202 | } |
||
203 | } |
||
204 | } |
||
205 | |||
206 | // pass back as string. or simple xml object if you want! |
||
207 | return $structure->asXML(); |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * To CSV conversion |
||
212 | * |
||
213 | * @param mixed $data |
||
214 | * @param mixed $delimiter |
||
215 | * @return string |
||
216 | */ |
||
217 | public function toCsv($data = null, $delimiter = null) |
||
218 | { |
||
219 | // csv format settings |
||
220 | $newline = Arr::get($this->config, 'csv.newline', "\n"); |
||
221 | $delimiter or $delimiter = Arr::get($this->config, 'csv.delimiter', ','); |
||
222 | $enclosure = Arr::get($this->config, 'csv.enclosure', '"'); |
||
223 | $escape = Arr::get($this->config, 'csv.escape', '\\'); |
||
224 | |||
225 | // escape function |
||
226 | $escaper = function($items) use($enclosure, $escape) { |
||
227 | return array_map(function($item) use($enclosure, $escape){ |
||
228 | return str_replace($enclosure, $escape.$enclosure, $item); |
||
229 | }, $items); |
||
230 | }; |
||
231 | |||
232 | if ($data === null) |
||
233 | { |
||
234 | $data = $this->data; |
||
235 | } |
||
236 | |||
237 | if (is_object($data) and ! $data instanceof \Iterator) |
||
238 | { |
||
239 | $data = $this->toArray($data); |
||
240 | } |
||
241 | |||
242 | // Multi-dimensional array |
||
243 | if (is_array($data) and Arr::isMulti($data)) |
||
244 | { |
||
245 | $data = array_values($data); |
||
246 | |||
247 | if (Arr::isAssoc($data[0])) |
||
248 | { |
||
249 | $headings = array_keys($data[0]); |
||
250 | } |
||
251 | else |
||
252 | { |
||
253 | $headings = array_shift($data); |
||
254 | } |
||
255 | } |
||
256 | // Single array |
||
257 | else |
||
258 | { |
||
259 | $headings = array_keys((array) $data); |
||
260 | $data = array($data); |
||
261 | } |
||
262 | |||
263 | $output = $enclosure.implode($enclosure.$delimiter.$enclosure, $escaper($headings)).$enclosure.$newline; |
||
264 | |||
265 | foreach ($data as $row) |
||
266 | { |
||
267 | $output .= $enclosure.implode($enclosure.$delimiter.$enclosure, $escaper((array) $row)).$enclosure.$newline; |
||
268 | } |
||
269 | |||
270 | return rtrim($output, $newline); |
||
271 | } |
||
272 | |||
273 | /** |
||
274 | * To JSON conversion |
||
275 | * |
||
276 | * @param mixed $data |
||
277 | * @param bool wether to make the json pretty |
||
278 | * @return string |
||
279 | */ |
||
280 | public function toJson($data = null, $pretty = false) |
||
281 | { |
||
282 | if ($data === null) |
||
283 | { |
||
284 | $data = $this->data; |
||
285 | } |
||
286 | |||
287 | // To allow exporting ArrayAccess objects like Orm\Model instances they need to be |
||
288 | // converted to an array first |
||
289 | $data = (is_array($data) or is_object($data)) ? $this->toArray($data) : $data; |
||
290 | |||
291 | // Return the result in the requested format |
||
292 | if ($pretty) |
||
293 | { |
||
294 | return $this->prettyJson($data); |
||
295 | } |
||
296 | else |
||
297 | { |
||
298 | $result = json_encode($data, Arr::get($this->config, 'json.encode.options', JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP)); |
||
299 | return json_last_error() === JSON_ERROR_NONE ? $result : false; |
||
300 | } |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * To JSONP conversion |
||
305 | * |
||
306 | * @param mixed $data |
||
307 | * @param bool $pretty wether to make the json pretty |
||
308 | * @param string $callback JSONP callback |
||
309 | * @return string formatted JSONP |
||
310 | */ |
||
311 | public function toJsonp($data = null, $pretty = false, $callback = null) |
||
312 | { |
||
313 | if ( ! $callback and $this->input) |
||
314 | { |
||
315 | $callback = $this->input->getParam('callback'); |
||
316 | if ( ! $callback) |
||
317 | { |
||
318 | $callback = 'response'; |
||
319 | } |
||
320 | } |
||
321 | |||
322 | return $callback.'('.(string) $this->toJson($data, $pretty).')'; |
||
323 | } |
||
324 | |||
325 | /** |
||
326 | * Serialize |
||
327 | * |
||
328 | * @param mixed $data |
||
329 | * @return string |
||
330 | */ |
||
331 | public function toSerialized($data = null) |
||
332 | { |
||
333 | if ($data === null) |
||
334 | { |
||
335 | $data = $this->data; |
||
336 | } |
||
337 | |||
338 | return serialize($data); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * Return as a string representing the PHP structure |
||
343 | * |
||
344 | * @param mixed $data |
||
345 | * @return string |
||
346 | */ |
||
347 | public function toPhp($data = null) |
||
348 | { |
||
349 | if ($data === null) |
||
350 | { |
||
351 | $data = $this->data; |
||
352 | } |
||
353 | |||
354 | return var_export($data, true); |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * Convert to YAML |
||
359 | * |
||
360 | * @param mixed $data |
||
361 | * @throws RuntimeException if the Symfony/YAML composer package is not installed |
||
362 | * @return string |
||
363 | */ |
||
364 | public function toYaml($data = null) |
||
365 | { |
||
366 | if ($data == null) |
||
367 | { |
||
368 | $data = $this->data; |
||
369 | } |
||
370 | |||
371 | if ( ! class_exists('Symfony\Component\Yaml\Yaml')) |
||
372 | { |
||
373 | // @codeCoverageIgnoreStart |
||
374 | throw new \RuntimeException('You need to install the "symfony/yaml" composer package to use Format::toYaml()'); |
||
375 | // @codeCoverageIgnoreEnd |
||
376 | } |
||
377 | |||
378 | $parser = new \Symfony\Component\Yaml\Yaml(); |
||
379 | return $parser::dump($data); |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * Import XML data |
||
384 | * |
||
385 | * @param string $string |
||
386 | * @return array |
||
387 | */ |
||
388 | protected function _fromXml($string, $recursive = false) |
||
389 | { |
||
390 | // If it forged with 'xml:ns' |
||
391 | if ( ! $this->xmlIgnoreNamespaces) |
||
392 | { |
||
393 | static $escape_keys = array(); |
||
394 | |||
395 | if ( ! $recursive) |
||
396 | { |
||
397 | $escape_keys = array('_xmlns' => 'xmlns'); |
||
398 | } |
||
399 | |||
400 | if ( ! $recursive and strpos($string, 'xmlns') !== false and preg_match_all('/(\<.+?\>)/s', $string, $matches)) |
||
401 | { |
||
402 | foreach ($matches[1] as $tag) |
||
403 | { |
||
404 | $escaped_tag = $tag; |
||
405 | |||
406 | strpos($tag, 'xmlns=') !== false and $escaped_tag = str_replace('xmlns=', '_xmlns=', $tag); |
||
407 | |||
408 | if (preg_match_all('/[\s\<\/]([^\/\s\'"]*?:\S*?)[=\/\>\s]/s', $escaped_tag, $xmlns)) |
||
409 | { |
||
410 | foreach ($xmlns[1] as $ns) |
||
411 | { |
||
412 | $escaped = Arr::search($escape_keys, $ns); |
||
413 | $escaped or $escape_keys[$escaped = str_replace(':', '_', $ns)] = $ns; |
||
414 | $string = str_replace($tag, $escaped_tag = str_replace($ns, $escaped, $escaped_tag), $string); |
||
415 | $tag = $escaped_tag; |
||
416 | } |
||
417 | } |
||
418 | } |
||
419 | } |
||
420 | } |
||
421 | |||
422 | $_arr = is_string($string) ? simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA) : $string; |
||
423 | $arr = array(); |
||
424 | |||
425 | // Convert all objects SimpleXMLElement to array recursively |
||
426 | foreach ((array)$_arr as $key => $val) |
||
427 | { |
||
428 | if ( ! $this->xmlIgnoreNamespaces) |
||
429 | { |
||
430 | $key = Arr::get($escape_keys, $key, $key); |
||
0 ignored issues
–
show
The variable
$escape_keys does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
431 | } |
||
432 | $arr[$key] = (is_array($val) or is_object($val)) ? $this->_fromXml($val, true) : $val; |
||
433 | } |
||
434 | |||
435 | return $arr; |
||
436 | } |
||
437 | |||
438 | /** |
||
439 | * Import YAML data |
||
440 | * |
||
441 | * @param string $string |
||
0 ignored issues
–
show
There is no parameter named
$string . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not.
Loading history...
|
|||
442 | * @return array |
||
443 | */ |
||
444 | protected function _fromYaml($data) |
||
445 | { |
||
446 | if ( ! class_exists('Symfony\Component\Yaml\Yaml')) |
||
447 | { |
||
448 | // @codeCoverageIgnoreStart |
||
449 | throw new \RuntimeException('You need to install the "symfony/yaml" composer package to use Format::fromYaml()'); |
||
450 | // @codeCoverageIgnoreEnd |
||
451 | } |
||
452 | |||
453 | $parser = new \Symfony\Component\Yaml\Yaml(); |
||
454 | return $parser::parse($data); |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * Import CSV data |
||
459 | * |
||
460 | * @param string $string |
||
461 | * @return array |
||
462 | */ |
||
463 | protected function _fromCsv($string) |
||
464 | { |
||
465 | $data = array(); |
||
466 | |||
467 | $rows = preg_split('/(?<='.preg_quote(Arr::get($this->config, 'csv.enclosure', '"')).')'.Arr::get($this->config, 'csv.regex_newline', '\n').'/', trim($string)); |
||
468 | |||
469 | // csv config |
||
470 | $delimiter = Arr::get($this->config, 'csv.delimiter', ','); |
||
471 | $enclosure = Arr::get($this->config, 'csv.enclosure', '"'); |
||
472 | $escape = Arr::get($this->config, 'csv.escape', '\\'); |
||
473 | |||
474 | // Get the headings |
||
475 | $headings = str_replace($escape.$enclosure, $enclosure, str_getcsv(array_shift($rows), $delimiter, $enclosure, $escape)); |
||
476 | |||
477 | foreach ($rows as $row) |
||
478 | { |
||
479 | $data_fields = str_replace($escape.$enclosure, $enclosure, str_getcsv($row, $delimiter, $enclosure, $escape)); |
||
480 | |||
481 | if (count($data_fields) == count($headings)) |
||
482 | { |
||
483 | $data[] = array_combine($headings, $data_fields); |
||
484 | } |
||
485 | |||
486 | } |
||
487 | |||
488 | return $data; |
||
489 | } |
||
490 | |||
491 | /** |
||
492 | * Import JSON data |
||
493 | * |
||
494 | * @param string $string |
||
495 | * @return mixed |
||
496 | */ |
||
497 | private function _fromJson($string) |
||
498 | { |
||
499 | return json_decode(trim($string)); |
||
500 | } |
||
501 | |||
502 | /** |
||
503 | * Import Serialized data |
||
504 | * |
||
505 | * @param string $string |
||
506 | * @return mixed |
||
507 | */ |
||
508 | private function _fromSerialized($string) |
||
509 | { |
||
510 | return unserialize(trim($string)); |
||
511 | } |
||
512 | |||
513 | /** |
||
514 | * Makes json pretty the json output. |
||
515 | * Borrowed from http://www.php.net/manual/en/function.json-encode.php#80339 |
||
516 | * |
||
517 | * @param string $json json encoded array |
||
0 ignored issues
–
show
There is no parameter named
$json . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not.
Loading history...
|
|||
518 | * @return string|false pretty json output or false when the input was not valid |
||
519 | */ |
||
520 | protected function prettyJson($data) |
||
521 | { |
||
522 | $json = json_encode($data, Arr::get($this->config, 'json.encode.options', JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP)); |
||
523 | |||
524 | if (json_last_error() !== JSON_ERROR_NONE) |
||
525 | { |
||
526 | return false; |
||
527 | } |
||
528 | |||
529 | $tab = "\t"; |
||
530 | $newline = "\n"; |
||
531 | $new_json = ""; |
||
532 | $indent_level = 0; |
||
533 | $in_string = false; |
||
534 | $len = strlen($json); |
||
535 | |||
536 | for ($c = 0; $c < $len; $c++) |
||
537 | { |
||
538 | $char = $json[$c]; |
||
539 | switch($char) |
||
540 | { |
||
541 | case '{': |
||
542 | View Code Duplication | case '[': |
|
543 | if ( ! $in_string) |
||
544 | { |
||
545 | $new_json .= $char.$newline.str_repeat($tab, $indent_level+1); |
||
546 | $indent_level++; |
||
547 | } |
||
548 | else |
||
549 | { |
||
550 | $new_json .= $char; |
||
551 | } |
||
552 | break; |
||
553 | case '}': |
||
554 | View Code Duplication | case ']': |
|
555 | if ( ! $in_string) |
||
556 | { |
||
557 | $indent_level--; |
||
558 | $new_json .= $newline.str_repeat($tab, $indent_level).$char; |
||
559 | } |
||
560 | else |
||
561 | { |
||
562 | $new_json .= $char; |
||
563 | } |
||
564 | break; |
||
565 | View Code Duplication | case ',': |
|
566 | if ( ! $in_string) |
||
567 | { |
||
568 | $new_json .= ','.$newline.str_repeat($tab, $indent_level); |
||
569 | } |
||
570 | else |
||
571 | { |
||
572 | $new_json .= $char; |
||
573 | } |
||
574 | break; |
||
575 | case ':': |
||
576 | if ( ! $in_string) |
||
577 | { |
||
578 | $new_json .= ': '; |
||
579 | } |
||
580 | else |
||
581 | { |
||
582 | $new_json .= $char; |
||
583 | } |
||
584 | break; |
||
585 | case '"': |
||
586 | if ($c > 0 and $json[$c-1] !== '\\') |
||
587 | { |
||
588 | $in_string = ! $in_string; |
||
589 | } |
||
590 | default: |
||
591 | $new_json .= $char; |
||
592 | break; |
||
593 | } |
||
594 | } |
||
595 | |||
596 | return $new_json; |
||
597 | } |
||
598 | } |
||
599 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
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:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.