1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
<?php
/**
* Handler for module requests.
*
* This web page receives requests for web-pages hosted by modules, and directs them to
* the RequestHandler in the module.
*
* @author Olav Morken, UNINETT AS.
* @package SimpleSAMLphp
*/
require_once('_include.php');
// index pages - file names to attempt when accessing directories
$indexFiles = array('index.php', 'index.html', 'index.htm', 'index.txt');
// MIME types - key is file extension, value is MIME type
$mimeTypes = array(
'bmp' => 'image/x-ms-bmp',
'css' => 'text/css',
'gif' => 'image/gif',
'htm' => 'text/html',
'html' => 'text/html',
'shtml' => 'text/html',
'ico' => 'image/vnd.microsoft.icon',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'js' => 'text/javascript',
'pdf' => 'application/pdf',
'png' => 'image/png',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
'swf' => 'application/x-shockwave-flash',
'swfl' => 'application/x-shockwave-flash',
'txt' => 'text/plain',
'xht' => 'application/xhtml+xml',
'xhtml' => 'application/xhtml+xml',
);
if (empty($_SERVER['PATH_INFO'])) {
throw new SimpleSAML_Error_NotFound('No PATH_INFO to module.php');
}
$url = $_SERVER['PATH_INFO'];
assert('substr($url, 0, 1) === "/"');
/* clear the PATH_INFO option, so that a script can detect whether it is called with anything following the
*'.php'-ending.
*/
unset($_SERVER['PATH_INFO']);
$modEnd = strpos($url, '/', 1);
if ($modEnd === false) {
// the path must always be on the form /module/
throw new SimpleSAML_Error_NotFound('The URL must at least contain a module name followed by a slash.');
}
$module = substr($url, 1, $modEnd - 1);
$url = substr($url, $modEnd + 1);
if ($url === false) {
$url = '';
}
if (!SimpleSAML\Module::isModuleEnabled($module)) {
throw new SimpleSAML_Error_NotFound('The module \''.$module.'\' was either not found, or wasn\'t enabled.');
}
/* Make sure that the request isn't suspicious (contains references to current directory or parent directory or
* anything like that. Searching for './' in the URL will detect both '../' and './'. Searching for '\' will detect
* attempts to use Windows-style paths.
*/
if (strpos($url, '\\') !== false) {
throw new SimpleSAML_Error_BadRequest('Requested URL contained a backslash.');
} elseif (strpos($url, './') !== false) {
throw new SimpleSAML_Error_BadRequest('Requested URL contained \'./\'.');
}
$moduleDir = SimpleSAML\Module::getModuleDir($module).'/www/';
// check for '.php/' in the path, the presence of which indicates that another php-script should handle the request
for ($phpPos = strpos($url, '.php/'); $phpPos !== false; $phpPos = strpos($url, '.php/', $phpPos + 1)) {
$newURL = substr($url, 0, $phpPos + 4);
$param = substr($url, $phpPos + 4);
if (is_file($moduleDir.$newURL)) {
/* $newPath points to a normal file. Point execution to that file, and
* save the remainder of the path in PATH_INFO.
*/
$url = $newURL;
$_SERVER['PATH_INFO'] = $param;
break;
}
}
$path = $moduleDir.$url;
if ($path[strlen($path) - 1] === '/') {
// path ends with a slash - directory reference. Attempt to find index file in directory
foreach ($indexFiles as $if) {
if (file_exists($path.$if)) {
$path .= $if;
break;
}
}
}
if (is_dir($path)) {
/* Path is a directory - maybe no index file was found in the previous step, or maybe the path didn't end with
* a slash. Either way, we don't do directory listings.
*/
throw new SimpleSAML_Error_NotFound('Directory listing not available.');
}
if (!file_exists($path)) {
// file not found
SimpleSAML\Logger::info('Could not find file \''.$path.'\'.');
throw new SimpleSAML_Error_NotFound('The URL wasn\'t found in the module.');
}
if (preg_match('#\.php$#D', $path)) {
// PHP file - attempt to run it
/* In some environments, $_SERVER['SCRIPT_NAME'] is already set with $_SERVER['PATH_INFO']. Check for that case,
* and append script name only if necessary.
*
* Contributed by Travis Hegner.
*/
$script = "/$module/$url";
if (stripos($_SERVER['SCRIPT_NAME'], $script) === false) {
$_SERVER['SCRIPT_NAME'] .= '/'.$module.'/'.$url;
}
require($path);
exit();
}
// some other file type - attempt to serve it
// find MIME type for file, based on extension
$contentType = null;
if (preg_match('#\.([^/\.]+)$#D', $path, $type)) {
$type = strtolower($type[1]);
if (array_key_exists($type, $mimeTypes)) {
$contentType = $mimeTypes[$type];
}
}
if ($contentType === null) {
/* We were unable to determine the MIME type from the file extension. Fall back to mime_content_type (if it
* exists).
*/
if (function_exists('mime_content_type')) {
$contentType = mime_content_type($path);
} else {
// mime_content_type doesn't exist. Return a default MIME type
SimpleSAML\Logger::warning('Unable to determine mime content type of file: '.$path);
$contentType = 'application/octet-stream';
}
}
$contentLength = sprintf('%u', filesize($path)); // force filesize to an unsigned number
header('Content-Type: '.$contentType);
header('Content-Length: '.$contentLength);
header('Cache-Control: public,max-age=86400');
header('Expires: '.gmdate('D, j M Y H:i:s \G\M\T', time() + 10 * 60));
header('Last-Modified: '.gmdate('D, j M Y H:i:s \G\M\T', filemtime($path)));
readfile($path);
|