Initial commit.

This commit is contained in:
2026-03-10 21:25:26 +08:00
commit 78739bf725
3089 changed files with 472990 additions and 0 deletions

View File

@@ -0,0 +1,775 @@
<?php
// File name: pagefunc.inc.php
// Description: PHP subroutines to handle pages
// Date: 2003-07-10
// Author: imacat <imacat@pristine.com.tw>
// Copyright: Copyright (C) 2003-2009 Pristine Communications
// Set the include path
if (!defined("INCPATH_SET")) {
require_once dirname(__FILE__) . "/incpath.inc.php";
}
// Referenced subroutines
require_once "monica/altlang.inc.php";
require_once "monica/chkfunc.inc.php";
require_once "monica/commtext.inc.php";
require_once "monica/echoform.inc.php";
require_once "monica/errhndl.inc.php";
require_once "monica/getlang.inc.php";
require_once "monica/gettext.inc.php";
require_once "monica/lninfo.inc.php";
require_once "monica/mkalldir.inc.php";
require_once "monica/page2rel.inc.php";
require_once "monica/rel2abs.inc.php";
require_once "monica/requri.inc.php";
require_once "monica/rmalldir.inc.php";
require_once "monica/scptpriv.inc.php";
require_once "monica/sql.inc.php";
require_once "monica/unicode.inc.php";
require_once "monica/xfileio.inc.php";
// page_param: Gather the HTML parameters
function page_param($args = null)
{
// Default to an empty array
if (is_null($args)) {
$args = array();
}
// It is already fixed
if (array_key_exists(".fixed", $args)) {
return $args;
}
// Obtain page parameters
if (array_key_exists("PAGE_PARAM", $GLOBALS)) {
$args = array_merge($args, $GLOBALS["PAGE_PARAM"]);
}
if (array_key_exists("ALT_PAGE_PARAM", $GLOBALS)) {
$args = array_merge($args, $GLOBALS["ALT_PAGE_PARAM"]);
}
// Set the path
if (!array_key_exists("path", $args)) {
$args["path"] = REQUEST_PATH;
}
// Set the language
if (!array_key_exists("lang", $args)) {
$args["lang"] = getlang();
}
// Set if static or not
if (!array_key_exists("static", $args)) {
$args["static"] = false;
}
// Set if show a pretty result or not
if (!array_key_exists("clean", $args)) {
$args["clean"] = false;
}
// Set if this page is administrative
if (!array_key_exists("admin", $args)) {
$args["admin"] = is_admin_script($args["path"]);
}
// Set if UTF-8 or not
if (!array_key_exists("utf8", $args)) {
$args["utf8"] = false;
}
// Set if this is a preview page or not
if (!array_key_exists("preview", $args)) {
$args["preview"] = null;
}
// Set if we shoud show the tite in html_header() or not
if (!array_key_exists("no_auto_title", $args)) {
$args["no_auto_title"] = false;
}
// Set if MathML is used or not
if (!array_key_exists("mathml", $args)) {
if ( !is_null($args["preview"])
&& array_key_exists("mathml", $args["preview"])) {
$args["mathml"] = $args["preview"]? true: false;
} else {
$args["mathml"] = false;
}
}
// Set all the available languages
if (!array_key_exists("all_linguas", $args)) {
$args["all_linguas"] = $GLOBALS["ALL_LINGUAS"];
}
// Set the language of the title
if (!array_key_exists("title_lang", $args)) {
$args["title_lang"] = $args["lang"];
}
// The upper level index page
if (!array_key_exists("up", $args)) {
$langfile = ln($args["lang"], LN_FILENAME);
// Certain pages that has no upper level index page
$rootdir = preg_replace("/^\/$langfile\/([^\/]*\/?).*?$/", "$1", $args["path"]);
switch ($rootdir) {
case "errors/":
case "longdesc/":
break;
default:
// See the directory where I belongs
$args["up"] = preg_replace("/[^\/]+\/?$/", "", $args["path"]);
// The home page path
$home = count($GLOBALS["ALL_LINGUAS"]) > 1? "/$langfile/": "/";
// Above the home -- go to the home page
if (substr($args["up"], 0, strlen($home)) != $home) {
$args["up"] = $home;
}
}
}
// Set the URLs of the language variants
if (!array_key_exists("altlang", $args)) {
set_altlang_urls($args);
}
// Load the local extension
if (function_exists("page_param_site")) {
$args = page_param_site($args);
}
if (function_exists("page_param_script")) {
$args = page_param_script($args);
}
// Tag that we have fixed this
$args[".fixed"] = true;
return $args;
}
// page_tree: Get the page tree in a directory
function page_tree($path, $lang, $preview = null)
{
// Get the available language list
global $ALL_LINGUAS;
// Set the language
$langfile = ln($lang, LN_FILENAME);
$lndb = ln($lang, LN_DATABASE);
$islnpre = preg_match("/^\/$langfile\//", $path)? true: false;
$lnpre = $islnpre? "/$langfile": "";
// Obtain the directory
$dir = preg_replace("/[^\/]*$/", "", $path);
if ($islnpre) {
$dir = preg_replace("/^\/$langfile/", "", $dir);
}
// Cache the result
static $cache = array();
// Initialize the directory array
if (!array_key_exists($dir, $cache)) {
$cache[$dir] = array();
}
// Return the cache
if (array_key_exists($lang, $cache[$dir])) {
return $cache[$dir][$lang];
}
// Initialize the result
$tree = array();
// Disable the page tree of error documents
if ($dir == "/errors/") {
$_path = $path;
if ($islnpre) {
$_path = preg_replace("/^\/$langfile/", "", $_path);
}
$title = count($ALL_LINGUAS) > 1? "title_$lndb": "title";
$select = "SELECT $title AS title from pages"
. " WHERE path='" . sql_esctext($_path) . "';\n";
$result = sql_query($select);
$row = sql_fetch_assoc($result);
$tree["index"] = array(
"path" => $path,
"_path" => $_path,
"title" => $row["title"]);
return $tree;
}
// Get the index page
$conds = array();
$conds[] = "path='" . sql_esctext($dir) . "'";
if (count($ALL_LINGUAS) > 1) {
$conds[] = "title_$lndb IS NOT NULL";
}
$conds[] = sql_is_false("hid");
$select = "SELECT * from pages"
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
$count = sql_num_rows($result);
// Index page exists
if ($count == 1) {
$row = sql_fetch_assoc($result);
$tree["index"] = array(
"path" => $lnpre . $dir,
"_path" => $dir,
"title" => count($ALL_LINGUAS) > 1?
$row["title_$lndb"]: $row["title"]);
}
// Get the page tree
$pages = _page_tree($dir, $lang, $lnpre, $preview);
if (!is_null($pages)) {
$tree["pages"] =& $pages;
}
// Nothing found
if ( !array_key_exists("index", $tree)
&& !array_key_exists("pages", $tree)) {
$cache[$dir][$lang] = null;
return null;
}
// Cache it
$cache[$dir][$lang] = $tree;
return $tree;
}
// _page_tree: Get the page tree
function _page_tree($dir, $lang, $lnpre, $preview = null)
{
// Get the available language list
global $ALL_LINGUAS;
// Cache the result
static $cache = array();
// Initialize the directory array
if (!array_key_exists($dir, $cache)) {
$cache[$dir] = array();
}
// Return the cache
if (array_key_exists($lang, $cache[$dir])) {
return $cache[$dir][$lang];
}
// Set the language
$lndb = ln($lang, LN_DATABASE);
// Get the related pages
$tree = array();
// Set the columns list
$cols = array();
if ($lnpre == "") {
$cols[] = "path AS path";
} else {
$cols[] = sql_strcat("'$lnpre'", "path") . " AS path";
}
$cols[] = "path AS _path";
if (count($ALL_LINGUAS) > 1) {
$cols[] = "title_$lndb AS title";
} else {
$cols[] = "title AS title";
}
$cols[] = "ord AS ord";
// Set the criteria
$conds = array();
$conds[] = "path LIKE '" . sql_esclike($dir) . "_%'";
$conds[] = "path NOT LIKE '" . sql_esclike($dir) . "_%/_%'";
if (count($ALL_LINGUAS) > 1) {
$conds[] = "title_$lndb IS NOT NULL";
}
// Skip the original file
if (!is_null($preview) && array_key_exists("sn", $preview)) {
$conds[] = "sn!=" . $preview["sn"];
}
// Set the order key
$orderbys = array();
$orderbys[] = "ord";
if (count($ALL_LINGUAS) > 1) {
$orderbys[] = "title_$lndb";
} else {
$orderbys[] = "title";
}
$orderbys[] = "path";
$conds[] = sql_is_false("hid");
$select = "SELECT " . implode(", ", $cols) . " FROM pages"
. " WHERE " . implode(" AND ", $conds)
. " ORDER BY " . implode(", ", $orderbys) . ";\n";
$result = sql_query($select);
$count = sql_num_rows($result);
for ($i = 0; $i < $count; $i++) {
$tree[] = sql_fetch_assoc($result);
}
// Insert the preview
if (!is_null($preview) && dirname($preview["path"]) . "/" == $dir) {
array_push($tree, array(
"path" => $lnpre . $preview["path"],
"_path" => $preview["path"],
"title" => $preview["title"],
"ord" => $preview["ord"]
));
// Sort again
usort($tree, "cmp_page_tree");
}
// Recur into subdirectories
for ($i = 0; $i < count($tree); $i++) {
if (substr($tree[$i]["path"], -1) != "/") {
continue;
}
$tree[$i]["sub"] = array();
$tree[$i]["sub"]["index"] = array(
"path" => $tree[$i]["path"],
"_path" => $tree[$i]["_path"],
"title" => $tree[$i]["title"]
);
$subtree = _page_tree($tree[$i]["_path"], $lang, $lnpre, $preview);
if (!is_null($subtree)) {
$tree[$i]["sub"]["pages"] = $subtree;
}
}
// Nothing found
if (count($tree) == 0) {
$cache[$dir][$lang] = null;
return null;
}
// Cache it
$cache[$dir][$lang] = $tree;
return $tree;
}
// cmp_page_tree: Sort the page tree again after inserting a preview
function cmp_page_tree($page1, $page2)
{
// Compare the order
if ($page1["ord"] != $page2["ord"]) {
return $page1["ord"] - $page2["ord"];
}
// Compare the title
if ($page1["title"] != $page2["title"]) {
return strcmp($page1["title"], $page2["title"]);
}
// Compare the path
return strcmp($page1["path"], $page2["path"]);
}
// hash_tree: Make a hash of the page tree
function hash_tree(&$tree)
{
$hash = array();
// The index page
if (array_key_exists("index", $tree)) {
$hash[$tree["index"]["path"]] =& $tree;
}
// Track the subdirectories
if (array_key_exists("pages", $tree)) {
for ($i = 0; $i < count($tree["pages"]); $i++) {
// A subdirectory exists
if (array_key_exists("sub", $tree["pages"][$i])) {
$hash = array_merge($hash,
hash_tree($tree["pages"][$i]["sub"]));
}
}
}
return $hash;
}
// hash_page: Make a hash of the page tree
function hash_page(&$tree)
{
$hash = array();
// The index page
if (array_key_exists("index", $tree)) {
$hash[$tree["index"]["path"]] =& $tree["index"];
}
// Track the subdirectories
if (array_key_exists("pages", $tree)) {
for ($i = 0; $i < count($tree["pages"]); $i++) {
// A plain page
if (!array_key_exists("sub", $tree["pages"][$i])) {
$hash[$tree["pages"][$i]["path"]] =& $tree["pages"][$i];
// A subdirectory
} else {
$hash = array_merge($hash,
hash_page($tree["pages"][$i]["sub"]));
}
}
}
return $hash;
}
// page_all_linguas: Get the available languages for this page
function page_all_linguas($page)
{
// Get the available language list
global $ALL_LINGUAS;
// It is specified
if (array_key_exists("all_linguas", $page)) {
return $page["all_linguas"];
}
// Preview
if (array_key_exists("preview", $page) && $page["preview"]) {
// Uni-lingual
if (!sql_is_ml_table(THIS_TABLE)) {
return array(getlang());
}
// Find the page
if (!array_key_exists("sn", $page)) {
return array(getlang());
}
$select = "SELECT * FROM " . THIS_TABLE
. " WHERE sn=" . $page["sn"] . ";\n";
$result = sql_query($select);
// If this record exist
if (sql_num_rows($result) == 0) {
return array(getlang());
}
$row = sql_fetch_assoc($result);
// Check each language
$page_all_linguas = array();
for ($l = 0; $l < count($ALL_LINGUAS); $l++) {
$lang = $ALL_LINGUAS[$l];
$lndb = ln($lang, LN_DATABASE);
// Add it if the content in this language exists
if (!is_null($row["title_$lndb"]) || $lang == getlang()) {
$page_all_linguas[] = $lang;
}
}
return $page_all_linguas;
}
// $page is uni-lingual
if (array_key_exists("title", $page)) {
return array(getlang());
}
// $page is multi-lingual
// Check each language
$page_all_linguas = array();
for ($l = 0; $l < count($ALL_LINGUAS); $l++) {
$lang = $ALL_LINGUAS[$l];
$lndb = ln($lang, LN_DATABASE);
// Add it if the content in this language exists
if (!is_null($page["title_$lndb"])) {
$page_all_linguas[] = $lang;
}
}
return $page_all_linguas;
}
// outpage: Output a page
function outpage($content, $path, $lang = null)
{
if (is_null($lang)) {
$lang = getlang();
}
$langfile = ln($lang, LN_FILENAME);
// An HTML file or directory index
if (substr($path, -5) == ".html" || substr($path, -1) == "/") {
// The page path in multi-lingual context
$lnpath = (count($GLOBALS["ALL_LINGUAS"]) > 1)?
"/$langfile$path": $path;
// Convert the URLs to relative
if (substr($path, 0, 8) == "/errors/") {
$content = page2abs($content, $lnpath, REL2ABS_RDIFF_STRIP);
// $url variable is handled inside of page2abs();
} else {
$content = page2rel($content, $lnpath);
}
// Encode the e-mail at-signs (@)
$content = str_replace("@", "&#64;", $content);
// Decode the e-mail at-signs (@) of spamtrap
$content = str_replace("spamtrap&#64;", "spamtrap@", $content);
// Encode the page to the target character set
$content = page_encode($content, ln($lang, LN_CHARSET));
// Obtain the real file name
$file = DOC_ROOT . $lnpath;
if (substr($file, -1) == "/") {
$file .= "index.html";
}
// Create the necessary directories
mkalldir(dirname($file));
// Write the file
xfupdate_template("$file.xhtml", $content);
// Make the symbolic link for the text/html
$targfile = basename("$file.xhtml");
$linkfile = "$file.html";
if (!is_link($linkfile) || readlink($linkfile) != $targfile) {
if (file_exists($linkfile)) {
if (is_dir($linkfile)) {
rmalldir($linkfile);
} else {
unlink($linkfile);
}
}
symlink($targfile, $linkfile);
}
// An RSS file or OpenSearch description document
} elseif (substr($path, -8) == "/rss.xml" || substr($path, -7) == "osd.xml") {
// The page path in multi-lingual context
$lnpath = (count($GLOBALS["ALL_LINGUAS"]) > 1)?
"/$langfile$path": $path;
// Encode the e-mail at-signs (@)
$content = str_replace("@", "&#64;", $content);
// Decode the e-mail at-signs (@) of spamtrap
$content = str_replace("spamtrap&#64;", "spamtrap@", $content);
// Encode the page to the target character set
// XML is not HTML, so HTML character entity reference should not be used.
$content = page_encode($content, ln($lang, LN_CHARSET), UNICODE_NO_HCEREF);
// Obtain the real file name
$file = DOC_ROOT . $lnpath;
// Create the necessary directories
mkalldir(dirname($file));
// Write the file
xfupdate_template($file, $content);
// A text file
} elseif (substr($path, -4) == ".txt") {
// The page path in multi-lingual context
$lnpath = (count($GLOBALS["ALL_LINGUAS"]) > 1)?
"/$langfile$path": $path;
// We do not encode to a target character set. This is not always
// possible for plain text files and hence not quite useful.
// Hence the output are always in UTF-8.
// Encode the e-mail at-signs (@)
$content = str_replace("@", "-at-", $content);
// Obtain the real file name
$file = DOC_ROOT . $lnpath;
// Create the necessary directories
mkalldir(dirname($file));
// Write the file
xfupdate_template($file, $content);
// A PDF file
} elseif (substr($path, -4) == ".pdf") {
// The page path in multi-lingual context
$lnpath = (count($GLOBALS["ALL_LINGUAS"]) > 1)?
"/$langfile$path": $path;
// Obtain the real file name
$file = DOC_ROOT . $lnpath;
// Create the necessary directories
mkalldir(dirname($file));
// Write the file
xfupdate($file, $content);
// A JavaScript file
} elseif (substr($path, -3) == ".js") {
// The page path in multi-lingual context
$lnpath = (count($GLOBALS["ALL_LINGUAS"]) > 1)?
substr($path, 0, -3) . ".$langfile.js": $path;
// Encode the e-mail at-signs (@)
$content = str_replace("@", "&#64;", $content);
// Encode the page to the target character set
$content = page_encode($content, ln($lang, LN_CHARSET));
// Obtain the real file name
$file = DOC_ROOT . $lnpath;
// Create the necessary directories
mkalldir(dirname($file));
// Write the file
xfupdate_template($file, $content);
}
return;
}
// readpage: Read from an include page
function readpage($path, $lang = null)
{
if (is_null($lang)) {
$lang = getlang();
}
$charset = ln($lang, LN_CHARSET);
$file = DOC_ROOT . $path;
if (count($GLOBALS["ALL_LINGUAS"]) > 1) {
$file = sprintf($file, ln($lang, LN_FILENAME));
}
$content = xfread($file);
// Try to decode with the specified encoding
$GLOBALS["php_errormsg"] = null;
set_error_handler("null_error_handler");
$content = iconv($charset, "UTF-8", $content);
restore_error_handler();
// Wrong encoding
if (!is_null($GLOBALS["php_errormsg"])) {
trigger_error("Failed decoding $file as $charset", E_USER_ERROR);
// In case when error handler is disabled
return null;
}
// An HTML file or XHTML file
if (substr($file, -5) == ".html" || substr($file, -6) == ".xhtml") {
// Decode the HTML character references
$content = a_hcref2char($content);
}
return $content;
}
// array_keys_ml: Return a list of multi-lingual keys in an associative array
function array_keys_ml(&$arr)
{
// Get the columns that have language variants
$suffix = "_" . getlang(LN_DATABASE);
$len = strlen($suffix);
$keys = array_keys($arr);
$mlkeys = array();
for ($i = 0; $i < count($keys); $i++) {
// It has a language suffix
if (substr($keys[$i], -$len) == $suffix) {
$mlkeys[] = substr($keys[$i], 0, -$len);
}
}
return $mlkeys;
}
// array_keys_nl: Return a list of keys without their multi-lingual
// deviants in an associative array
function array_keys_nl(&$arr)
{
$keys = array_keys($arr);
$mlkeys = array_keys_ml($arr);
// Remove those language variants
$nlkeys = array();
for ($i = 0; $i < count($keys); $i++) {
$pos = strrpos($keys[$i], "_");
// No suffix
if ($pos === false) {
$nlkeys[] = $keys[$i];
// Check the prefix
} else {
$prefix = substr($keys[$i], 0, $pos);
// The prefix is one of the language columns
if (in_array($prefix, $mlkeys)) {
// Not counted yet
if (!in_array($prefix, $nlkeys)) {
$nlkeys[] = $prefix;
}
// An ordinary prefix
} else {
$nlkeys[] = $keys[$i];
}
}
}
return $nlkeys;
}
// page_title: Obtain a page title
function page_title($sn)
{
// Cache the result
static $cache = array();
// Bounce if there is any problem with $sn
if (is_null($sn)) {
return t_notset();
}
// Return the cache
if (array_key_exists($sn, $cache)) {
return $cache[$sn];
}
// Check the serial number first
if (!check_sn($sn)) {
$cache[$sn] = t_na();
return $cache[$sn];
}
// Query
// Default language
if (getlang() == DEFAULT_LANG) {
$title = "title_" . getlang(LN_DATABASE) . " AS title";
// Fall back to the default language
} else {
$title = "COALESCE(title_" . getlang(LN_DATABASE) . ","
. " title_" . ln(DEFAULT_LANG, LN_DATABASE) . ") AS title";
}
$select = "SELECT $title FROM pages"
. " WHERE sn=$sn;\n";
$result = sql_query($select);
// Not found
if (sql_num_rows($result) != 1) {
$cache[$sn] = t_na();
return $cache[$sn];
}
// Found
$row = sql_fetch_assoc($result);
$cache[$sn] = $row["title"];
return $cache[$sn];
}
// page_path: Obtain a page path
function page_path($sn)
{
// Cache the result
static $cache = array();
// Bounce if there is any problem with $sn
if (is_null($sn)) {
return t_notset();
}
// Return the cache
if (array_key_exists($sn, $cache)) {
return $cache[$sn];
}
// Check the serial number first
if (!check_sn($sn)) {
$cache[$sn] = t_na();
return $cache[$sn];
}
// Query
$select = "SELECT path FROM pages WHERE sn=$sn;\n";
$result = sql_query($select);
// Not found
if (sql_num_rows($result) != 1) {
$cache[$sn] = t_na();
return $cache[$sn];
}
// Found
$row = sql_fetch_assoc($result);
$cache[$sn] = $row["path"];
return $cache[$sn];
}
// rebuildtype_options: Obtain a rebuild type options list
function rebuildtype_options($value)
{
// The type labels
$labels = array(
"pages" => C_("Web pages"),
"news" => C_("News"),
"links" => C_("Related links"),
"home" => C_("Home page"),
"all" => C_("Whole web site"),
);
if (array_key_exists("REBUILD_LABELS", $GLOBALS)) {
global $REBUILD_LABELS;
foreach (array_keys($REBUILD_LABELS) as $type) {
$labels[$type] = _($REBUILD_LABELS[$type]);
}
}
// Get the available rebuild types
$allfuncs = get_defined_functions();
$opts = array();
foreach ($allfuncs["user"] as $func) {
if (substr($func, 0, 8) == "rebuild_") {
$type = substr($func, 8);
// Skip rebuild_a_page()
// To be removed -- only for DK-Taipei now.
if ($type == "a_page") {
continue;
}
$label = array_key_exists($type, $labels)?
$labels[$type]: $type;
$opts[] = array(
"value" => $type,
"content" => $label,
);
}
}
// Obtain the HTML
$html = opt_list_array($opts);
return preselect_options($html, $value);
}
?>