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 | #!/usr/bin/env php |
||
2 | <?php |
||
3 | |||
4 | define('IGNORE_UI', true); |
||
5 | |||
6 | require_once __DIR__ . '/../common.inc.php'; |
||
7 | require_once __DIR__ . '/../constants.inc.php'; |
||
8 | |||
9 | use smtech\GradingAnalytics\Toolbox; |
||
10 | use smtech\CanvasPest\CanvasPest; |
||
11 | |||
12 | // http://stackoverflow.com/a/21896310 |
||
13 | function hoursRange($lower = 0, $upper = 86400, $step = 3600, $keyFormat = '', $value = '', $valueIsFormat = false) |
||
14 | { |
||
15 | $times = array(); |
||
16 | |||
17 | if (empty( $value ) && $valueIsFormat) { |
||
18 | $value = 'g:i a'; |
||
19 | } |
||
20 | |||
21 | if (empty($keyFormat)) { |
||
22 | $keyFormat = 'g:i a'; |
||
23 | } |
||
24 | |||
25 | foreach (range( $lower, $upper, $step ) as $increment) { |
||
26 | $increment = gmdate( $keyFormat, $increment ); |
||
27 | |||
28 | list( $hour, $minutes ) = explode( ':', $increment ); |
||
29 | |||
30 | $date = new DateTime( $hour . ':' . $minutes ); |
||
31 | |||
32 | $times[(string) $increment] = ($valueIsFormat ? $date->format( $value ) : $value); |
||
33 | } |
||
34 | |||
35 | return $times; |
||
36 | } |
||
37 | |||
38 | function collectStatistics($term, Toolbox $toolbox) |
||
39 | { |
||
40 | $courses = $toolbox->api_get( |
||
41 | '/accounts/' . $toolbox->config(Toolbox::TOOL_CANVAS_ACCOUNT_ID) . '/courses', |
||
42 | array( |
||
43 | 'with_enrollments' => 'true', |
||
44 | 'enrollment_term_id' => $term |
||
45 | ) |
||
46 | ); |
||
47 | |||
48 | // so that everything has a consistent benchmark |
||
49 | $timestamp = time(); |
||
50 | |||
51 | foreach ($courses as $course) { |
||
0 ignored issues
–
show
|
|||
52 | $statistic = array( |
||
53 | 'timestamp' => date(DATE_ISO8601, $timestamp), |
||
54 | 'course[id]' => $course['id'], |
||
55 | 'course[name]' => $course['name'], |
||
56 | 'course[account_id]' => $course['account_id'], |
||
57 | 'gradebook_url' => $_SESSION[CANVAS_INSTANCE_URL] . "/courses/{$course['id']}/gradebook2", |
||
58 | 'assignments_due_count' => 0, |
||
59 | 'dateless_assignment_count' => 0, |
||
60 | 'created_after_due_count' => 0, |
||
61 | 'gradeable_assignment_count' => 0, |
||
62 | 'graded_assignment_count' => 0, |
||
63 | 'zero_point_assignment_count' => 0, |
||
64 | 'analytics_page' => $_SESSION[CANVAS_INSTANCE_URL] . "/courses/{$course['id']}/external_tools/" . $toolbox->config(Toolbox::TOOL_CANVAS_EXTERNAL_TOOL_ID) |
||
65 | ); |
||
66 | |||
67 | $teacherIds = array(); |
||
68 | $teacherNames = array(); |
||
69 | $teachers = $toolbox->api_get( |
||
70 | "/courses/{$course['id']}/enrollments", |
||
71 | array( |
||
72 | 'type[]' => 'TeacherEnrollment' |
||
73 | ) |
||
74 | ); |
||
75 | foreach ($teachers as $teacher) { |
||
0 ignored issues
–
show
The expression
$teachers of type object<smtech\CanvasPest...CanvasPest\CanvasArray> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
76 | $teacherIds[] = $teacher['user']['id']; |
||
77 | $teacherNames[] = $teacher['user']['sortable_name']; |
||
78 | } |
||
79 | $statistic['teacher[id]s'] = serialize($teacherIds); |
||
80 | $statistic['teacher[sortable_name]s'] = serialize($teacherNames); |
||
81 | |||
82 | $account = $toolbox->api_get("/accounts/{$course['account_id']}"); |
||
83 | $statistic['account[name]'] = $account['name']; |
||
84 | |||
85 | // ignore classes with no teachers (how do they even exist? weird.) |
||
86 | if (count($teacherIds) != 0) { |
||
87 | $statistic['student_count'] = 0; |
||
88 | $students = $toolbox->api_get( |
||
89 | "/courses/{$course['id']}/enrollments", |
||
90 | array( |
||
91 | 'type[]' => 'StudentEnrollment' |
||
92 | ) |
||
93 | ); |
||
94 | $statistic['student_count'] = $students->count(); |
||
0 ignored issues
–
show
The method
count does only exist in smtech\CanvasPest\CanvasArray , but not in smtech\CanvasPest\CanvasObject .
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
![]() |
|||
95 | |||
96 | // ignore classes with no students |
||
97 | if ($statistic['student_count'] != 0) { |
||
98 | $assignments = $toolbox->api_get( |
||
99 | "/courses/{$course['id']}/assignments" |
||
100 | ); |
||
101 | |||
102 | $gradedSubmissionsCount = 0; |
||
103 | $turnAroundTimeTally = 0; |
||
104 | $leadTimeTally = 0; |
||
105 | $createdModifiedHistogram = array( |
||
106 | HISTOGRAM_CREATED => hoursRange(0, 86400, 3600, '', 0), |
||
107 | HISTOGRAM_MODIFIED => hoursRange(0, 86400, 3600, '', 0) |
||
108 | ); |
||
109 | |||
110 | foreach ($assignments as $assignment) { |
||
0 ignored issues
–
show
The expression
$assignments of type object<smtech\CanvasPest...CanvasPest\CanvasArray> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
111 | // ignore unpublished assignments |
||
112 | if ($assignment['published'] == true) { |
||
113 | // check for due dates |
||
114 | $dueDate = new DateTime($assignment['due_at']); |
||
115 | $dueDate->setTimeZone(new DateTimeZone(SCHOOL_TIME_ZONE)); |
||
116 | if (($timestamp - $dueDate->getTimestamp()) > 0) { |
||
117 | $statistic['assignments_due_count']++; |
||
118 | |||
119 | // update created_modified_histogram |
||
120 | $createdAt = new DateTime($assignment['created_at']); |
||
121 | $createdAt->setTimeZone(new DateTimeZone(SCHOOL_TIME_ZONE)); |
||
122 | $updatedAt = new DateTime($assignment['updated_at']); |
||
123 | $updatedAt->setTimeZone(new DateTimeZone(SCHOOL_TIME_ZONE)); |
||
124 | $createdModifiedHistogram[HISTOGRAM_CREATED][$createdAt->format('g:00 a')]++; |
||
125 | if ($createdAt != $updatedAt) { |
||
126 | $createdModifiedHistogram[HISTOGRAM_MODIFIED][$updatedAt->format('g:00 a')]++; |
||
127 | } |
||
128 | |||
129 | // tally lead time on the assignment |
||
130 | $leadTimeTally += strtotime($assignment['due_at']) - strtotime($assignment['created_at']); |
||
131 | |||
132 | // was the assignment created after it was due? |
||
133 | if (strtotime($assignment['due_at']) < strtotime($assignment['created_at'])) { |
||
134 | $statistic['created_after_due_count']++; |
||
135 | } |
||
136 | |||
137 | // ignore ungraded assignments |
||
138 | if ($assignment['grading_type'] != 'not_graded') { |
||
139 | $statistic['gradeable_assignment_count']++; |
||
140 | $hasBeenGraded = false; |
||
141 | |||
142 | // tally zero point assignments |
||
143 | if ($assignment['points_possible'] == '0') { |
||
144 | $statistic['zero_point_assignment_count']++; |
||
145 | } |
||
146 | |||
147 | // build submission statistic |
||
148 | $submissions = $toolbox->api_get( |
||
149 | "/courses/{$course['id']}/assignments/{$assignment['id']}/submissions" |
||
150 | ); |
||
151 | foreach ($submissions as $submission) { |
||
0 ignored issues
–
show
The expression
$submissions of type object<smtech\CanvasPest...CanvasPest\CanvasArray> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
152 | if ($submission['workflow_state'] == 'graded') { |
||
153 | if ($hasBeenGraded == false) { |
||
154 | $hasBeenGraded = true; |
||
155 | $statistic['graded_assignment_count']++; |
||
156 | } |
||
157 | $gradedSubmissionsCount++; |
||
158 | $turnAroundTimeTally += max( |
||
159 | 0, |
||
160 | strtotime($submission['graded_at']) - strtotime($assignment['due_at']) |
||
161 | ); |
||
162 | } |
||
163 | } |
||
164 | |||
165 | if (!$hasBeenGraded) { |
||
166 | if (array_key_exists('oldest_ungraded_assignment_due_date', $statistic)) { |
||
167 | if (strtotime($assignment['due_at']) < strtotime($statistic['oldest_ungraded_assignment_due_date'])) { |
||
168 | $statistic['oldest_ungraded_assignment_due_date'] = $assignment['due_at']; |
||
169 | $statistic['oldest_ungraded_assignment_url'] = $assignment['html_url']; |
||
170 | $statistic['oldest_ungraded_assignment_name'] = $assignment['name']; |
||
171 | } |
||
172 | } else { |
||
173 | $statistic['oldest_ungraded_assignment_due_date'] = $assignment['due_at']; |
||
174 | $statistic['oldest_ungraded_assignment_url'] = $assignment['html_url']; |
||
175 | $statistic['oldest_ungraded_assignment_name'] = $assignment['name']; |
||
176 | } |
||
177 | } |
||
178 | } |
||
179 | } else { |
||
180 | $statistic['dateless_assignment_count']++; |
||
181 | } |
||
182 | } |
||
183 | } |
||
184 | |||
185 | $statistic['created_modified_histogram'] = serialize($createdModifiedHistogram); |
||
186 | |||
187 | // calculate average submissions graded per assignment (if non-zero) |
||
188 | if ($statistic['gradeable_assignment_count'] && $statistic['student_count']) { |
||
189 | $statistic['average_submissions_graded'] = $gradedSubmissionsCount / ($statistic['gradeable_assignment_count'] * $statistic['student_count']); |
||
190 | } |
||
191 | |||
192 | // calculate the average lead-time on assignments |
||
193 | if ($statistic['assignments_due_count']) { |
||
194 | $statistic['average_assignment_lead_time'] = $leadTimeTally / $statistic['assignments_due_count'] / 60 / 60 / 24; |
||
195 | } |
||
196 | |||
197 | // calculate average grading turn-around per submission |
||
198 | if ($gradedSubmissionsCount) { |
||
199 | $statistic['average_grading_turn_around'] = $turnAroundTimeTally / $gradedSubmissionsCount / 60 / 60 / 24; |
||
200 | } |
||
201 | |||
202 | $query = "INSERT INTO `course_statistics`"; |
||
203 | $fields = array(); |
||
204 | $values = array(); |
||
205 | while (list($field, $value) = each($statistic)) { |
||
206 | $fields[] = $field; |
||
207 | $values[] = $value; |
||
208 | } |
||
209 | $query .= ' (`' . implode('`, `', $fields) . "`) VALUES ('" . implode("', '", $values) . "')"; |
||
210 | $result = $toolbox->mysql_query($query); |
||
211 | } |
||
212 | } |
||
213 | } |
||
214 | } |
||
215 | |||
216 | /* force API configuration from config file */ |
||
217 | $toolbox->setApi(new CanvasPest( |
||
218 | $_SESSION[CANVAS_INSTANCE_URL] . '/api/v1', |
||
219 | $toolbox->config(Toolbox::TOOL_CANVAS_API)['token'] |
||
220 | )); |
||
221 | |||
222 | /* collect data on terms currently in session */ |
||
223 | try { |
||
224 | $terms = $toolbox->api_get('accounts/1/terms'); |
||
225 | $now = strtotime('now'); |
||
226 | foreach ($terms['enrollment_terms'] as $term) { |
||
227 | if (isset($term['start_at']) && isset($term['end_at'])) { |
||
228 | if ((strtotime($term['start_at']) <= $now) && ($now <= strtotime($term['end_at']))) { |
||
229 | collectStatistics($term['id'], $toolbox); |
||
230 | } |
||
231 | } |
||
232 | } |
||
233 | } catch (Exception $e) { |
||
234 | echo $e->getMessage(); |
||
235 | } |
||
236 |
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.