$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 '\n"; } ?>'.htmlspecialchars($prompttext)."
\n"; echo ''."\n"; echo ' \n'."\n"; } } if (file_exists($wysihtmldir.'/wysihtml.min.js')) { include_wysihtml('.min'); } elseif (file_exists($wysihtmldir.'/wysihtml.js')) { include_wysihtml(''); } ?>