Issues (287)

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/Controller.php (4 issues)

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 declare(strict_types=1);
2
/**
3
 * Hummingbird Anime Client
4
 *
5
 * An API client for Hummingbird to manage anime and manga watch lists
6
 *
7
 * PHP version 7
8
 *
9
 * @package     HummingbirdAnimeClient
10
 * @author      Timothy J. Warren <[email protected]>
11
 * @copyright   2015 - 2016  Timothy J. Warren
12
 * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
 * @version     3.1
14
 * @link        https://github.com/timw4mail/HummingBirdAnimeClient
15
 */
16
17
namespace Aviat\AnimeClient;
18
19
use const Aviat\AnimeClient\SESSION_SEGMENT;
20
21
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
22
use Aviat\Ion\View\{HtmlView, HttpView, JsonView};
23
use InvalidArgumentException;
24
25
/**
26
 * Controller base, defines output methods
27
 *
28
 * @property Response object $response
29
 */
30
class Controller {
31
32
	use ContainerAware;
33
34
	/**
35
	 * Cache manager
36
	 * @var \Aviat\Ion\Cache\CacheInterface
37
	 */
38
	protected $cache;
39
40
	/**
41
	 * The global configuration object
42
	 * @var Aviat\Ion\ConfigInterface $config
43
	 */
44
	protected $config;
45
46
	/**
47
	 * Request object
48
	 * @var object $request
49
	 */
50
	protected $request;
51
52
	/**
53
	 * Response object
54
	 * @var object $response
55
	 */
56
	protected $response;
57
58
	/**
59
	 * The api model for the current controller
60
	 * @var object
61
	 */
62
	protected $model;
63
64
	/**
65
	 * Url generation class
66
	 * @var UrlGenerator
67
	 */
68
	protected $urlGenerator;
69
70
	/**
71
	 * Session segment
72
	 * @var [type]
73
	 */
74
	protected $session;
75
76
	/**
77
	 * Common data to be sent to views
78
	 * @var array
79
	 */
80
	protected $base_data = [
81
		'url_type' => 'anime',
82
		'other_type' => 'manga',
83
		'menu_name' => ''
84
	];
85
86
	/**
87
	 * Constructor
88
	 *
89
	 * @param ContainerInterface $container
0 ignored issues
show
Should the type for parameter $container not be \Aviat\Ion\Di\ContainerInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
90
	 */
91
	public function __construct(ContainerInterface $container)
92
	{
93
		$this->setContainer($container);
94
		$auraUrlGenerator = $container->get('aura-router')->getGenerator();
95
		$urlGenerator = $container->get('url-generator');
96
		$this->cache =  $container->get('cache');
97
		$this->config = $container->get('config');
98
		$this->request = $container->get('request');
99
		$this->response = $container->get('response');
100
		$this->base_data['url'] = $auraUrlGenerator;
101
		$this->base_data['urlGenerator'] = $urlGenerator;
102
		$this->base_data['auth'] = $container->get('auth');
103
		$this->base_data['config'] = $this->config;
104
		$this->urlGenerator = $urlGenerator;
105
106
		$session = $container->get('session');
107
		$this->session = $session->getSegment(SESSION_SEGMENT);
108
109
		// Set a 'previous' flash value for better redirects
110
		$server_params = $this->request->getServerParams();
111
		if (array_key_exists('HTTP_REFERER', $server_params))
112
		{
113
			$this->session->setFlash('previous', $server_params['HTTP_REFERER']);
114
		}
115
116
		// Set a message box if available
117
		$this->base_data['message'] = $this->session->getFlash('message');
118
	}
119
120
	/**
121
	 * Redirect to the default controller/url from an empty path
122
	 *
123
	 * @return void
124
	 */
125
	public function redirectToDefaultRoute()
126
	{
127
		$default_type = $this->config->get(['routes', 'route_config', 'default_list']);
128
		$this->redirect($this->urlGenerator->default_url($default_type), 303);
129
	}
130
131
	/**
132
	 * Redirect to the previous page
133
	 *
134
	 * @return void
135
	 */
136
	public function redirect_to_previous()
137
	{
138
		$previous = $this->session->getFlash('previous');
139
		$this->redirect($previous, 303);
140
	}
141
142
	/**
143
	 * Set the current url in the session as the target of a future redirect
144
	 *
145
	 * @param string|null $url
146
	 * @return void
147
	 */
148
	public function set_session_redirect($url = NULL)
149
	{
150
		$server_params = $this->request->getServerParams();
151
152
		if ( ! array_key_exists('HTTP_REFERER', $server_params))
153
		{
154
			return;
155
		}
156
157
		$util = $this->container->get('util');
158
		$double_form_page = $server_params['HTTP_REFERER'] === $this->request->getUri();
159
160
		// Don't attempt to set the redirect url if
161
		// the page is one of the form type pages,
162
		// and the previous page is also a form type page_segments
163
		if ($double_form_page)
164
		{
165
			return;
166
		}
167
168
		if (is_null($url))
169
		{
170
			$url = $util->is_view_page()
171
				? $this->request->url->get()
172
				: $server_params['HTTP_REFERER'];
173
		}
174
175
		$this->session->set('redirect_url', $url);
176
	}
177
178
	/**
179
	 * Redirect to the url previously set in the  session
180
	 *
181
	 * @return void
182
	 */
183
	public function session_redirect()
184
	{
185
		$target = $this->session->get('redirect_url');
186
		if (empty($target))
187
		{
188
			$this->notFound();
189
		}
190
		else
191
		{
192
			$this->redirect($target, 303);
193
			$this->session->set('redirect_url', NULL);
194
		}
195
	}
196
197
	/**
198
	 * Get a class member
199
	 *
200
	 * @param string $key
201
	 * @return mixed
202
	 */
203
	public function __get(string $key)
204
	{
205
		$allowed = ['response', 'config'];
206
207
		if (in_array($key, $allowed))
208
		{
209
			return $this->$key;
210
		}
211
212
		return NULL;
213
	}
214
215
	/**
216
	 * Get the string output of a partial template
217
	 *
218
	 * @param HtmlView $view
219
	 * @param string $template
220
	 * @param array $data
221
	 * @throws InvalidArgumentException
222
	 * @return string
223
	 */
224
	protected function load_partial($view, $template, array $data = [])
225
	{
226
		$router = $this->container->get('dispatcher');
227
228
		if (isset($this->base_data))
229
		{
230
			$data = array_merge($this->base_data, $data);
231
		}
232
233
		$route = $router->getRoute();
234
		$data['route_path'] = $route ? $router->getRoute()->path : '';
235
236
237
		$template_path = _dir($this->config->get('view_path'), "{$template}.php");
238
239
		if ( ! is_file($template_path))
240
		{
241
			throw new InvalidArgumentException("Invalid template : {$template}");
242
		}
243
244
		return $view->renderTemplate($template_path, (array)$data);
245
	}
246
247
	/**
248
	 * Render a template with header and footer
249
	 *
250
	 * @param HtmlView $view
251
	 * @param string $template
252
	 * @param array $data
253
	 * @return void
254
	 */
255
	protected function render_full_page($view, $template, array $data)
256
	{
257
		$view->appendOutput($this->load_partial($view, 'header', $data));
258
259
		if (array_key_exists('message', $data) && is_array($data['message']))
260
		{
261
			$view->appendOutput($this->load_partial($view, 'message', $data['message']));
262
		}
263
264
		$view->appendOutput($this->load_partial($view, $template, $data));
265
		$view->appendOutput($this->load_partial($view, 'footer', $data));
266
	}
267
268
	/**
269
	 * Show the login form
270
	 *
271
	 * @codeCoverageIgnore
272
	 * @param string $status
273
	 * @return void
274
	 */
275
	public function login(string $status = '')
276
	{
277
		$message = '';
278
279
		$view = new HtmlView($this->container);
280
281
		if ($status !== '')
282
		{
283
			$message = $this->show_message($view, 'error', $status);
0 ignored issues
show
The method show_message() does not seem to exist on object<Aviat\AnimeClient\Controller>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
284
		}
285
286
		// Set the redirect url
287
		$this->set_session_redirect();
288
289
		$this->outputHTML('login', [
290
			'title' => 'Api login',
291
			'message' => $message
292
		], $view);
0 ignored issues
show
$view is of type object<Aviat\Ion\View\HtmlView>, but the function expects a object<HtmlView>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
293
	}
294
295
	/**
296
	 * Attempt login authentication
297
	 *
298
	 * @return void
299
	 */
300
	public function loginAction()
301
	{
302
		$auth = $this->container->get('auth');
303
		$post = $this->request->getParsedBody();
304
		if ($auth->authenticate($post['password']))
305
		{
306
			return $this->session_redirect();
307
		}
308
309
		$this->set_flash_message('Invalid username or password.');
310
		$this->redirect($this->urlGenerator->url('login'), 303);
311
	}
312
313
	/**
314
	 * Deauthorize the current user
315
	 *
316
	 * @return void
317
	 */
318
	public function logout()
319
	{
320
		$auth = $this->container->get('auth');
321
		$auth->logout();
322
323
		$this->redirectToDefaultRoute();
324
	}
325
326
	/**
327
	 * 404 action
328
	 *
329
	 * @return void
330
	 */
331
	public function notFound()
332
	{
333
		$this->outputHTML('404', [
334
			'title' => 'Sorry, page not found'
335
		], NULL, 404);
336
	}
337
338
	/**
339
	 * Display a generic error page
340
	 *
341
	 * @param int $http_code
342
	 * @param string $title
343
	 * @param string $message
344
	 * @param string $long_message
345
	 * @return void
346
	 */
347
	public function errorPage($http_code, $title, $message, $long_message = "")
348
	{
349
		$this->outputHTML('error', [
350
			'title' => $title,
351
			'message' => $message,
352
			'long_message' => $long_message
353
		], NULL, $http_code);
354
	}
355
356
	/**
357
	 * Set a session flash variable to display a message on
358
	 * next page load
359
	 *
360
	 * @param string $message
361
	 * @param string $type
362
	 * @return void
363
	 */
364
	public function set_flash_message($message, $type = "info")
365
	{
366
		$this->session->setFlash('message', [
367
			'message_type' => $type,
368
			'message' => $message
369
		]);
370
	}
371
372
	/**
373
	 * Purges the API cache
374
	 *
375
	 * @return void
376
	 */
377
	public function clearCache()
378
	{
379
		$this->cache->clear();
380
		$this->outputHTML('blank', [
381
			'title' => 'Cache cleared'
382
		], NULL, 200);
383
	}
384
385
	/**
386
	 * Add a message box to the page
387
	 *
388
	 * @codeCoverageIgnore
389
	 * @param HtmlView $view
390
	 * @param string $type
391
	 * @param string $message
392
	 * @return string
393
	 */
394
	protected function showMessage($view, $type, $message)
395
	{
396
		return $this->load_partial($view, 'message', [
397
			'message_type' => $type,
398
			'message'  => $message
399
		]);
400
	}
401
402
	/**
403
	 * Output a template to HTML, using the provided data
404
	 *
405
	 * @param string $template
406
	 * @param array $data
407
	 * @param HtmlView|null $view
408
	 * @param int $code
409
	 * @return void
410
	 */
411
	protected function outputHTML($template, array $data = [], $view = NULL, $code = 200)
412
	{
413
		if (is_null($view))
414
		{
415
			$view = new HtmlView($this->container);
416
		}
417
418
		$view->setStatusCode($code);
419
		$this->render_full_page($view, $template, $data);
0 ignored issues
show
It seems like $view can also be of type object<Aviat\Ion\View\HtmlView>; however, Aviat\AnimeClient\Controller::render_full_page() does only seem to accept object<HtmlView>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
420
	}
421
422
	/**
423
	 * Output a JSON Response
424
	 *
425
	 * @param mixed $data
426
	 * @param int $code - the http status code
427
	 * @return void
428
	 */
429
	protected function outputJSON($data = 'Empty response', int $code = 200)
430
	{
431
		(new JsonView($this->container))
432
			->setStatusCode($code)
433
			->setOutput($data)
434
			->send();
435
	}
436
437
	/**
438
	 * Redirect to the selected page
439
	 *
440
	 * @param string $url
441
	 * @param int $code
442
	 * @return void
443
	 */
444
	protected function redirect($url, $code)
445
	{
446
		$http = new HttpView($this->container);
447
		$http->redirect($url, $code);
448
	}
449
}
450
// End of BaseController.php