Completed
Push — develop ( 879d74...52dce9 )
by Seth
04:03
created

common.inc.php (8 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
require_once(__DIR__ . '/vendor/autoload.php');
4
5
define('SECRETS_FILE', __DIR__ . '/secrets.xml');
6
define('SCHEMA_FILE', __DIR__ . '/admin/schema-app.sql');
7
define('MYSQL_PREFIX', '');
8
9
use Battis\AppMetadata;
10
use smtech\StMarksSmarty\StMarksSmarty;
11
use Battis\BootstrapSmarty\NotificationMessage;
12
13
/**
14
 * Test if the app is in the middle of launching
15
 *
16
 * Wait for $toolProvider to be fully initialized before starting the app logic.
17
 *
18
 * @return boolean
19
 **/
20
function midLaunch() {
0 ignored issues
show
midLaunch 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);
    }
}
Loading history...
21
	global $metadata; // FIXME:0 grown-ups don't program like this issue:17
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 global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
22
	return $metadata['APP_LAUNCH_URL'] === (($_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']);
23
}
24
25
/**
26
 * Initialize a SimpleXMLElement from the SECRETS_FILE
27
 *
28
 * @return SimpleXMLElement
29
 *
30
 * @throws CanvasAPIviaLTI_Exception MISSING_SECRETS_FILE if the SECRETS_FILE cannot be found
31
 * @throws CanvasAPIviaLTI_Exception INVALID_SECRETS_FILE if the SECRETS_FILE exists, but cannot be parsed
32
 **/
33
function initSecrets() {
34
	if (file_exists(SECRETS_FILE)) {
35
		// http://stackoverflow.com/a/24760909 (oy!)
36
		if (($secrets = simplexml_load_string(file_get_contents(SECRETS_FILE))) !== false) {
37
			return $secrets;
38
		} else {
39
			throw new CanvasAPIviaLTI_Exception(
40
				SECRETS_FILE . ' could not be loaded. ',
41
				CanvasAPIviaLTI_Exception::INVALID_SECRETS_FILE
42
			);
43
		}
44
	} else {
45
		throw new CanvasAPIviaLTI_Exception(
46
			SECRETS_FILE . " could not be found.",
47
			CanvasAPIviaLTI_Exception::MISSING_SECRETS_FILE
48
		);
49
	}
50
}
51
52
/**
53
 * Initialize a mysqli connector using the credentials stored in SECRETS_FILE
54
 *
55
 * @uses initSecrets() If $secrets is not already initialized
56
 *
57
 * @return mysqli A valid mysqli connector to the database backing the CanvasAPIviaLTI instance
58
 *
59
 * @throws CanvasAPIviaLTI_Exception MYSQL_CONNECTION if a mysqli connection cannot be established
60
 **/
61
function initMySql() {
62
	global $secrets; // FIXME:0 grown-ups don't program like this issue:17
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 global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
63
	if (!($secrets instanceof SimpleXMLElement)) {
64
		$secrets = initSecrets();
65
	}
66
67
	/* turn off warnings, since we're going to test the connection ourselves */
68
	set_error_handler(function() {});
69
	$sql = new mysqli(
70
		(string) $secrets->mysql->host,
71
		(string) $secrets->mysql->username,
72
		(string) $secrets->mysql->password,
73
		(string) $secrets->mysql->database
74
	);
75
	restore_error_handler();
76
77
	if ($sql->connect_error) {
78
		throw new CanvasAPIviaLTI_Exception(
79
			$sql->connect_error,
80
			CanvasAPIviaLTI_Exception::MYSQL_CONNECTION
81
		);
82
	}
83
	return $sql;
84
}
85
86
/**
87
 * Initialize AppMetadata
88
 *
89
 * @return \Battis\AppMetadata
90
 **/
91
function initAppMetadata() {
92
	global $secrets; // FIXME:0 grown-ups don't program like this issue:17
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 global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
93
	global $sql; // FIXME:0 grown-ups don't program like this issue:17
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 global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
94
95
	$metadata = new AppMetadata($sql, (string) $secrets->app->id);
96
97
	return $metadata;
98
}
99
100
/**
101
 * Preformat `var_dump()`
102
 *
103
 * @param mixed $var
104
 *
105
 * @return void
106
 **/
107
function html_var_dump($var) {
108
	echo '<pre>';
109
	var_dump($var);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($var); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
110
	echo '</pre>';
111
}
112
113
/*****************************************************************************
114
 *                                                                           *
115
 * The script begins here                                                    *
116
 *                                                                           *
117
 *****************************************************************************/
118
119
/* assume everything's going to be fine... */
120
$ready = true;
121
122
/* preliminary interactive only initialization */
123
if (php_sapi_name() != 'cli') {
124
	session_start();
125
126
	/* fire up the templating engine for interactive scripts */
127
	$smarty = StMarksSmarty::getSmarty();
128
	$smarty->addTemplateDir(__DIR__ . '/templates', 'starter-canvas-api-via-lti');
129
	$smarty->setFramed(true);
130
}
131
132
/* initialization that needs to happen for interactive and CLI scripts */
133
try {
134
	/* initialize global variables */
135
	$secrets = initSecrets();
136
	$sql = initMySql();
137
	$metadata = initAppMetadata();
138
} catch (CanvasAPIviaLTI_Exception $e) {
139
	if (php_sapi_name() == 'cli') {
140
		echo 'Initialization Failure [' . $e->getCode() . ']' . PHP_EOL . $e->getMessage() . PHP_EOL;
141
		exit;
142
	} else {
143
		$smarty->addMessage(
144
			'Initialization Failure [' . $e->getCode() . ']',
145
			$e->getMessage(),
146
			NotificationMessage::ERROR
0 ignored issues
show
Deprecated Code introduced by
The constant Battis\BootstrapSmarty\NotificationMessage::ERROR has been deprecated with message: Use `DANGER` instead for consistency with Bootstrap

This class constant has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.

Loading history...
147
		);
148
		$smarty->display();
149
		exit;
150
	}
151
}
152
153
/* interactive initialization only */
154
if ($ready && php_sapi_name() != 'cli') {
155
156
	/* allow web apps to use common.inc.php without LTI authentication */
157
	if (!defined('IGNORE_LTI')) {
158
159
		try {
160
			if (midLaunch()) {
161
				$ready = false;
162
			} elseif (isset($_SESSION['toolProvider'])) {
163
				$toolProvider = $_SESSION['toolProvider'];
164
			} else {
165
				throw new CanvasAPIviaLTI_Exception(
166
					'The LTI launch request is missing',
167
					CanvasAPIviaLTI_Exception::LAUNCH_REQUEST
168
				);
169
			}
170
171
		} catch (CanvasAPIviaLTI_Exception $e) {
172
			$ready = false;
173
		}
174
	}
175
176
	if ($ready) {
177
		$smarty->addStylesheet($metadata['APP_URL'] . '/css/canvas-api-via-lti.css', 'starter-canvas-api-via-lti');
178
		$smarty->addStylesheet($metadata['APP_URL'] . '/css/app.css');
179
180
		if (!midLaunch() || !defined('IGNORE_LTI')) {
181
			require_once(__DIR__ . '/common-app.inc.php');
182
		}
183
	}
184
} elseif (php_sapi_name() == 'cli') {
185
	require_once(__DIR__ . '/common-app.inc.php');
186
}
187
188
189
?>
0 ignored issues
show
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
190