226 lines
6.9 KiB
PHP
226 lines
6.9 KiB
PHP
<?php
|
|
/**
|
|
* File-based courseware: one .pptx file per lesson in the repo-root courseware/ directory.
|
|
*/
|
|
|
|
if (!function_exists('courseware_root')) {
|
|
function courseware_root() {
|
|
if (isset($GLOBALS['_courseware_root']) && $GLOBALS['_courseware_root'] !== '') {
|
|
$resolved = realpath($GLOBALS['_courseware_root']);
|
|
return $resolved === false ? '' : $resolved;
|
|
}
|
|
$resolved = realpath(__DIR__ . '/../../courseware');
|
|
return $resolved === false ? '' : $resolved;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_is_slug')) {
|
|
function courseware_is_slug($slug) {
|
|
if (!is_string($slug) || $slug === '' || $slug === '.' || $slug === '..') {
|
|
return false;
|
|
}
|
|
if (strpos($slug, "\0") !== false) {
|
|
return false;
|
|
}
|
|
if (strpos($slug, '/') !== false || strpos($slug, '\\') !== false) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_is_pptx_name')) {
|
|
function courseware_is_pptx_name($name) {
|
|
if (!is_string($name) || strlen($name) < 6) {
|
|
return false;
|
|
}
|
|
if (strpos($name, "\0") !== false || strpos($name, '/') !== false || strpos($name, '\\') !== false) {
|
|
return false;
|
|
}
|
|
return strtolower(substr($name, -5)) === '.pptx';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_inside_root')) {
|
|
function courseware_inside_root($path, $root) {
|
|
$root_norm = rtrim(str_replace('\\', '/', $root), '/');
|
|
$path_norm = rtrim(str_replace('\\', '/', $path), '/');
|
|
if ($root_norm === '' || $path_norm === '') {
|
|
return false;
|
|
}
|
|
$insensitive = (DIRECTORY_SEPARATOR === '\\');
|
|
if ($insensitive) {
|
|
if (strcasecmp($path_norm, $root_norm) === 0) {
|
|
return true;
|
|
}
|
|
$prefix = $root_norm . '/';
|
|
return strncasecmp($path_norm, $prefix, strlen($prefix)) === 0;
|
|
}
|
|
return $path_norm === $root_norm || strpos($path_norm, $root_norm . '/') === 0;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_is_absolute_path')) {
|
|
function courseware_is_absolute_path($path) {
|
|
if (!is_string($path) || $path === '') {
|
|
return false;
|
|
}
|
|
if ($path[0] === '/' || $path[0] === '\\') {
|
|
return true;
|
|
}
|
|
return (bool) preg_match('#^[A-Za-z]:[\\\\/]#', $path);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_scan_pptx_entries')) {
|
|
function courseware_scan_pptx_entries() {
|
|
$root = courseware_root();
|
|
$found = array();
|
|
if ($root === '' || !is_dir($root)) {
|
|
return $found;
|
|
}
|
|
$entries = @scandir($root);
|
|
if ($entries === false) {
|
|
return $found;
|
|
}
|
|
foreach ($entries as $name) {
|
|
if ($name === '.' || $name === '..') {
|
|
continue;
|
|
}
|
|
if (!courseware_is_pptx_name($name)) {
|
|
continue;
|
|
}
|
|
$slug = substr($name, 0, -5);
|
|
if (!courseware_is_slug($slug)) {
|
|
continue;
|
|
}
|
|
if (!isset($found[$slug])) {
|
|
$found[$slug] = $name;
|
|
}
|
|
}
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_link_stays_inside')) {
|
|
function courseware_link_stays_inside($raw, $root) {
|
|
if (!is_link($raw)) {
|
|
return true;
|
|
}
|
|
$link = @readlink($raw);
|
|
if ($link === false || strpos($link, "\0") !== false) {
|
|
return false;
|
|
}
|
|
$target = courseware_is_absolute_path($link)
|
|
? $link
|
|
: (dirname($raw) . DIRECTORY_SEPARATOR . $link);
|
|
$resolved_link = realpath($target);
|
|
if ($resolved_link === false || !courseware_inside_root($resolved_link, $root)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_resolve_pptx')) {
|
|
function courseware_resolve_pptx($slug) {
|
|
if (!courseware_is_slug($slug)) {
|
|
return null;
|
|
}
|
|
$root = courseware_root();
|
|
if ($root === '') {
|
|
return null;
|
|
}
|
|
$entries = courseware_scan_pptx_entries();
|
|
if (!isset($entries[$slug])) {
|
|
return null;
|
|
}
|
|
$name = $entries[$slug];
|
|
$raw = $root . DIRECTORY_SEPARATOR . $name;
|
|
if (!courseware_link_stays_inside($raw, $root)) {
|
|
return null;
|
|
}
|
|
$resolved = realpath($raw);
|
|
if ($resolved === false || !is_file($resolved)) {
|
|
return null;
|
|
}
|
|
if (!courseware_inside_root($resolved, $root)) {
|
|
return null;
|
|
}
|
|
if (!courseware_is_pptx_name(basename($resolved)) && !courseware_is_pptx_name($name)) {
|
|
return null;
|
|
}
|
|
return array(
|
|
'slug' => $slug,
|
|
'title' => $slug,
|
|
'filename' => $name,
|
|
'path' => $resolved,
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_build_deck')) {
|
|
function courseware_build_deck($slug) {
|
|
$found = courseware_resolve_pptx($slug);
|
|
if ($found === null) {
|
|
return null;
|
|
}
|
|
return array(
|
|
'slug' => $found['slug'],
|
|
'title' => $found['title'],
|
|
'filename' => $found['filename'],
|
|
'url' => 'courseware-file.php?deck=' . rawurlencode($found['slug']),
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_list_decks')) {
|
|
function courseware_list_decks() {
|
|
$decks = array();
|
|
$seen = array();
|
|
foreach (courseware_scan_pptx_entries() as $slug => $name) {
|
|
unset($name);
|
|
if (isset($seen[$slug])) {
|
|
continue;
|
|
}
|
|
$deck = courseware_build_deck($slug);
|
|
if ($deck !== null) {
|
|
$seen[$slug] = true;
|
|
$decks[] = $deck;
|
|
}
|
|
}
|
|
usort($decks, function ($a, $b) {
|
|
return strnatcasecmp($a['title'], $b['title']);
|
|
});
|
|
return $decks;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_clamp_page')) {
|
|
function courseware_clamp_page($deck, $page) {
|
|
$page = intval($page);
|
|
if ($page < 1) {
|
|
return 1;
|
|
}
|
|
$count = (is_array($deck) && isset($deck['page_count'])) ? intval($deck['page_count']) : 0;
|
|
if ($count < 1) {
|
|
return $page;
|
|
}
|
|
if ($page > $count) {
|
|
return $count;
|
|
}
|
|
return $page;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('courseware_content_disposition')) {
|
|
function courseware_content_disposition($filename) {
|
|
$safe = str_replace(array("\r", "\n", '"', '\\'), '_', strval($filename));
|
|
$ascii = preg_replace('/[^\x20-\x7E]/', '_', $safe);
|
|
if ($ascii === '' || $ascii === '_' || $ascii === '.pptx') {
|
|
$ascii = 'courseware.pptx';
|
|
}
|
|
return 'inline; filename="' . $ascii . '"; filename*=UTF-8\'\'' . rawurlencode($filename);
|
|
}
|
|
}
|