Skip to content

Commit 13384dd

Browse files
committed
Module framework for request handling.
git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@809 44740490-163a-0410-bde0-09ae8108e29a
1 parent 85e4dea commit 13384dd

3 files changed

Lines changed: 265 additions & 39 deletions

File tree

lib/SimpleSAML/Module.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,23 @@ public static function resolveClass($id, $type, $subclass = NULL) {
129129
return $className;
130130
}
131131

132+
133+
/**
134+
* Get absolute URL to a specified module resource.
135+
*
136+
* This function creates an absolute URL to a resource stored under ".../modules/<module>/www/".
137+
*
138+
* @param string $resource Resource path, on the form "<module name>/<resource>"
139+
* @return string The absolute URL to the given resource.
140+
*/
141+
public static function getModuleURL($resource) {
142+
assert('is_string($resource)');
143+
assert('$resource[0] !== "/"');
144+
145+
$config = SimpleSAML_Configuration::getInstance();
146+
return SimpleSAML_Utilities::selfURLhost() . '/' . $config->getBaseURL() . 'module.php/' . $resource;
147+
}
148+
132149
}
133150

134151
?>

lib/SimpleSAML/XHTML/Template.php

Lines changed: 102 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,8 @@ private function getLanguageList() {
190190
*/
191191
private function includeAtTemplateBase($file) {
192192
$data = $this->data;
193-
$filename = $this->configuration->getPathValue('templatedir') . $this->configuration->getValue('theme.use') . '/' . $file;
194193

195-
if (!file_exists($filename)) {
196-
197-
SimpleSAML_Logger::error($_SERVER['PHP_SELF'].' - Template: Could not find template file [' . $file .
198-
'] at [' . $filename . '] - Now trying at base');
199-
200-
$filename = $this->configuration->getPathValue('templatedir') . $this->configuration->getValue('theme.base') . '/' . $file;
201-
if (!file_exists($filename)) {
202-
SimpleSAML_Logger::error($_SERVER['PHP_SELF'].' - Template: Could not find template file [' . $file .
203-
'] at [' . $filename . ']');
204-
throw new Exception('Could not load template file [' . $file . ']');
205-
}
206-
207-
}
194+
$filename = $this->findTemplatePath($file);
208195

209196
include($filename);
210197
}
@@ -223,8 +210,16 @@ private function getDictionary($name) {
223210
assert('is_string($name)');
224211

225212
if(!array_key_exists($name, $this->dictionaries)) {
226-
$dictDir = $this->configuration->getPathValue('dictionarydir');
227-
$this->dictionaries[$name] = $this->readDictionaryFile($dictDir . $name . '.php');
213+
$sepPos = strpos($name, ':');
214+
if($sepPos !== FALSE) {
215+
$module = substr($name, 0, $sepPos);
216+
$fileName = substr($name, $sepPos + 1);
217+
$dictDir = SimpleSAML_Module::getModuleDir($module) . '/dictionaries/';
218+
} else {
219+
$dictDir = $this->configuration->getPathValue('dictionarydir');
220+
$fileName = $name;
221+
}
222+
$this->dictionaries[$name] = $this->readDictionaryFile($dictDir . $fileName . '.php');
228223
}
229224

230225
return $this->dictionaries[$name];
@@ -249,7 +244,7 @@ public function getTag($tag) {
249244
}
250245

251246
/* Check whether we should use the default dictionary or a dictionary specified in the tag. */
252-
if(substr($tag, 0, 1) === '{' && preg_match('/^{(\w+?):(.*)}$/', $tag, $matches)) {
247+
if(substr($tag, 0, 1) === '{' && preg_match('/^{((?:\w+:)?\w+?):(.*)}$/', $tag, $matches)) {
253248
$dictionary = $matches[1];
254249
$tag = $matches[2];
255250
} else {
@@ -460,31 +455,99 @@ private function readDictionaryFile($filename) {
460455
* Show the template to the user.
461456
*/
462457
public function show() {
463-
464-
$filename = $this->configuration->getPathValue('templatedir') .
465-
$this->configuration->getValue('theme.use') . '/' . $this->template;
466-
467458

468-
if (!file_exists($filename)) {
469-
SimpleSAML_Logger::warning($_SERVER['PHP_SELF'].' - Template: Could not find template file [' . $this->template . '] at [' . $filename . '] - now trying the base template');
470-
471-
472-
$filename = $this->configuration->getPathValue('templatedir') .
473-
$this->configuration->getValue('theme.base') . '/' . $this->template;
474-
475-
476-
if (!file_exists($filename)) {
477-
SimpleSAML_Logger::critical($_SERVER['PHP_SELF'].' - Template: Could not find template file [' . $this->template . '] at [' . $filename . ']');
478-
479-
echo 'Fatal error: Could not find template file [' . $this->template . '] at [' . $filename . ']';
480-
exit(0);
481-
}
482-
}
483-
459+
$filename = $this->findTemplatePath($this->template);
484460
require_once($filename);
485461
}
486-
487-
462+
463+
464+
/**
465+
* Find template path.
466+
*
467+
* This function locates the given template based on the template name.
468+
* It will first search for the template in the current theme directory, and
469+
* then the default theme.
470+
*
471+
* The template name may be on the form <module name>:<template path>, in which case
472+
* it will search for the template file in the given module.
473+
*
474+
* An error will be thrown if the template file couldn't be found.
475+
*
476+
* @param string $template The relative path from the theme directory to the template file.
477+
* @return string The absolute path to the template file.
478+
*/
479+
private function findTemplatePath($template) {
480+
assert('is_string($template)');
481+
482+
$tmp = explode(':', $template, 2);
483+
if (count($tmp) === 2) {
484+
$templateModule = $tmp[0];
485+
$templateName = $tmp[1];
486+
} else {
487+
$templateModule = 'default';
488+
$templateName = $tmp[0];
489+
}
490+
491+
$tmp = explode(':', $this->configuration->getValue('theme.use'), 2);
492+
if (count($tmp) === 2) {
493+
$themeModule = $tmp[0];
494+
$themeName = $tmp[1];
495+
} else {
496+
$themeModule = NULL;
497+
$themeName = $tmp[0];
498+
}
499+
500+
501+
/* First check the current theme. */
502+
if ($themeModule !== NULL) {
503+
/* .../module/<themeModule>/themes/<themeName>/<templateModule>/<templateName> */
504+
505+
$filename = SimpleSAML_Module::getModuleDir($themeModule) . '/themes/' . $themeName . '/' .
506+
$templateModule . '/' . $templateName;
507+
} elseif ($templateModule !== 'default') {
508+
/* .../module/<templateModule>/templates/<themeName>/<templateName> */
509+
$filename = SimpleSAML_Module::getModuleDir($templateModule) . '/templates/' .
510+
$themeName . '/' . $templateName;
511+
} else {
512+
/* .../templates/<theme>/<templateName> */
513+
$filename = $this->configuration->getPathValue('templatedir') . $themeName . '/' .
514+
$templateName;
515+
}
516+
517+
if (file_exists($filename)) {
518+
return $filename;
519+
}
520+
521+
522+
/* Not found in current theme. */
523+
SimpleSAML_Logger::info($_SERVER['PHP_SELF'].' - Template: Could not find template file [' .
524+
$template . '] at [' . $filename . '] - now trying the base template');
525+
526+
527+
/* Try default theme. */
528+
$baseTheme = $this->configuration->getValue('theme.base');
529+
if ($templateModule !== 'default') {
530+
/* .../module/<templateModule>/templates/<baseTheme>/<templateName> */
531+
$filename = SimpleSAML_Module::getModuleDir($templateModule) . '/templates/' .
532+
$baseTheme . '/' . $templateName;
533+
} else {
534+
/* .../templates/<baseTheme>/<templateName> */
535+
$filename = $this->configuration->getPathValue('templatedir') . $baseTheme . '/' .
536+
$templateName;
537+
}
538+
539+
if (file_exists($filename)) {
540+
return $filename;
541+
}
542+
543+
544+
/* Not found in default template - log error and throw exception. */
545+
$error = 'Template: Could not find template file [' . $template . '] at [' . $filename . ']';
546+
SimpleSAML_Logger::critical($_SERVER['PHP_SELF'] . ' - ' . $error);
547+
548+
throw new Exception($error);
549+
}
550+
488551
}
489552

490553
?>

www/module.php

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php
2+
/**
3+
* Handler for module requests.
4+
*
5+
* This web page receives requests for web-pages hosted by modules, and directs them to
6+
* the RequestHandler in the module.
7+
*
8+
* @author Olav Morken, UNINETT AS.
9+
* @package simpleSAMLphp
10+
* @version $Id$
11+
*/
12+
13+
require_once('_include.php');
14+
15+
SimpleSAML_Error_Assertion::installHandler();
16+
17+
/* Index pages - filenames to attempt when accessing directories. */
18+
$indexFiles = array('index.php', 'index.html', 'index.htm', 'index.txt');
19+
20+
/* MIME types - key is file extension, value is MIME type. */
21+
$mimeTypes = array(
22+
'bml' => 'image/x-ms-bmp',
23+
'css' => 'text/css',
24+
'gif' => 'image/gif',
25+
'htm' => 'text/html',
26+
'html' => 'text/html',
27+
'shtml' => 'text/html',
28+
'jpe' => 'image/jpeg',
29+
'jpeg' => 'image/jpeg',
30+
'jpg' => 'image/jpeg',
31+
'js' => 'text/javascript',
32+
'pdf' => 'application/pdf',
33+
'png' => 'image/png',
34+
'svg' => 'image/svg+xml',
35+
'svgz' => 'image/svg+xml',
36+
'swf' => 'application/x-shockwave-flash',
37+
'swfl' => 'application/x-shockwave-flash',
38+
'txt' => 'text/plain',
39+
'xht' => 'application/xhtml+xml',
40+
'xhtml' => 'application/xhtml+xml',
41+
);
42+
43+
try {
44+
45+
if (empty($_SERVER['PATH_INFO'])) {
46+
throw new SimpleSAML_Error_NotFound('No PATH_INFO to module.php');
47+
}
48+
49+
$url = $_SERVER['PATH_INFO'];
50+
assert('substr($url, 0, 1) === "/"');
51+
52+
$modEnd = strpos($url, '/', 1);
53+
if ($modEnd === FALSE) {
54+
/* The path must always be on the form /module/. */
55+
throw new SimpleSAML_Error_NotFound('The URL must at least contain a module name followed by a slash.');
56+
}
57+
58+
$module = substr($url, 1, $modEnd - 1);
59+
$url = substr($url, $modEnd + 1);
60+
if ($url === FALSE) {
61+
$url = '';
62+
}
63+
64+
if (!SimpleSAML_Module::isModuleEnabled($module)) {
65+
throw new SimpleSAML_Error_NotFound('The module \'' . $module .
66+
'\' was either not found, or wasn\'t enabled.');
67+
}
68+
69+
/* Make sure that the request isn't suspicious (contains references to current
70+
* directory or parent directory or anything like that. Searching for './' in the
71+
* URL will detect both '../' and './'. Searching for '\' will detect attempts to
72+
* use Windows-style paths.
73+
*/
74+
if (strpos($url, '\\')) {
75+
throw new SimpleSAML_Error_BadRequest('Requested URL contained a backslash.');
76+
} elseif (strpos($url, './')) {
77+
throw new SimpleSAML_Error_BadRequest('Requested URL contained \'./\'.');
78+
}
79+
80+
$path = SimpleSAML_Module::getModuleDir($module) . '/www/' . $url;
81+
82+
if ($path[strlen($path)-1] === '/') {
83+
/* Path ends with a slash - directory reference. Attempt to find index file
84+
* in directory.
85+
*/
86+
foreach ($indexFiles as $if) {
87+
if (file_exists($path . $if)) {
88+
$path .= $if;
89+
break;
90+
}
91+
}
92+
}
93+
94+
if (is_dir($path)) {
95+
/* Path is a directory - maybe no index file was found in the previous step, or
96+
* maybe the path didn't end with a slash. Either way, we don't do directory
97+
* listings.
98+
*/
99+
throw new SimpleSAML_Error_NotFound('Directory listing not available.');
100+
}
101+
102+
if (!file_exists($path)) {
103+
/* File not found. */
104+
SimpleSAML_Logger::info('Could not find file \'' . $path . '\'.');
105+
throw new SimpleSAML_Error_NotFound('The URL wasn\'t found in the module.');
106+
}
107+
108+
if (preg_match('#\.php$#', $path)) {
109+
/* PHP file - attempt to run it. */
110+
require($path);
111+
exit();
112+
}
113+
114+
/* Some other file type - attempt to serve it. */
115+
116+
/* Find MIME type for file, based on extension. */
117+
if (preg_match('#\.([^/]+)$#', $path, $type)) {
118+
$type = strtolower($type[1]);
119+
if (array_key_exists($type, $mimeTypes)) {
120+
$contentType = $mimeTypes[$type];
121+
} else {
122+
$contentType = mime_content_type($path);
123+
}
124+
} else {
125+
$contentType = mime_content_type($path);
126+
}
127+
128+
$contentLength = sprintf('%u', filesize($path)); /* Force filesize to an unsigned number. */
129+
130+
header('Content-Type: ' . $contentType);
131+
header('Content-Length: ' . $contentLength);
132+
readfile($path);
133+
exit();
134+
135+
} catch(SimpleSAML_Error_Error $e) {
136+
137+
$e->show();
138+
139+
} catch(Exception $e) {
140+
141+
$e = new SimpleSAML_Error_Error('UNHANDLEDEXCEPTION', $e);
142+
$e->show();
143+
144+
}
145+
146+
?>

0 commit comments

Comments
 (0)