$maxtitle) {
$title = substr($title, 0, $maxtitle-3);
$title = trim(clean_utf8($title)).'...';
}
return $title;
}
function clean_text($text) {
// Clean up control characters, special quotes, ligatures, special spacing, etc.
$text = str_replace('\t', ' ', $text);
$text = preg_replace('#[\x00-\x09\x0B-\x1F]#', '', $text);
$unicode_specials = array(
// 0x7F-0x9F control characters
'','','','','','','
','','','','','','','',
'','','','','','','','','','','','','','',
'','','','','',
// Unicode spacing
'','','','','\xE2\x80\xA8','\xE2\x80\xA9','','','','','',
// Unicode quotes
'‘','’','“','”');
$ascii_specials = array(
// Strip 0x7F-0x9F control characters
'','','','','','','','','','','','','','',
'','','','','','','','','','','','','','',
'','','','','',
// Replacements for unicode spacing
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
// Replacements for unicode quotes
"'","'",'"','"');
$text = str_replace($unicode_specials, $ascii_specials, $text);
return $text;
}
function clean_template($template) {
global $templates, $defaulttemplate;
foreach ($templates as $tem) {
if ($tem === $template) { return $tem; }
}
return $defaulttemplate;
}
function clean_url($url) {
global $filesediturl, $filesrealurl;
// Turn editor-relative links into page-relative links
if (startswith($url, $filesediturl)) {
$url = $filesrealurl.substr($url, strlen($filesediturl));
}
// Remove domain/path of local absolute URLs
$base = preg_replace('#(pageeditor/)?(index\.php)?(\?.*)?$#', '', $_SERVER['REQUEST_URI']);
$regex = '#^https?://\[?'.preg_quote(str_replace('/', '', $_SERVER['HTTP_HOST']), '#').'\]?(:[0-9]+)?'.preg_quote($base, '#').'#i';
$url = preg_replace($regex, '', $url);
return $url;
}
function make_editor_relative_urls($html) {
global $filesediturl, $filesrealurl;
return str_replace(' src="'.htmlspecialchars($filesrealurl),
' src="'.htmlspecialchars($filesediturl), $html);
}
function wrap_largeimg_callback($matches) {
$href = htmlspecialchars(clean_text(hex2bin($matches[3])));
return '';
}
define('ST_TEXT', 0);
define('ST_TAGNAME', 1);
define('ST_ATTR', 2);
define('ST_COMMENT', 3);
function clean_html($html) {
//
is not included yet because it needs special handling
$allowed = array(
// block elements
'address','aside','blockquote','dd','dl','dt','div','figcaption',
'figure','h1','h2','h3','h4','h5','h6','hgroup','hr','li','ol','p','ul',
// text elements
'abbr','b','big','bdi','bdo','br','cite','code','del','dfn','em',
'i','ins','kbd','mark','nobr','q','rp','rt','rtc','ruby','s','samp',
'small','span','strong','sub','sup','time','tt','u','var','wbr',
// tables
'caption','col','colgroup','table','tbody','td','tfoot','th','thead',
'tr',
// special elements
'a','area','audio','img','map','track','video');
/* deprecated tags:
acronym --> abbr
big --> keep
blink --> ignore
center --> div
listing --> pre (not common)
marquee --> ignore
nobr --> keep
plaintext --> ~pre (not common)
spacer --> ignore
strike --> s
tt --> code
xmp --> pre+code?
*/
$allowed_attrs = array('dir', 'id', 'lang', 'role', 'title', 'translate', /*'style',*/);
$allowed_attr_regex = '#(aria-[a-z0-9-])+#';
$allowed_attrs_tag = array(
'a' => array('download', 'href', 'hreflang', 'rel', 'rev', 'name',
'nofollow', 'target', 'type', 'referrerpolicy'),
'area' => array('alt', 'crossorigin', 'coords', 'download', 'href',
'hreflang', 'rel', 'shape', 'name', 'nofollow', 'target',
'type', 'referrerpolicy'),
'audio' => array('crossorigin', 'loop', 'muted', 'preload', 'src'),
'blockquote' => array('cite'),
'del' => array('cite','datetime'),
/*'iframe' => array('allowfullscreen', 'allowpaymentrequest', 'height',
'name', 'referrerpolicy', 'sandbox', 'src',
'srcdoc', 'width'),*/
'img' => array('alt', 'border', 'crossorigin', 'height', 'ismap',
'longdesc', 'refererpolicy', 'sizes', 'src', 'srcset',
'usemap', 'width'),
'ins' => array('cite','datetime'),
'li' => array('value'),
'map' => array('name'),
'ol' => array('reversed', 'start', 'type'),
'q' => array('cite'),
'table' => array('cellpadding', 'cellspacing'),
'td' => array('rowspan', 'colspan'),
'th' => array('rowspan', 'colspan'),
'track' => array('default', 'kind', 'label', 'src', 'srclang'),
'time' => array('datetime'),
'video' => array('crossorigin', 'height', 'loop', 'muted', 'preload',
'poster', 'src', 'width'),
);
$tag_replacements = array(
'acronym' => 'abbr',
'image' => 'img',
'strike' => 's',
'tt' => 'code',
);
$nonenc = array('<','>','"',"'");
$enc = array('<','>','"',''');
$html = clean_text($html);
$cleaned = '';
$state = ST_TEXT;
$textstart = 0;
$tagstart = 0;
$attrstart = 0;
$i = 0;
$done = false;
while (!$done) {
switch ($state) {
case ST_TEXT:
$length = strcspn($html, "<", $i);
// encode for extra security (except & which would destroy &enties;)
$cleaned .= str_replace($nonenc, $enc, substr($html, $i, $length));
$i += $length;
if ($i < strlen($html)) {
$state = ST_TAGNAME;
$i++;
} else {
$done = true;
}
break;
case ST_TAGNAME:
$length = strcspn($html, " \r\n\t><", $i);
$tagname = strtolower(trim(substr($html, $i, $length)));
$endtag = (strlen($tagname) >= 1 && $tagname[0] === '/');
$tagname = preg_replace('#^/\\s*#', '', $tagname);
if ($endtag) {
$i += $length;
if ($i < strlen($html) && $html[$i] === '>') {
$i++;
}
if (in_array($tagname, $allowed, true)) {
$cleaned .= ''.$tagname.'>';
}
$state = ST_TEXT;
} elseif (substr($html, $i, 3) === '!--') {
$i += 3;
$state = ST_COMMENT;
// TODO special handling for script and style elements
} else {
$i += $length;
$tagattrs = array();
$state = ST_ATTR;
}
break;
case ST_ATTR:
$i += strspn($html, " \r\n\t", $i);
$ch = ($i < strlen($html) ? $html[$i] : null);
$selfclosechar = '';
if ($ch === '/') {
$i++;
$i += strspn($html, " \r\n\t", $i);
$ch = ($i < strlen($html) ? $html[$i] : null);
$selfclosechar = '/';
}
if ($ch === '>' || $ch === '<' || $ch === null) {
// End of tag
$i++;
if (isset($tag_replacements[$tagname])) {
$tagname = $tag_replacements[$tagname];
}
if (in_array($tagname, $allowed, true)) {
$cleaned .= '<'.$tagname;
// TODO sort attributes?
foreach ($tagattrs as $attrname => $attrvalue) {
if (in_array($attrname, $allowed_attrs, true) ||
preg_match($allowed_attr_regex, $attrname) ||
(isset($allowed_attrs_tag[$tagname]) &&
in_array($attrname, $allowed_attrs_tag[$tagname], true))) {
$cleaned .= ' '.$attrname.($attrvalue !== null ?
'="'.str_replace($nonenc, $enc, $attrvalue).'"' : '');
}
}
$cleaned .= $selfclosechar.'>';
}
$state = $ch === '<' ? ST_TAGNAME : ST_TEXT;
break;
}
// Attribute name
$length = strcspn($html, " \r\n\t\"\'=/><&", $i);
$attrname = strtolower(substr($html, $i, $length));
$i += $length;
$i += strspn($html, " \r\n\t", $i);
$ch = ($i < strlen($html) ? $html[$i] : null);
$attrvalue = null;
if ($ch === '=') {
// Attribute value
$i++;
$i += strspn($html, " \r\n\t", $i);
$ch = ($i < strlen($html) ? $html[$i] : null);
if ($ch === '"' || $ch === "'") {
$quotechar = $ch;
$i++;
$length = strcspn($html, $quotechar, $i);
$attrvalue = substr($html, $i, $length);
$i += $length;
$ch = ($i < strlen($html) ? $html[$i] : null);
if ($ch === $quotechar) {
$i++;
}
} else {
$length = strcspn($html, " \r\n\t\"\'=><&", $i);
$attrvalue = substr($html, $i, $length);
$i += $length;
}
}
if (!isset($tagattrs[$attrname])) { // ignore duplicates
if ($attrname === 'src' || $attrname === 'href') {
$attrvalue = clean_url($attrvalue);
}
$tagattrs[$attrname] = $attrvalue;
}
break;
case ST_COMMENT:
$end = strpos($html, '-->', $i-2);
if ($end === false) {
$comment = substr($html, $i);
$end = strlen($html);
} elseif ($end <= $i) {
// or
$comment = '';
$end += 3;
} else {
$comment = substr($html, $i, $end-$i);
$end += 3;
}
// safety measure: remove < and > inside comments,
// in case there would be a bug in the parser
$cleaned .= '';
$i = $end;
$state = ST_TEXT;
break;
}
}
// Add around
$cleaned = preg_replace_callback('/
/', 'wrap_largeimg_callback', $cleaned);
// TODO strip "class" attributes
// TODO change * | *| if x is not block level (actually, the spaces outside of the element (e.g. ) might matter... check this)
// TODO strip * |... if x is not block level
// TODO strip special elements (script, style)
// TODO finally, ensure that tags are closed/nested correctly
return $cleaned;
}
function filename_from_title($pagetitle) {
if ($pagetitle === '') {
return '';
}
$non_ascii = array(
'À','Á','Â','Ã','Ä','Å', 'Æ','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï','Ð','Ñ','Ò','Ó','Ô','Õ','Ö','Ø','Ù','Ú','Û','Ü','Ý', 'Þ',
'à','á','â','ã','ä','å', 'æ','ç','è','é','ê','ë','ì','í','î','ï','ð','ñ','ò','ó','ô','õ','ö','ø','ù','ú','û','ü','ý', 'þ','ÿ',
'Ā','ā','Ă','ă','Ą','ą','Ć','ć','Ĉ','ĉ','Ċ','ċ','Č','č','Ď','ď','Đ','đ','Ē','ē','Ĕ','ĕ','Ė','ė','Ę','ę','Ě','ě','Ĝ','ĝ','Ğ',
'ğ','Ġ','ġ','Ģ','ģ','Ĥ','ĥ','Ħ','ħ','Ĩ','ĩ','Ī','ī','Ĭ','ĭ','Į','į','İ','ı', 'IJ', 'ij','Ĵ','ĵ','Ķ','ķ','ĸ','Ĺ','ĺ','Ļ','ļ',
'Ľ','ľ','Ŀ','ŀ','Ł','ł','Ń','ń','Ņ','ņ','Ň','ň','ʼn', 'Ŋ', 'ŋ','Ō','ō','Ŏ','ŏ','Ő','ő', 'Œ', 'œ','Ŕ','ŕ','Ŗ','ŗ','Ř','ř',
'Ś','ś','Ŝ','ŝ','Ş','ş','Š','š','Ţ','ţ','Ť','ť','Ŧ','ŧ','Ũ','ũ','Ū','ū','Ŭ','ŭ','Ů','ů','Ű','ű','Ų','ų','Ŵ','ŵ','Ŷ','ŷ','Ÿ',
'Ź','ź','Ż','ż','Ž','ž','ſ',
);
$ascii = array(
'a','a','a','a','a','a','ae','c','e','e','e','e','i','i','i','i','d','n','o','o','o','o','o','o','u','u','u','u','y','th',
'a','a','a','a','a','a','ae','c','e','e','e','e','i','i','i','i','d','n','o','o','o','o','o','o','u','u','u','u','y','th','y',
'a','a','a','a','a','a','c','c','c','c','c','c','c','c','d','d','d','d','e','e','e','e','e','e','e','e','e','e','g','g','g',
'g','g','g','g','g','h','h','h','h','i','i','i','i','i','i','i','i','i','i','ij','ij','j','j','k','k','k','l','l','l','l',
'l','l','l','l','l','l','n','n','n','n','n','n','n','ng','ng','o','o','o','o','o','o','oe','oe','r','r','r','r','r','r',
's','s','s','s','s','s','s','s','t','t','t','t','t','t','u','u','u','u','u','u','u','u','u','u','u','u','w','w','y','y','y',
'z','z','z','z','z','z','s',
);
$name = preg_replace('#[ +.,:,!?]+#', '_', strtolower(str_replace($non_ascii, $ascii, $pagetitle)));
$name = clean_filename($name);
if ($name === '' || 4*count($name) < count($pagetitle)) {
$name = substr(sha1($pagetitle), 0, 10);
}
return $name;
}
function read_page_list() {
$pageinfos = array();
$path = configpath("/pages.txt");
if (!file_exists($path)) {
return $pageinfos;
}
$f = fopen($path, "r");
if (!$f) {
return $pageinfos;
}
while (($line = fgets($f)) !== false) {
$line = trim($line);
if (!$line) continue;
$pageinfo = explode("\t", $line);
$pageinfos[] = $pageinfo;
}
fclose($f);
return $pageinfos;
}
/**
* Modifies the page list. The changes are written to disk.
* It can perform insertion, deletion and moving, depending on the paramters.
*
* @param string|null pagename Old name of page, or null if a new page should be added.
* @param string|null newname New name of page. Ignored when deleting.
* @param string|null newtitle New title of page. Ignored when deleting.
* @param string|null newtemplate New template of page. Ignored when deleting.
* @param int|null newindex New index of page. Set to -1 to place last, or null to delete.
*/
function update_page_list($pagename, $newname, $newtitle, $newtemplate, $newindex=-1) {
global $pageinfos, $error;
// Update in $pageinfos
$newpageinfos = array();
for ($i = 0; $i < count($pageinfos); $i++) {
$pi = $pageinfos[$i];
if ($i === $newindex) {
// Insert page at this index
$newpageinfos[] = array($newtemplate, $newname, $newtitle);
}
if ($pi[PI_NAME] !== $pagename) {
// This page is not to be deleted/moved
$newpageinfos[] = $pi;
}
}
if ($newindex === -1 || $newindex == count($pageinfos)) {
$newpageinfos[] = array($newtemplate, $newname, $newtitle);
}
// Write to file
$reallist = configpath("/pages.txt");
$tmplist = configpath("/pages.txt.tmp");
$newf = fopen($tmplist, "w");
if (!$newf) {
$error = gettxt('ERROR_WRITEPAGELIST');
}
foreach ($newpageinfos as $pi) {
fwrite($newf, implode("\t", $pi)."\n");
}
fclose($newf);
if (!rename($tmplist, $reallist)) {
$error = gettxt('ERROR_RENAMEPAGELIST');
}
$pageinfos = $newpageinfos;
// Set "regeneration needed" flag
mark_regen_needed();
}
function mark_regen_needed() {
global $regen_needed_since;
if ($regen_needed_since === null) {
$regen_needed_since = time();
file_put_contents(configpath('/regen_needed.txt'), $regen_needed_since);
}
}
function generate_page($pagename, $pagetitle, $pagecontent, $pagetemplate) {
global $pageinfos, $siteconfig;
$tpl = file_get_contents(configpath("/templates/${pagetemplate}.html"));
if ($pagename === 'index') {
$title = $siteconfig['sitename'];
} else {
$title = $pagetitle.' - '.$siteconfig['sitename'];
}
$menu_li = '';
foreach ($pageinfos as $pageinfo) {
$menu_li .= ''.htmlspecialchars($pageinfo[PI_TITLE])." \n";
}
$langselect = ''; // TODO multi-language support
$tpl = str_replace(array('${title}', '${content}', '${menu_li}', '${langselect}', '${sitename}', '${footer}'),
array($title, $pagecontent, $menu_li, $langselect, $siteconfig['sitename'], $siteconfig['footer']), $tpl);
return file_put_contents(webpath("/${pagename}.html"), $tpl) !== false;
}
function read_template_list() {
$templates = array();
$dir = opendir(configpath('/templates'));
while (($entry = readdir($dir)) !== false) {
if (preg_match('#^[^.\t\n][^\t\n]*\.html$#D', $entry)) {
$templates[] = preg_replace('#\.html$#D', '', $entry);
}
}
closedir($dir);
return $templates;
}
function read_config_file($filename, $defaults) {
$cfg = $defaults;
$cfgfile = configpath($filename);
if (!file_exists($cfgfile)) return $cfg;
$f = fopen($cfgfile, 'r');
if (!$f) return $cfg;
while (($line = fgets($f)) !== false) {
$pieces = explode('=', $line, 2);
if (count($pieces) == 1) continue;
$key = trim($pieces[0]);
$value = trim($pieces[1]);
$cfg[$key] = $value;
}
fclose($f);
return $cfg;
}
function read_site_config() {
$defaults = array(
'sitename' => 'Enter name here',
'footer' => 'Copyright © '.date('Y'),
);
return read_config_file('/siteconfig.txt', $defaults);
}
function read_auth_config() {
return read_config_file('/users.txt', array());
}
function update_config_file($filename, $cfg) {
$f = fopen(configpath($filename), 'w');
if (!$f) return false;
foreach ($cfg as $key => $value) {
$k = str_replace(array('=', "\n"), array('', ''), trim($key));
$v = str_replace("\n", '', trim($value));
fwrite($f, "$k = $v\n");
}
fclose($f);
mark_regen_needed();
return true;
}
function update_site_config($cfg) {
if (!update_config_file('/siteconfig.txt', $cfg)) return false;
mark_regen_needed();
return true;
}
function update_auth_config($cfg) {
return update_config_file('/users.txt', $cfg);
}
function unsaved_site_config() {
global $siteconfig, $editsitename, $editfooter;
return $siteconfig['sitename'] !== $editsitename ||
$siteconfig['footer'] !== $editfooter;
}
function unsaved_edit_state() {
global $pagecontent, $pagename, $pageindex, $pageinfo,
$editpagename, $editpagetitle, $editpageindex, $editpagetemplate;
return $editpagename !== $pageinfo[PI_NAME] ||
$editpagetitle !== $pageinfo[PI_TITLE] ||
$editpagetemplate !== $pageinfo[PI_TEMPLATE] ||
$editpageindex !== $pageindex ||
$pagecontent !== read_page($pagename);
}
function get_page_info($pageinfos, $name) {
foreach ($pageinfos as $i => $pageinfo) {
if ($pageinfo[PI_NAME] === $name) return array($i, $pageinfo);
}
return null;
}
function index_page_defaults() {
return array($defaulttemplate, 'index', 'Start page');
}
function read_page($pagename) {
return file_get_contents(configpath("/pages/${pagename}.txt"));
}
function read_regen_needed() {
$path = configpath('/regen_needed.txt');
if (!file_exists($path)) return null;
else return intval(trim(file_get_contents($path)));
}
function already_exists($pageinfos, $pagename) {
// Check if it exists in the page list
if (get_page_info($pageinfos, $pagename) !== null) return true;
// Check if it is some html file not created with this tool
return !file_exists(configpath("/pages/${pagename}.txt")) &&
file_exists(webpath("/${pagename}.html"));
}
function is_image_filename($filename) {
return preg_match('/\.(png|jpg|jpeg|jpe|gif|bmp|ico|svg|svgz)$/i', $filename);
}
function upload_file_ext_allowed($filename) {
global $allowedexts;
// Always disallow hidden files
if (preg_match('/^\./', $filename)) {
return 'ERROR_UPLOAD_HIDDEN';
}
if (!preg_match('/\.('.$allowedexts.')$/i', $filename)) {
return 'ERROR_UPLOAD_FILEEXT';
}
$filename = preg_replace('/\.('.$allowedexts.')$/i', '', $filename);
// Disallow double extensions (except for the allowed ones, like .tar.gz)
if (preg_match('/\.[a-zA-Z]+$/', $filename)) {
return 'ERROR_UPLOAD_DOUBLEFILEEXT';
}
// Block too long filenames
if (strlen($filename) > 100) {
return 'ERROR_UPLOAD_NAMETOOLONG';
}
return true;
}
function clean_upload_filename($filename) {
$filename = clean_one_line($filename);
$filename = preg_replace('#[/\\:]#', '', $filename);
$filename = preg_replace('/_small\.([a-zA-Z0-9]+)$/i', '_small.$1', $filename);
return $filename;
}
function startswith($s, $beginning) {
return substr($s, 0, strlen($beginning)) === $beginning;
}
function is_webp($s) {
return startswith($s, 'RIFF') && substr($s, 8, 7) == 'WEBPVP8';
}
function is_small_image($filename) {
return preg_match('/_small\.jpg$/', $filename);
}
function get_small_name($filename) {
return preg_replace('/\.([a-zA-Z0-9]+)$/', '_small.jpg', $filename);
}
function can_scale_image($filename) {
return preg_match('/.(jpg|jpeg|png|webp)$/i', $filename);
}
function create_lowres_picture($cleanedname) {
global $filesdir, $image_width, $image_height;
if (!can_scale_image($cleanedname) || is_small_image($cleanedname) ||
!function_exists('getimagesize')) {
return false;
}
$origname = $filesdir.'/'.$cleanedname;
$newname = $filesdir.'/'.get_small_name($cleanedname);
// Check the file header
$f = fopen($origname, 'rb');
if (!$f) return false;
$header = fread($f, 16);
fclose($f);
if (!startswith($header, "\xff\xd8\xff") && // JPEG
!startswith($header, "\x89PNG\x0d\x0a\x1a\x0a") && // PNG
//!startswith($header, 'GIF8') && // GIF
!is_webp($header)) {
return false;
}
// Check if it needs to be scaled down
// TODO check for images with EXIF rotation also. These need to be rotated
$size = getimagesize($origname);
if (!$size || ($size[0] < $image_width && $size[1] < $image_height)) {
return false;
}
$type = $size[2];
if ($type != IMAGETYPE_PNG && $type != IMAGETYPE_JPEG && $type != IMAGETYPE_WEBP) {
return false;
}
// Determine new size
$scalew = floatval($image_width) / $size[0];
$scaleh = floatval($image_height) / $size[1];
$scale = min($scalew, $scaleh);
$width = intval($size[0] * $scale);
$height = intval($size[1] * $scale);
// Perform scaling
switch ($type) {
case IMAGETYPE_PNG: $origimg = imagecreatefrompng($origname); break;
case IMAGETYPE_JPEG: $origimg = imagecreatefromjpeg($origname); break;
case IMAGETYPE_WEBP: $origimg = imagecreatefromwebp($origname); break;
}
if (!$origimg) return false;
//$newimg = imagescale($origimg, $width, $height);
$newimg = imagecreatetruecolor($width, $height);
if (!$newimg) return false;
imagecopyresampled($newimg, $origimg, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
imagedestroy($origimg);
// Write file
$output = fopen($newname, 'wb');
imagejpeg($newimg, $output);
fclose($output);
return true;
}
function redirect_get() {
global $pagename;
if ($pagename == 'index') {
header("Location: .");
//header("Location: ?nosdr"); // avoid same-document reference
} else {
header("Location: ?page=".urlencode($pagename));
}
exit();
}
function login_success_redirect() {
if (isset($_POST['iframeLoginForm'])) {
// Close login iframe
// FIXME if the user logs in with a different user, the username
// will not be updated until page reload
?>
';
}
function verify_anti_csrf() {
global $secretvalue;
if ($_SERVER['REQUEST_METHOD'] == 'POST' || !empty($_POST)) {
$pieces = explode(':', get_req_var('anti_csrf', ''), 2);
$time = intval($pieces[0]);
$token = isset($pieces[1]) ? $pieces[1] : '';
if ($time < time() - 3600*24*30) { // 30 days should be enough for most people
die("Page has expired, please try again. (CSRF token expired)");
}
if (sha1($secretvalue.':'.$token) !== sha1($secretvalue.':'.make_anti_csrf_token($time))) {
die("CSRF token error");
}
}
}
$auth = false;
$username = null;
$login_error = false;
$login_session = false;
if ($auth_http_enabled && isset($_SERVER['REMOTE_USER'])) {
// HTTP authentication. Controlled by web server
$username = $_SERVER['REMOTE_USER'];
$auth = true;
} else if ($auth_session_enabled && isset($_POST['username']) && isset($_POST['password'])) {
// Attempt to log in
$authconfig = read_auth_config();
$login_username = get_post_var('username');
if (check_password($login_username, get_post_var('password'))) {
session_start();
$username = $login_username;
$_SESSION['username'] = $username;
$_SESSION['sessionHash'] = hash('sha256', $secretvalue.':'.$username);
session_write_close();
$pagename = 'index';
login_success_redirect();
} else {
$login_error = gettxt('LOGIN_ERROR_USERPASS');
}
} else if ($auth_session_enabled && isset($_POST['button_logout'])) {
// Delete session on server
session_start();
$_SESSION = array();
session_destroy();
// Delete session cookie
$cookieParams = session_get_cookie_params();
function getCookieParam($key) {
global $cookieParams;
return (isset($cookieParams[$key]) ? $cookieParams[$key] : NULL);
}
$path = getCookieParam('path');
$domain = getCookieParam('domain');
$secure = getCookieParam('secure');
$httpOnly = getCookieParam('httpOnly');
if ($httpOnly) {
setcookie(session_name(), '', 0, $path, $domain, $secure, $httpOnly);
} else if ($secure) {
setcookie(session_name(), '', 0, $path, $domain, $secure);
} else if ($domain) {
setcookie(session_name(), '', 0, $path, $domain);
} else if ($path) {
setcookie(session_name(), '', 0, $path);
} else {
setcookie(session_name(), '', 0);
}
redirect_get();
} else if ($auth_session_enabled && isset($_COOKIE[session_name()])) {
// Check session
session_start();
if (isset($_SESSION['username'])) {
$sessionUsername = $_SESSION['username'];
$expectedHash = hash('sha256', $secretvalue.':'.hash('sha256', $secretvalue.':'.$sessionUsername));
if (isset($_SESSION['sessionHash']) &&
hash('sha256', $secretvalue.':'.$_SESSION['sessionHash']) === $expectedHash) {
$username = $sessionUsername;
$auth = true;
$login_session = true;
}
} else {
$login_error = gettxt('LOGIN_ERROR_EXPIRED');
}
session_write_close();
}
if (!$auth_session_enabled) {
die('Internal error. Authentication in '.$title.' and/or the web server is not configured correctly');
}
if (isset($_GET['sessionKeepAlive'])) {
header('Content-Type: text/plain; charset=UTF-8');
echo $auth ? "1" : "0";
exit();
}
if (!$auth || isset($_GET['iframeLoginForm'])) {
// Not authenticated
?>
'; } ?>
class="textentry">
count($pageinfos)) {
$error = gettxt('ERROR_PAGEINDEXOUTOFRANGE', $editpageindex+1, count($pageinfos));
}
$editpagetemplate = clean_template(get_post_var('pagetemplate', $pageinfo[PI_TEMPLATE]));
$editsitename = clean_title(get_post_var('editsitename', $siteconfig['sitename']));
$editfooter = clean_title(get_post_var('editfooter', $siteconfig['footer']));
$jsUnsaved = get_post_var('jsUnsaved', '') === '1'; // for javascript save warning. value is set by javascript.
$change_password = false;
// Handle actions
if (!$error) { // We skip the whole block of if/elseif/... if there's an error
if (isset($_POST['button_save'])) {
if ($editpagetitle === '') {
$error = gettxt('ERROR_BADTITLE');
} elseif ($pagename !== '' && $editpagename !== '') {
if ($newpage) {
if (already_exists($pageinfos, $editpagename)) {
$error = gettxt('ERROR_EXISTS');
} else {
update_page_list(null, $editpagename, $editpagetitle, $editpagetemplate, $editpageindex);
}
} elseif ($pagename !== $editpagename) {
if (already_exists($pageinfos, $editpagename)) {
$error = gettxt('ERROR_EXISTS');
} else {
$oldpath = webpath("/${pagename}.html");
if (file_exists($oldpath)) {
unlink($oldpath);
}
update_page_list($pagename, $editpagename, $editpagetitle, $editpagetemplate, $editpageindex);
}
} elseif ($editpagetitle !== $pageinfo[PI_TITLE] ||
$editpagetemplate !== $pageinfo[PI_TEMPLATE] ||
$editpageindex !== $pageindex) {
update_page_list($pagename, $editpagename, $editpagetitle, $editpagetemplate, $editpageindex);
}
if (!$error) {
$pagename = $editpagename;
// TODO move old .txt file to backups directory
if (file_put_contents(configpath("/pages/${pagename}.txt"), $pagecontent) === false) {
$error = gettxt('ERROR_WRITE');
} elseif (!generate_page($pagename, $editpagetitle, $pagecontent,
$editpagetemplate)) {
$error = gettxt('ERROR_GENERATEOUTPUT');
} elseif (!unsaved_site_config()) {
redirect_get(); // show success msg somehow?
}
}
} else {
$error = gettxt('ERROR_BADFILENAME');
}
} elseif (isset($_POST['button_deletepage'])) {
$promptbutton = 'button_deletepage_confirm';
$promptbuttontext = gettxt('BUTTON_DELETE_CONFIRM');
$prompttext = gettxt('TEXT_DELETE', $pageinfo[PI_TITLE], $pagename);
$promptdata = $pagename;
} elseif (isset($_POST['button_deletepage_confirm'])) {
$deletepagename = get_post_var('promptdata');
$deletepageindexinfo = get_page_info($pageinfos, $deletepagename);
if ($deletepageindexinfo === null) {
$error = gettxt('ERROR_INTERNAL', 'Page info not found');
} else {
list($deletepageindex, $deletepageinfo) = $deletepageindexinfo;
$deletepagename = $deletepageinfo[PI_NAME];
update_page_list($pagename, null, null, null, null);
//unlink(configpath("/pages/${deletepagename}.txt")); // TODO should make a backup instead
unlink(webpath("/${deletepagename}.html"));
if (!unsaved_site_config()) {
header("Location: ."); // redirect to main page
exit();
} else {
// Switch to index page without redirect (due to unsaved settings)
$pagename = 'index';
$pageindexinfo = get_page_info($pageinfos, $pagename);
if ($pageindexinfo === null) {
// Some defaults for an index page
$pageinfo = index_page_defaults();
$pageindex = 0;
$newpage = true;
$pagecontent = '';
} else {
list($pageinfo, $pageindex) = $pageindexinfo;
$newpage = false;
$pagecontent = read_page($pagename);
}
$editpagename = clean_filename($pageinfo[PI_NAME]);
$editpagetitle = clean_title($pageinfo[PI_TITLE]);
$editpagetemplate = clean_template($pageinfo[PI_TEMPLATE]);
$editpageindex = $pageindex;
}
}
} elseif (isset($_POST['button_newpage'])) {
$newpagename = filename_from_title($newpagetitle);
$newpagename = clean_filename($newpagename);
if ($newpagetitle === '') {
$error = gettxt('ERROR_BADTITLE');
} elseif ($newpagename === '') {
$error = gettxt('ERROR_BADFILENAME');
} elseif (already_exists($pageinfos, $newpagename)) {
$error = gettxt('ERROR_EXISTS');
} else {
$pagename = $newpagename;
$pageinfo = array($defaulttemplate, $pagename, $newpagetitle);
$pageindex = count($pageinfos);
$newpage = true;
$editpagename = $pagename;
$editpagetitle = $newpagetitle;
$editpageindex = $pageindex;
$pagecontent = '';
$newpagetitle = '';
}
} elseif (isset($_POST['button_regenerate'])) {
$errorpages = array();
foreach ($pageinfos as $genpi) {
$genname = $genpi[PI_NAME];
$gencontent = read_page($genname);
if ($gencontent === null || !generate_page($genname,
$genpi[PI_TITLE], $gencontent, $genpi[PI_TEMPLATE])) {
$errorpages[] = $genname;
}
}
if (!empty($errorpages)) {
$error = gettxt('ERROR_GENERATEOUTPUT_ALL', implode(', ', $errorpages));
} elseif (file_exists(configpath('/regen_needed.txt'))) {
// Clear marker
unlink(configpath('/regen_needed.txt'));
}
if (!unsaved_site_config() && !unsaved_edit_state()) {
redirect_get(); // show success msg somehow?
exit();
} else {
$regen_needed_since = null;
}
} elseif (isset($_POST['button_saveconfig'])) {
$siteconfig['sitename'] = $editsitename;
$siteconfig['footer'] = $editfooter;
if (!update_site_config($siteconfig)) {
$error = gettxt('ERROR_SAVESETTINGS');
}
} elseif (isset($_POST['button_upload'])) {
$errors = array();
if (!file_exists($filesdir)) {
$errors[] = gettxt('ERROR_UPLOAD_DIR_NONEXISTENT', $filesdir);
} elseif (!is_writeable($filesdir)) {
$errors[] = gettxt('ERROR_UPLOAD_DIR_NOT_WRITEABLE', $filesdir);
} elseif (!isset($_FILES['upload']['name'])) {
$errors[] = gettxt('ERROR_UPLOAD_NO_FILE');
} else {
$files = array();
if (is_array($_FILES['upload']['name'])) {
// Multiple files were uploaded
for ($i = 0; $i < count($_FILES['upload']['name']); $i++) {
$files[] = array(
'name' => $_FILES['upload']['name'][$i],
'tmp_name' => $_FILES['upload']['tmp_name'][$i],
'size' => $_FILES['upload']['size'][$i],
'error' => $_FILES['upload']['error'][$i],
);
}
} else {
// Single file
$files[] = $_FILES['upload'];
}
foreach ($files as $file) {
$name = (isset($file['name']) ? basename($file['name']) : '');
$nameprefix = ($name !== '' ? $name . ': ' : '');
if (!empty($file['error'])) {
$errors[] = $nameprefix . $file['error'];
continue;
} elseif ($file['size'] == 0) {
$errors[] = $nameprefix . gettxt('ERROR_UPLOAD_EMPTY');
continue;
} elseif (($exterr = upload_file_ext_allowed($name)) !== true) {
$errors[] = $nameprefix . gettxt($exterr);
continue;
}
$cleanedname = clean_upload_filename($name);
if (!move_uploaded_file($file['tmp_name'], $filesdir.'/'.$cleanedname)) {
$errors[] = $nameprefix . gettxt('ERROR_UPLOAD_INTERNAL_MOVE');
}
create_lowres_picture($cleanedname);
}
}
if (count($errors) != 0) {
$error = gettxt('ERROR_UPLOADFAIL', implode(', ', $errors));
}
// TODO renaming of uploaded files also?
} elseif (isset($_POST['button_deletefile'])) {
$promptbutton = 'button_deletefile_confirm';
$promptbuttontext = gettxt('BUTTON_DELETE_CONFIRM');
$deletefilename = clean_upload_filename(get_post_var('button_deletefile'));
$prompttext = gettxt('TEXT_DELETEFILE', $deletefilename);
$promptdata = $deletefilename;
} elseif (isset($_POST['button_deletefile_confirm'])) {
$deletefilename = clean_upload_filename(get_post_var('promptdata'));
$filepath = $filesdir.'/'.$deletefilename;
if ($deletefilename === '.' || $deletefilename === '..' ||
$deletefilename === '.htaccess' || $deletefilename === '.') {
$error = gettxt('ERROR_INTERNAL', 'Invalid file delete operation');
} elseif (file_exists($filepath)) {
unlink($filepath);
}
} elseif ($auth_session_enabled && isset($_POST['button_changepass'])) {
$change_password = true;
} elseif ($auth_session_enabled && isset($_POST['button_changepass_save'])) {
$currentpassword = get_post_var('currentpassword');
$newpassword = get_post_var('newpassword');
$repeatpassword = get_post_var('repeatpassword');
$change_password = true;
$authconfig = read_auth_config();
if (!check_password($username, $currentpassword)) {
$error = gettxt('ERROR_PASSWORD_BADOLDPASS');
} elseif ($newpassword !== $repeatpassword) {
$error = gettxt('ERROR_PASSWORD_BADREPEAT');
} elseif (empty($newpassword) || strlen($newpassword) < $minpasswordlength) { // FIXME should check length in characters, not bytes
$error = gettxt('ERROR_PASSWORD_BADLENGTH');
} elseif (strlen($newpassword) > $maxpasswordlength) {
$error = gettxt('ERROR_INTERNAL', 'Password is too long, maximum length is '.intval($maxpasswordlength).' bytes');
} elseif (!update_password($username, $newpassword)) {
$error = gettxt('ERROR_INTERNAL', 'Failed to write to user accounts file.');
} else {
$change_password = false; // Done
}
}
} // if/elseif/... are skipped if there's an error
/*
TODO: should be responsive
TODO: previewing?
TODO: drafts? (with draft, then rename = rename both txt and html files?)
*/
?>
>
'."\n";
}
if ($promptbutton) {
echo "\n";
echo ''.htmlspecialchars($prompttext)."
\n";
echo ''."\n";
echo '\n\n";
}
?>
'."\n";
}
}
if (file_exists($wysihtmldir.'/wysihtml.min.js')) {
include_wysihtml('.min');
} elseif (file_exists($wysihtmldir.'/wysihtml.js')) {
include_wysihtml('');
}
?>