Issues (103)

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.

app/controllers/LeagueAdminController.php (10 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
2
3
/**
4
 * League admin controller
5
 *
6
 * Class LeagueAdminController
7
 */
8
class LeagueAdminController extends PageController {
0 ignored issues
show
The property $league_settings_rules is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
The property $team_valiation_rules is not named in camelCase.

This check marks property names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
9
10
	/**
11
	 * League settings validation rules
12
	 *
13
	 * @var array
14
	 */
15
	public $league_settings_rules = [
16
		'name'        => ['required', 'max:255'],
17
		'description' => ['required'],
18
		'url'         => ['url'],
19
		'private'     => ['boolean'],
20
21
		'money'       => ['required', 'integer'],
22
		'units'       => ['required', 'max:16'],
23
		'extra_weeks' => ['required', 'integer', 'between:1,12'],
24
	];
25
26
	/**
27
	 * League settings page
28
	 *
29
	 * @param League $league
30
	 */
31
	public function settings(League $league) {
32
		$league->load('admins');
33
34
		$this->layout->content = View::make('league.admin.settings', compact('league'));
35
		$this->layout->content->validation_rules = $this->league_settings_rules;
36
	}
37
38
	/**
39
	 * Updating league settings page
40
	 *
41
	 * @param League $league
42
	 *
43
	 * @return $this|\Illuminate\Http\RedirectResponse
44
	 */
45
	public function storeSettings(League $league) {
46
		$validator = Validator::make(Input::all(), $this->league_settings_rules);
47
48
		if ($validator->fails()) {
49
			Notification::error('Duder, check your input');
50
51
			return Redirect::back()->withInput()->withErrors($validator);
52
		}
53
54
		// Overwrites
55
		$league->fill(Input::only([
56
			'name', 'description', 'url', 'money', 'units', 'extra_weeks'
57
		]));
58
		$league->private = Input::get('private') ? true : false;
59
60
		if ($league->save()) {
61
			// TODO: End date checking
62
63
			Notification::success('Changes saved!');
64
65
			return Redirect::route('league.admin.settings', ['league' => $league->slug]);
66
		} else {
67
			Notification::error('Database error, try again later!');
68
69
			return Redirect::back()->withInput();
70
		}
71
	}
72
73
	/**
74
	 * List league's movies
75
	 *
76
	 * @param League $league
77
	 */
78
	public function movies(League $league) {
79
		$league->load(['movies' => function ($query) {
80
			/** @var \Illuminate\Database\Eloquent\Builder|Movie $query */
81
			$query->ordered();
82
		}, 'movies.movie']);
83
84
		$this->layout->content = View::make('league.admin.movies', compact('league'));
85
	}
86
87
	/**
88
	 * List movies that can be added to the league
89
	 *
90
	 * @param League $league
91
	 */
92
	public function addableMovies(League $league) {
93
		$show_past = (bool)Input::get('show_past',false);
94
		list($date_range, $movies) = $this->getAddableMovies($league,array(),$show_past);
95
96
		$this->layout->content = View::make('league.admin.addmovies', compact('league', 'movies', 'date_range','show_past'));
97
	}
98
99
100
	/**
101
	 * Add movies to a league
102
	 *
103
	 * @param League $league
104
	 *
105
	 * @return \Illuminate\Http\RedirectResponse
106
	 */
107
	public function addMovies(League $league) {
108
		$movie_ids = Input::get('movie');
109
		$show_past = Input::get('show_past',false);
110
		if (count($movie_ids) == 0) {
111
			Notification::error('Please choose movies to add');
112
113
			return Redirect::back();
114
		}
115
116
		list($date_range, $movies) = $this->getAddableMovies($league, $movie_ids,$show_past);
0 ignored issues
show
The assignment to $date_range is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
117
118
		/** @type Movie $movie */
119
		foreach ($movies as $movie) {
120
			$league->movies()->create(['movie_id' => $movie->id, 'latest_earnings_id' => $movie->latest_earnings_id]);
121
		}
122
123
		$league->updateLeagueDates();
124
		$league->save();
125
126
		Notification::success(count($movies) . ' movie(s) have been added!');
127
128
		return Redirect::route('league.admin.movies', ['league' => $league->slug]);
129
	}
130
131
132
	/**
133
	 * Removes a LeagueMovie from the league
134
	 *
135
	 * @param League $league
136
	 *
137
	 * @return \Illuminate\Http\RedirectResponse
138
	 */
139
	public function removeMovie(League $league) {
140
141
		$movie_id = intval(Input::get('movie'));
142
143
		/** @var LeagueMovie $movie */
144
		if (! $movie_id || ! ($movie = $league->movies()->find($movie_id))) {
145
			Notification::error('Movie not found');
146
147
			return Redirect::back();
148
		}
149
150
		$movie->delete();
151
		$league->updateLeagueDates();
152
		$league->save();
153
154
		Notification::success('Movie removed from the league');
155
156
		return Redirect::back();
157
	}
158
159
	/**
160
	 * Get moves that can be added by the league, optionally filtered by ID's
161
	 *
162
	 * @param League $league
163
	 * @param array  $ids
0 ignored issues
show
There is no parameter named $ids. 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 $italy is not defined by the method finale(...).

/**
 * @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...
164
	 *
165
	 * @return array
166
	 */
167
	protected function getAddableMovies(League $league, $movie_ids = [],$show_past = false) {
0 ignored issues
show
Coding Style Naming introduced by
The parameter $movie_ids is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
Coding Style Naming introduced by
The parameter $show_past is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
168
169
		$query = Movie::query();
170
		if ($show_past)
171
		{
172
			$date_range = [Carbon::now()->subYear(),Carbon::now()];
173
			$query->orderBy('release', 'desc');		
174
		}
175
		else
176
		{
177
			$date_range = [Carbon::now(), $league->maxLastMovieDate()];
178
		}
179
180
		if (count($movie_ids)) {
181
			$query->whereIn('id', $movie_ids);
182
		}
183
		// Remove movies already added
184
		if ($league->movies->count()) {
185
			$query->whereNotIn('id', $league->movies->fetch('movie_id')->toArray());
186
		} else {
187
			// If no movies set start date to a more saner value
188
			$date_range[1] = Carbon::now()->addWeeks(Config::get('draft.maximum_weeks'));
189
		}
190
		$query->whereBetween('release', $date_range);
191
		$query->whereNotNull(Config::get('draft.source') . '_id');
192
		$query->orderBy('release', 'asc');
193
194
		$movies = $query->get();
195
196
		return [$date_range, $movies];
197
	}
198
199
	public $team_valiation_rules = [
200
		'username'  => ['required', 'exists:users,username'],
201
		'team_name' => ['required', 'between:1,64'],
202
	];
203
204
	/**
205
	 * Show user's teams
206
	 *
207
	 * @param League $league
208
	 */
209
	public function teams(League $league) {
210
		$validation_rules = $this->team_valiation_rules;
211
212
		$league->load('teams', 'teams.users');
213
214
		$this->layout->content = View::make('league.admin.teams', compact('league', 'validation_rules'));
215
	}
216
217
218
	/**
219
	 * Add a team to the league
220
	 *
221
	 * @param League $league
222
	 *
223
	 * @return $this|\Illuminate\Http\RedirectResponse
224
	 */
225
	public function addTeam(League $league) {
226
		$validation = Validator::make(Input::all(), $this->team_valiation_rules);
227
		if ($validation->fails()) {
228
			Notification::error('Please check your input and try again');
229
230
			return Redirect::back()->withInput()->withErrors($validation);
231
		}
232
233
		$user = User::whereUsername(Input::get('username'))->first();
0 ignored issues
show
The method first does only exist in Illuminate\Database\Query\Builder, but not in User.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
234
235
		// Check if user is already in a team
236
		$check = DB::table('league_teams')
237
		           ->where('league_teams.league_id', $league->id)
238
		           ->join('league_team_user', 'league_teams.id', '=', 'league_team_user.league_team_id')
239
		           ->where('league_team_user.user_id', $user->id)->count();
240
241
		if ($check) {
242
			Notification::error('This user is already in a team in this league');
243
244
			return Redirect::back()->withInput();
245
		}
246
247
		// All good
248
		DB::beginTransaction();
249
250
		/** @type LeagueTeam $team */
251
		$team = $league->teams()->create(['name' => Input::get('team_name')]);
252
		$team->users()->attach($user->id);
253
254
		DB::commit();
255
256
		Notification::success('Team has been added to your league!');
257
258
		return Redirect::back();
259
	}
260
261
	/**
262
	 * Removing a team from the league.
263
	 *
264
	 * @param League $league
265
	 *
266
	 * @return \Illuminate\Http\RedirectResponse
267
	 * @throws Exception
268
	 */
269
	public function removeTeam(League $league) {
270
		/** @type LeagueTeam $team */
271
		$team = $league->teams()->where('id', Input::get('team'))->first();
272
273
		if (! $team) {
274
			Notification::error('Team not found');
275
276
			return Redirect::back();
277
		}
278
279
		$team->delete();
280
281
		Notification::success('Team has been removed');
282
283
		return Redirect::back();
284
	}
285
286
287
	/**
288
	 * Get league drafting page
289
	 *
290
	 * @param League $league
291
	 *
292
	 * @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
293
	 */
294
	public function draft(League $league) {
295
		$league->load(['movies' => function($query) {
296
			$query->ordered();
297
		}, 'movies.movie', 'movies.teams', 'teams']);
298
299
		if ($league->movies->count() == 0) {
300
			Notification::error('You need to add more movies before being able to draft');
301
302
			return Redirect::route('league.admin.movies', ['league' => $league->slug]);
303
		}
304
		if ($league->teams->count() == 0) {
305
			Notification::error('You need to add more teams before being able to draft');
306
307
			return Redirect::route('league.admin.teams', ['league' => $league->slug]);
308
		}
309
310
		// Prepend a no team element
311
		$teams = [0 => '(No team)'] + ['Teams' => $league->teams->lists('name', 'id')];
312
313
		// Create a movies array that has the team which owns it ID
314
		$movies = $league->movies->reduce(function ($data, LeagueMovie $movie) {
315
			$data[$movie->id] = [
316
				'movie'   => $movie->movie,
317
				'price'   => $movie->price,
318
				'team_id' => $movie->teams->first() ? $movie->teams->first()->id : null
319
			];
320
321
			return $data;
322
		}, []);
323
324
		$this->layout->content = View::make('league.admin.draft', compact('league', 'movies', 'teams'));
325
326
		return $this->layout;
327
	}
328
329
	/**
330
	 * Save league drafting changes
331
	 *
332
	 * @param League $league
333
	 *
334
	 * @return \Illuminate\Http\RedirectResponse
335
	 */
336
	public function storeDraft(League $league) {
337
		$league->load('movies', 'movies.movie', 'movies.teams', 'teams');
338
339
		$movies = $league->movies;
340
		$teams = $league->teams;
341
342
		$input = Input::get('movie');
343
		if(!is_array($input)) {
344
			App::error(403);
345
		}
346
		$changes = 0;
347
348
		foreach ($input as $movie_id => $post_data) {
0 ignored issues
show
The expression $input of type object|integer|double|string|null|boolean|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. 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:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
349
			/** @type LeagueMovie $movie */
350
			$movie = $movies->find($movie_id);
351
			if (! $movie) continue;
352
353
			// Price
354
			$movie->price = $post_data['price'];
355
			if ($movie->isDirty()) {
356
				$changes++;
357
				$movie->save();
358
			}
359
360
			// Team
361
			$current_team = (! $movie->teams->isEmpty()) ? $movie->teams->first()->id : 0;
362
363
			// If there's a change detected and the new team is valid
364
			if ($post_data['team_id'] != $current_team && (
365
					$post_data['team_id'] == 0 || ($new_team = $teams->find($post_data['team_id']))
366
				)
367
			) {
368
				/** @type LeagueTeam $new_team */
369
				DB::beginTransaction();
370
371
				// Remove old team
372
				if(! $movie->teams->isEmpty()) {
373
					$movie->teams()->detach($current_team);
374
				}
375
				// Add new team
376
				if(isset($new_team)) {
377
					$movie->teams()->attach($new_team);
378
				}
379
380
				$changes++;
381
				DB::commit();
382
			}
383
384
		}
385
386
		Notification::success("{$changes} changes have been saved!");
387
388
		// Active league check
389
		$active_check = DB::table('league_team_movies')->whereIn('league_team_id', $teams->modelKeys())->count();
390
391
		$league->active = $active_check ? 1 : 0;
392
		if($league->isDirty('active')) {
393
			$league->save();
394
395
			if($league->active) {
396
				Notification::success('Your league is now considered active! Happy Drafting!');
397
			} else {
398
				Notification::warning('Your league is no longer considered active.');
399
			}
400
		}
401
402
		return Redirect::back();
403
	}
404
405
	/**
406
	 * Display admins for the league
407
	 *
408
	 * @param League $league
409
	 */
410
	public function admins(League $league) {
411
		$this->layout->content = View::make('league.admin.admins', compact('league'));
412
	}
413
414
	/**
415
	 * Add admins to the league
416
	 *
417
	 * @param League $league
418
	 *
419
	 * @return \Illuminate\Http\RedirectResponse
420
	 */
421
	public function addAdmin(League $league) {
422
		$user = User::whereUsername(Input::get('username'))->first();
0 ignored issues
show
The method first does only exist in Illuminate\Database\Query\Builder, but not in User.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
423
424
		if (! $user) {
425
			Notification::error('User not found');
426
427
			return Redirect::back()->withInput();
428
		}
429
		if (! $league->admins()->where('users.id', $user->id)->count()) {
430
			$league->admins()->attach($user);
431
432
			Notification::success('Admin added');
433
		} else {
434
			Notification::warning('User is already an admin');
435
		}
436
437
		return Redirect::back();
438
	}
439
440
	/**
441
	 * Remove an admin from the league
442
	 *
443
	 * @param League $league
444
	 *
445
	 * @return \Illuminate\Http\RedirectResponse
446
	 */
447
	public function removeAdmin(League $league) {
448
		$user = $league->admins()->where('users.id', Input::get('user'))->first();
449
450
		if (! $user) {
451
			Notification::warning('User isn\'t an admin');
452
		} elseif ($user->id == Auth::user()->id) {
453
			Notification::error('You can\'t remove yourself');
454
		} else {
455
			$league->admins()->detach($user->id);
456
			Notification::success('User removed from admins');
457
		}
458
459
		return Redirect::back();
460
	}
461
462
463
}