These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | require_once __DIR__ . '/vendor/autoload.php'; |
||
4 | |||
5 | use smtech\CanvasICSSync\Toolbox; |
||
6 | use smtech\ReflexiveCanvasLTI\LTI\ToolProvider; |
||
7 | use Battis\DataUtilities; |
||
8 | |||
9 | define('CONFIG_FILE', __DIR__ . '/config.xml'); |
||
10 | define('CANVAS_INSTANCE_URL', 'canvas_instance_url'); |
||
11 | |||
12 | @session_start(); // TODO I don't feel good about suppressing warnings |
||
0 ignored issues
–
show
|
|||
13 | |||
14 | /* prepare the toolbox */ |
||
15 | if (empty($_SESSION[Toolbox::class])) { |
||
16 | $_SESSION[Toolbox::class] =& Toolbox::fromConfiguration(CONFIG_FILE); |
||
17 | } |
||
18 | $toolbox =& $_SESSION[Toolbox::class]; |
||
19 | $toolbox->smarty_prependTemplateDir(__DIR__ . '/templates', basename(__DIR__)); |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
smtech\ReflexiveCanvasLTI\Toolbox as the method smarty_prependTemplateDir() does only exist in the following sub-classes of smtech\ReflexiveCanvasLTI\Toolbox : smtech\CanvasICSSync\Toolbox , smtech\StMarksReflexiveCanvasLTI\Toolbox . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
20 | $toolbox->smarty_assign([ |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
smtech\ReflexiveCanvasLTI\Toolbox as the method smarty_assign() does only exist in the following sub-classes of smtech\ReflexiveCanvasLTI\Toolbox : smtech\CanvasICSSync\Toolbox , smtech\StMarksReflexiveCanvasLTI\Toolbox . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
21 | 'category' => DataUtilities::titleCase(preg_replace('/[\-_]+/', ' ', basename(__DIR__))) |
||
22 | ]); |
||
23 | |||
24 | /* set the Tool Consumer's instance URL, if present */ |
||
25 | if (empty($_SESSION[CANVAS_INSTANCE_URL]) && |
||
26 | !empty($_SESSION[ToolProvider::class]['canvas']['api_domain']) |
||
27 | ) { |
||
28 | $_SESSION[CANVAS_INSTANCE_URL] = 'https://' . $_SESSION[ToolProvider::class]['canvas']['api_domain']; |
||
29 | } |
||
30 | |||
31 | /* argument values for sync */ |
||
32 | define('SCHEDULE_ONCE', 'once'); |
||
33 | define('SCHEDULE_WEEKLY', 'weekly'); |
||
34 | define('SCHEDULE_DAILY', 'daily'); |
||
35 | define('SCHEDULE_HOURLY', 'hourly'); |
||
36 | define('SCHEDULE_CUSTOM', 'custom'); |
||
37 | |||
38 | define('LOCAL_TIMEZONE', 'US/Eastern'); // TODO:0 Can we detect the timezone for the Canvas instance and use it? issue:18 |
||
39 | define('SEPARATOR', '_'); // used when concatenating information in the cache database |
||
40 | define('CANVAS_TIMESTAMP_FORMAT', 'Y-m-d\TH:iP'); |
||
41 | define('SYNC_TIMESTAMP_FORMAT', 'Y-m-d\TH:iP'); // same as CANVAS_TIMESTAMP_FORMAT, FWIW |
||
42 | |||
43 | define('VALUE_OVERWRITE_CANVAS_CALENDAR', 'overwrite'); |
||
44 | define('VALUE_ENABLE_REGEXP_FILTER', 'enable_filter'); |
||
45 | |||
46 | /* cache database tables */ |
||
47 | |||
48 | /* calendars |
||
49 | id hash of ICS and Canvas pairing, generated by getPairingHash() |
||
50 | ics_url URL of ICS feed |
||
51 | canvas_url canonical URL for Canvas object |
||
52 | synced sync identification, generated by getSyncTimestamp() |
||
53 | modified timestamp of last modificiation of the record |
||
54 | */ |
||
55 | |||
56 | /* events |
||
57 | id auto-incremented cache record id |
||
58 | calendar pair hash for cached calendar, generated by getPairingHash() |
||
59 | calendar_event[id] Canvas ID of calendar event |
||
60 | event_hash hash of cached event data from previous sync |
||
61 | synced sync identification, generated by getSyncTimestamp() |
||
62 | modified timestamp of last modification of the record |
||
63 | */ |
||
64 | |||
65 | /* schedules |
||
66 | id auto-incremented cache record id |
||
67 | calendar pair hash for cached calendar, generated by getPairingHash() |
||
68 | crontab crontab data for scheduled synchronization |
||
69 | synced sync identification, generated by getSyncTimestamp() |
||
70 | modified timestamp of last modification of the record |
||
71 | */ |
||
72 | |||
73 | function postMessage($subject, $body, $flag = NotificationMessage::INFO) |
||
74 | { |
||
75 | global $toolbox; |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
![]() |
|||
76 | if (php_sapi_name() != 'cli') { |
||
77 | $toolbox->smarty_addMessage($subject, $body, $flag); |
||
78 | } else { |
||
79 | $logEntry = "[$flag] $subject: $body"; |
||
80 | $toolbox->log($logEntry); |
||
81 | } |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * Generate a unique ID to identify this particular pairing of ICS feed and |
||
86 | * Canvas calendar |
||
87 | **/ |
||
88 | function getPairingHash($icsUrl, $canvasContext) |
||
89 | { |
||
90 | global $metadata; |
||
91 | return md5($icsUrl . $canvasContext . $metadata['CANVAS_INSTANCE_URL']); |
||
92 | } |
||
93 | |||
94 | $FIELD_MAP = array( |
||
95 | 'calendar_event[title]' => 'SUMMARY', |
||
96 | 'calendar_event[description]' => 'DESCRIPTION', |
||
97 | 'calendar_event[start_at]' => array ( |
||
98 | 0 => 'X-CURRENT-DTSTART', |
||
99 | 1 => 'DTSTART' |
||
100 | ), |
||
101 | 'calendar_event[end_at]' => array( |
||
102 | 0 => 'X-CURRENT-DTEND', |
||
103 | 1 => 'DTEND' |
||
104 | ), |
||
105 | 'calendar_event[location_name]' => 'LOCATION' |
||
106 | ); |
||
107 | |||
108 | /** |
||
109 | * Generate a hash of this version of an event to cache in the database |
||
110 | **/ |
||
111 | function getEventHash($event) |
||
112 | { |
||
113 | global $FIELD_MAP; |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
![]() |
|||
114 | $blob = ''; |
||
115 | foreach ($FIELD_MAP as $field) { |
||
116 | if (is_array($field)) { |
||
117 | foreach ($field as $option) { |
||
118 | if (!empty($property = $event->getProperty($option))) { |
||
119 | $blob .= serialize($property); |
||
120 | break; |
||
121 | } |
||
122 | } |
||
123 | } else { |
||
124 | if (!empty($property = $event->getProperty($field))) { |
||
125 | $blob .= serialize($property); |
||
126 | } |
||
127 | } |
||
128 | } |
||
129 | return md5($blob); |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * Generate a unique identifier for this synchronization pass |
||
134 | **/ |
||
135 | $SYNC_TIMESTAMP = null; |
||
136 | function getSyncTimestamp() |
||
0 ignored issues
–
show
getSyncTimestamp uses the super-global variable $_SERVER which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
![]() |
|||
137 | { |
||
138 | global $SYNC_TIMESTAMP; |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
![]() |
|||
139 | if ($SYNC_TIMESTAMP) { |
||
140 | return $SYNC_TIMESTAMP; |
||
141 | } else { |
||
142 | $timestamp = new DateTime(); |
||
143 | $SYNC_TIMESTAMP = $timestamp->format(SYNC_TIMESTAMP_FORMAT) . SEPARATOR . |
||
144 | md5((php_sapi_name() == 'cli' ? 'cli' : $_SERVER['REMOTE_ADDR']) . time()); |
||
145 | return $SYNC_TIMESTAMP; |
||
146 | } |
||
147 | } |
||
148 |
If you suppress an error, we recommend checking for the error condition explicitly: