Passed
Push — developer ( 1516b4...c7d7af )
by Mariusz
18:41
created

Exception::logError()   B

Complexity

Conditions 7
Paths 33

Size

Total Lines 37
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
eloc 30
dl 0
loc 37
ccs 0
cts 0
cp 0
rs 8.5066
c 0
b 0
f 0
cc 7
nc 33
nop 0
crap 56
1
<?php
2
3
/**
4
 * Web service exception file.
5
 *
6
 * @package API
7
 *
8
 * @copyright YetiForce S.A.
9
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
10
 * @author    Mariusz Krzaczkowski <[email protected]>
11
 */
12
13
namespace Api\Core;
14
15
/**
16
 * Web service exception class.
17
 */
18
class Exception extends \Exception
19
{
20
	/** {@inheritdoc}  */
21
	public function __toString(): string
22
	{
23
		return rtrim(str_replace(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR, '', parent::__toString()), PHP_EOL);
24
	}
25
26
	/** {@inheritdoc}  */
27
	public function __construct($message, $code = 500, \Throwable $previous = null)
28
	{
29
		parent::__construct($message, $code, $previous);
30
	}
31
32
	/**
33
	 * Show exception error JSON.
34
	 *
35
	 * @return void
36
	 */
37
	public function showError(): void
38
	{
39
		$this->logError();
40
		$message = rtrim(str_replace(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR, '', $this->getMessage()), PHP_EOL);
41
		if ($previous = $this->getPrevious()) {
42
			$this->file = $previous->getFile();
43
			$this->line = $previous->getLine();
44
		}
45
		if (empty($this->message)) {
46
			$this->message = $message;
47
		}
48
		$code = $this->getCode();
49
		if (!\App\Config::debug('apiShowExceptionMessages') && 406 !== $code) {
50
			$message = 'Internal Server Error';
51
		}
52
		$body = [
53
			'status' => 0,
54
			'error' => [
55
				'message' => $message,
56
				'code' => $code,
57
			],
58
		];
59
		if (\App\Config::debug('apiShowExceptionBacktrace')) {
60
			$body['error']['file'] = rtrim(str_replace(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR, '', $this->getFile()), PHP_EOL);
61
			$body['error']['line'] = $this->getLine();
62
			if (!empty($previous)) {
63
				$body['error']['previous'] = rtrim(str_replace(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR, '', $previous->__toString()), PHP_EOL);
64
			}
65
			$body['error']['backtrace'] = \App\Debuger::getBacktrace();
66
		}
67
		$response = Response::getInstance();
68
		$response->setContentType('application/json');
69
		$response->setRequest(Request::init());
70
		$response->setBody($body);
71
		$response->setStatus($code);
72
		if (\App\Config::debug('apiShowExceptionReasonPhrase')) {
73
			$response->setReasonPhrase($this->message);
74
		}
75
		$response->send();
76
	}
77
78
	/**
79
	 * Log error function.
80
	 *
81
	 * @return void
82
	 */
83
	public function logError(): void
84
	{
85
		if (\App\Config::debug('apiLogException')) {
86
			$request = Request::init();
87
			$error = "code: {$this->getCode()} | message: {$this->getMessage()}\n";
88
			$error .= "file: {$this->getFile()} ({$this->getLine()})\n";
89
			$error .= '============ stacktrace: ' . PHP_EOL . $this->getTraceAsString() . PHP_EOL;
90
			$error .= '============ Request ' . \App\RequestUtil::requestId() . ' ======  ' . date('Y-m-d H:i:s') . "  ======\n";
91
			$error .= 'REQUEST_METHOD: ' . \App\Request::getRequestMethod() . PHP_EOL;
92
			$error .= 'REQUEST_URI: ' . $_SERVER['REQUEST_URI'] . PHP_EOL;
93
			$error .= 'QUERY_STRING: ' . $_SERVER['QUERY_STRING'] . PHP_EOL;
94
			$error .= 'PATH_INFO: ' . ($_SERVER['PATH_INFO'] ?? '') . PHP_EOL;
95
			$error .= 'IP: ' . $_SERVER['REMOTE_ADDR'] . PHP_EOL;
96
			$error .= '----------- Headers -----------' . PHP_EOL;
97
			foreach ($request->getHeaders() as $key => $header) {
98
				$error .= $key . ': ' . $header . PHP_EOL;
99
			}
100
			$error .= '----------- Request data -----------' . PHP_EOL;
101
			$error .= print_r($request->getAllRaw(), true) . PHP_EOL;
0 ignored issues
show
Bug introduced by
Are you sure print_r($request->getAllRaw(), true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
			$error .= /** @scrutinizer ignore-type */ print_r($request->getAllRaw(), true) . PHP_EOL;
Loading history...
102
			if ($_GET) {
103
				$error .= "----------- _GET -----------\n";
104
				$error .= print_r($_GET, true) . PHP_EOL;
0 ignored issues
show
Bug introduced by
Are you sure print_r($_GET, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
				$error .= /** @scrutinizer ignore-type */ print_r($_GET, true) . PHP_EOL;
Loading history...
105
			}
106
			if ($_POST) {
107
				$error .= "----------- _POST -----------\n";
108
				$error .= print_r($_POST, true) . PHP_EOL;
0 ignored issues
show
Bug introduced by
Are you sure print_r($_POST, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

108
				$error .= /** @scrutinizer ignore-type */ print_r($_POST, true) . PHP_EOL;
Loading history...
109
			}
110
			if ($payload = file_get_contents('php://input')) {
111
				$error .= "----------- Request payload -----------\n";
112
				$error .= print_r($payload, true) . PHP_EOL;
0 ignored issues
show
Bug introduced by
Are you sure print_r($payload, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

112
				$error .= /** @scrutinizer ignore-type */ print_r($payload, true) . PHP_EOL;
Loading history...
113
			}
114
			$path = ROOT_DIRECTORY . '/cache/logs/webserviceErrors.log';
115
			if (isset(\Api\Controller::$container)) {
116
				$path = ROOT_DIRECTORY . '/cache/logs/webservice' . \Api\Controller::$container . 'Errors.log';
117
			}
118
			file_put_contents($path, '============ Error exception ====== ' . date('Y-m-d H:i:s') . ' ======'
0 ignored issues
show
Security File Manipulation introduced by
$path can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_GET, and $_GET['_container'] is assigned to $container
    in api/webservice/Controller.php on line 65
  2. $container is assigned to property Controller::$container
    in api/webservice/Controller.php on line 69
  3. Read from property Controller::$container, and Api\Core\ROOT_DIRECTORY . '/cache/logs/webservice' . Api\Controller::container . 'Errors.log' is assigned to $path
    in api/webservice/Core/Exception.php on line 116

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
119
				. PHP_EOL . $error . PHP_EOL, FILE_APPEND);
120
		}
121
	}
122
}
123