view msitegen.inc.php @ 1096:bbc0a3d0b51e

Major renaming / refactor of site messages. Some that were previously modifiable from admin interface are now "hardcoded" in the configuration file. Having these settings made modifiable from there made no sense and just took space in the UI.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 27 Jan 2017 22:15:06 +0200
parents 7bfa5a38b6ca
children c9c73d2c4702
line wrap: on
line source

<?php
//
// FAPWeb - Simple Web-based Demoparty Management System
// Generic and miscellaneous site support code
// (C) Copyright 2012-2017 Tecnic Software productions (TNSP)
//

// Globals and definitions
$errorSet = FALSE;
$errorMsgs = array();
$statusSet = 0;
$statusMsg = "";

// Value types
define("VT_STR", 1);
define("VT_INT", 2);
define("VT_BOOL", 3);
define("VT_TEXT", 4);

// Validation check types
define("CHK_TYPE", 1);
define("CHK_ISLT", 2);
define("CHK_ISGT", 3);
define("CHK_ISEQ", 4);
define("CHK_GTEQ", 5);
define("CHK_LTEQ", 6);
define("CHK_RANGE", 7);
define("CHK_CUSTOM", 8);
define("CHK_ARRAY_KEY", 9);
define("CHK_ARRAY_VAL", 10);


function stDebug($msg)
{
  if (stGetSetting("debug"))
    error_log("FAPWeb[D]: ".$msg);
}


function stLogError($msg)
{
  error_log("FAPWeb[E]: ".$msg);
  return FALSE;
}


function stLogSQLError($dbh, $sql)
{
  return stLogError("SQL error '".implode("; ", $dbh->errorInfo())."' in statement: \"".$sql."\"");
}


function stError($msg)
{
  global $errorSet, $errorMsgs;
  $errorSet = TRUE;
  $errorMsgs[] = $msg;
  return FALSE;
}


function stSetStatus($status, $msg)
{
  global $statusSet, $statusMsg;
  $statusMsg = $msg;
  $statusSet = $status;
}


function stDumpAJAXStatusErrors()
{
  global $errorSet, $errorMsgs, $statusSet, $statusMsg;

  if ($errorSet && !$statusSet)
    stSetStatus(902, "Error");

  if ($statusSet)
  {
    header("HTTP/1.0 ".$statusSet." ".$statusMsg);
    header("Status: ".$statusSet." ".$statusMsg);
  }
    
  if ($errorSet)
  {
    echo
      "<h1>Following errors occured</h1>\n".
      "<ul>\n";

    foreach ($errorMsgs as $msg)
      echo " <li>".chentities($msg)."</li>\n";

    echo "</ul>\n";
  }
}


function stCheckHTTPS()
{
  return isset($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] != "" && $_SERVER["HTTPS"] != "off");
}


function stSetupCacheControl()
{
  header("Cache-Control: must-revalidate, no-store, private");
  header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
}


function stGetSQLSettingData($item)
{
  switch ($item["vtype"])
  {
    case VT_INT:  return intval($item["vint"]);
    case VT_BOOL: return intval($item["vint"]) ? true : false;
    case VT_STR:  return $item["vstr"];
    case VT_TEXT: return $item["vtext"];
  }
}


function stGetSettingSQL($item, $val)
{
  global $db;
  switch ($item["vtype"])
  {
    case VT_INT:  return "vint=".intval($val); break;
    case VT_BOOL: return "vint=".($val ? "1" : "0"); break;
    case VT_STR:  return "vstr=".$db->quote($val); break;
    case VT_TEXT: return "vtext=".$db->quote($val); break;
    default:      return FALSE;
  }
}


function stReloadSettings()
{
  global $siteSettings;

  if (($res = stExecSQL("SELECT * FROM settings")) !== FALSE)
  {
    foreach ($res as $item)
      $siteSettings[$item["key"]] = stGetSQLSettingData($item);
  }
  else
    die("Error fetching site settings.");
}


function stGetSetting($name, $default = FALSE)
{
  global $siteSettings;
  if (isset($siteSettings[$name]))
    return $siteSettings[$name];
  else
  if ($default !== FALSE)
    return $default;
  else
  {
    stLogError("No config value for '".$name."'");
    die("No config value for '".$name."'.\n");
  }
}


function stChkSetting($name)
{
  global $siteSettings;
  return isset($siteSettings[$name]) && $siteSettings[$name];
}


function dhentities($str)
{
  return str_replace(array("&lt;","&gt;"), array("<", ">"),
    htmlentities($str, ENT_NOQUOTES, "UTF-8"));
}


function chentities($str)
{
  return htmlentities($str, ENT_NOQUOTES, "UTF-8");
}


function ihentities($str)
{
  return htmlentities($str, ENT_QUOTES, "UTF-8");
}


//
// Helper functions for form/HTML elements
// XXX/TODO .. this name/id/prefix mess needs to be cleaned up.
//
function stGetIDName($name, $id, $prefix = "")
{
  return
    ($id != "" ? "id=\"".$prefix.$name.$id."\" " : "").
    ($name != "" ? "name=\"".$prefix.$name.$id."\" " : "");
}


function stGetFormCheckBoxInput($name, $id, $prefix, $checked, $label, $extra = "")
{
  return
    "<input ".$extra." type=\"checkbox\" ".stGetIDName($name, $id, $prefix).
    ($checked ? "checked=\"checked\" " : "")." />".
    ($label != "" ? "<label for=\"".$prefix.$name.$id."\">".$label."</label>" : "");
}


function stGetFormRadioButtonInput($name, $id, $prefix, $value, $checked, $label, $extra = "")
{
  return
    "<input ".$extra." type=\"radio\" ".stGetIDName($name, $id, $prefix).
    ($checked ? "checked=\"checked\" " : "")." value=\"".$value."\" />".
    ($label != "" ? "<label for=\"".$prefix.$name.$id."\">".$label."</label>" : "");
}


function stGetFormButtonInput($name, $id, $prefix, $label, $onclick = "")
{
  return
    "<input type=\"button\" ".stGetIDName($name, $id, $prefix).
    "value=\" ".ihentities($label)." \" ".
    ($onclick != "" ? "onClick=\"".$onclick."\"" : "")." />";
}


function stGetFormButtonElement($name, $id, $prefix, $label, $onclick = "")
{
  return
    "<button class=\"button\" ".stGetIDName($name, $id, $prefix)." type=\"button\"".
    ($onclick != "" ? " onClick=\"".$onclick."\"" : "")."> ".chentities($label)." </button>";
}


function stGetFormTextArea($rows, $cols, $name, $id, $prefix, $value, $extra = "")
{
  return
    "<textarea ".$extra." ".stGetIDName($name, $id, $prefix).
    "rows=\"".$rows."\" cols=\"".$cols."\">".
    (isset($value) ? ihentities($value) : "").
    "</textarea>";
}


function stGetFormTextInput($size, $len, $name, $id, $prefix, $value, $extra = "")
{
  return
    "<input ".$extra." type=\"text\" ".stGetIDName($name, $id, $prefix).
    "size=\"".$size."\" maxlength=\"".$len."\"".
    (isset($value) ? " value=\"".ihentities($value)."\"" : "").
    " />";
}


function stGetFormPasswordInput($name, $id, $prefix, $extra = "")
{
  return
    "<input type=\"password\" ".stGetIDName($name, $id, $prefix)." ".$extra." />";
}


function stGetFormSubmitInput($name, $label, $onclick = "")
{
  return
    "<input type=\"submit\" name=\"".$name.
    "\" value=\" ".ihentities($label)." \" ".
    ($onclick != "" ? "onClick=\"".$onclick."\"" : "")." />";
}


function stGetFormHiddenInput($name, $value)
{
  return
    "<input type=\"hidden\" name=\"".$name.
    "\" value=\"".ihentities($value)."\" />";
}


function stGetFormStart($name, $action = FALSE, $method = FALSE, $extra = FALSE)
{
  $str =
    "<form name=\"".$name."\"".
    ($action !== FALSE ? " action=\"".$action."\"" : "").
    " method=\"".($method !== FALSE ? $method : "post")."\"".
    ($extra !== FALSE ? " ".$extra : "").">\n";

  if (($csrfID = stGetSessionItem("csrfID", FALSE)) !== FALSE)
    $str .= stGetFormHiddenInput("csrfID", $csrfID)."\n";
  
  return $str;
}


function stGetFormOptionListStart($id, $indent, $outer, $size = 10, $onChange = "")
{
  return
    ($outer ? $indent."<div id=\"".$id."\">\n" : "").
    $indent."<select class=\"selectBox\" id=\"".$id."Sel\"".
    ($size > 0 ? " size=\"".$size."\"" : "").
    ($onChange != "" ? " onChange=\"".$onChange."\"" : "").">\n";
}


function stGetFormOptionListItem($indent, $value, $active, $name)
{
  return
    $indent."<option value=\"".$value."\"".
    ($active ? " selected=\"selected\"" : "").
    ">".str_replace(" ", "&nbsp;", chentities($name))."</option>\n";
}


function stGetFormOptionListEnd($indent, $outer)
{
  return
    $indent."</select>\n".
    ($outer ? $indent."</div>\n" : "");
}


function stGetFormOptionListFromArray($id, $indent, $outer, $data, $active, $size = 10, $arrIndex = 0, $onChange = "")
{
  $str = stGetFormOptionListStart($id, $indent, $outer, $size, $onChange);

  foreach ($data as $key => $value)
  {
    $str .= stGetFormOptionListItem($indent." ", $key,
      ($key == $active),
      is_array($value) ? $value[$arrIndex] : $value);
  }

  return $str.stGetFormOptionListEnd($indent, $outer);
}


function stErrorStrF($fmt)
{
  $argc = func_num_args();
  $argv = func_get_args();
  
  $len = strlen($fmt);
  $str = "";
  $argn = 1;
  for ($pos = 0; $pos < $len; $pos++)
  {
    if ($fmt[$pos] == "%")
    {
      $pos++;
      if ($fmt[$pos] == "%")
        $str .= "%";
      else
      {
        $n = intval($fmt[$pos]);
        if ($n >= 1 && $n < $argc)
          $str .= $argv[$n];
        else
        {
          stLogError("Invalid stErrorStrF() format string, arg #".$n.
            " referenced, but only has ".$argc." arguments: '".$fmt."'\n");
          return FALSE;
        }
      }
    }
    else
      $str .= $fmt[$pos];
  }
  
  stError($str);
  return FALSE;
}


//
// Check and validate one item from $_REQUEST[], based on
// list of validation conditions. For example:
//
//  stChkRequestItem("name", FALSE,
//    array(CHK_ISGT, VT_STR, 0, "Handle / name not given."),
//    array(CHK_ISGT, VT_STR, 3, "Handle / name too short, should be 3 characters or more."),
//    array(CHK_LTEQ, VT_STR, SET_LEN_USERNAME, "Handle / name is too long, should be less than ".SET_LEN_USERNAME." characters."),
//    array(CHK_RANGE, VT_STR, array(3, SET_LEN_USERNAME), "Ulululu!"),
//                             ^- ranges specified as array of MIN and MAX values (inclusive)
//
//    array(CHK_CUSTOM, VT_STR, function($value) { return FALSE; }, "Error! Error!"),
//                              ^- can be any callable/anonymous function etc.
//    ...
//
function stChkRequestDataItem($type, $value, $cmp)
{
  switch ($type)
  {
    case CHK_ISLT : return $value <  $cmp;
    case CHK_ISGT : return $value >  $cmp;
    case CHK_ISEQ : return $value == $cmp;
    case CHK_LTEQ : return $value <= $cmp;
    case CHK_GTEQ : return $value >= $cmp;
    case CHK_RANGE:
      if (!is_array($cmp))
        return FALSE;
      else
        return ($value >= $cmp[0] && $value <= $cmp[1]);
      break;
    default: return FALSE;
  }
}


function stDoCheckRequestItem($name, &$sdata, $nindex, $argc, $argv)
{
  if (stGetSetting("debug"))
  {
    if (!isset($_REQUEST[$name]))
      return stErrorStrF("Required data item '%1' not set.", $name);

    $data = trim($_REQUEST[$name]);
  }
  else
  {
    if (!isset($_POST[$name]))
      return stErrorStrF("Required data item '%1' not set.", $name);

    $data = trim($_POST[$name]);
  }
  
  $slen = strlen($data);


  // Go through list of validation checks
  for ($argn = $nindex; $argn < $argc; $argn++)
  {
    // Act according to check type
    $check = $argv[$argn];
    switch ($check[0])
    {
      case CHK_TYPE:
        // Check type of the data
        switch ($check[1])
        {
          case VT_STR:
            if ($slen == 0)
              return stErrorStrF($check[2], $slen);
            break;

          case VT_INT:
          case VT_BOOL:
            if ($slen == 0 || !is_numeric($data))
              return stErrorStrF($check[2], $data);
            else
              $data = intval($data);
            break;
        }
        break;

      case CHK_ISLT: case CHK_ISGT: case CHK_ISEQ:
      case CHK_GTEQ: case CHK_LTEQ: case CHK_RANGE:
        // Check length or value of the data
        switch ($check[1])
        {
          case VT_STR:
          case VT_TEXT:
            // Strings get their length checked
            if (!stChkRequestDataItem($check[0], $slen, $check[2]))
                return stErrorStrF($check[3], $slen, $check[2]);
            break;

          case VT_INT:
          case VT_BOOL:
            // Integer values checked against .. value
            if (!stChkRequestDataItem($check[0], intval($data), $check[2]))
                return stErrorStrF($check[3], intval($data), $check[2]);
            break;
        }
        break;

      case CHK_ARRAY_KEY:
        if (!isset($check[1][$data]))
          return stErrorStrF($check[2], $data);
        break;

      case CHK_ARRAY_VAL:
        if (!in_array($data, $check[1], TRUE))
          return stErrorStrF($check[2], $data);
        break;

      case CHK_CUSTOM:
        // Call a custom function (or closure)
        $func = $check[1];
        if (!is_callable($func) || !$func($data))
          return stErrorStrF($check[2], $data);
        break;
    }
  }

  if ($sdata !== FALSE)
    $sdata = $data;

  return TRUE;
}


function stChkRequestItem($name, &$sdata)
{
  return stDoCheckRequestItem($name, $sdata, 2, func_num_args(), func_get_args());
}


function stChkRequestItemFail($name, &$sdata, &$sfail)
{
  $sres = stDoCheckRequestItem($name, $sdata, 3, func_num_args(), func_get_args());
  if ($sres !== TRUE) $sfail = FALSE;
  return $sres;
}


function stTrimIfString($val)
{
  if (is_string($val))
    return trim($val);
  else
    return $val;
}


function stGetRequestItem($name, $default = "", $allowGet = FALSE)
{
  if ($allowGet || stGetSetting("debug"))
    return isset($_REQUEST[$name]) ? stTrimIfString($_REQUEST[$name]) : $default;
  else
    return isset($_POST[$name]) ? stTrimIfString($_POST[$name]) : $default;
}


function stConnectSQLDBSpec($dbspec)
{
  try {
    $dbh = new PDO($dbspec);
  }
  catch (PDOException $e) {
    stLogError("Could not connect to SQL database: ".$e->getMessage().".");
    return FALSE;
  }
  return $dbh;
}


function stConnectSQLDB()
{
  global $db;
  try {
    $db = new PDO(stGetSetting("sqlDB"),
      stGetSetting("sqlUsername", NULL),
      stGetSetting("sqlPassword", NULL),
      stGetSetting("sqlOptions", array()));
  }
  catch (PDOException $e) {
    stLogError("Could not connect to SQL database: ".$e->getMessage().".");
    return FALSE;
  }
  $db = stConnectSQLDBSpec(stGetSetting("sqlDB"));
  return ($db !== false);
}


function stDBGetSQLParam($dbh, $type, $value)
{
  switch ($type)
  {
    case "d": return intval($value);
    case "s": return $dbh->quote($value);
    case "b": return intval($value) ? 1 : 0;

    case "D": return intval(stGetRequestItem($value));
    case "S": return $dbh->quote(stGetRequestItem($value));
    case "Q": return $dbh->quote(stGetRequestItem($value));
    case "B": return intval(stGetRequestItem($value)) ? 1 : 0;
  }
}


function stDBPrepareSQLUpdate($dbh, $table, $cond, $pairs)
{
  $sql = array();
  foreach ($pairs as $name => $attr)
  {
    $sql[] = $name."=".stDBGetSQLParam($dbh, $attr, $name);
  }
  return
    "UPDATE ".$table." SET ".implode(",", $sql).
    ($cond != "" ? " ".$cond : "");
}


function stDBPrepareSQL($dbh)
{
  $argc = func_num_args();
  $argv = func_get_args();

  $fmt = $argv[1];
  $len = strlen($fmt);
  $sql = "";
  $argn = 2;
  for ($pos = 0; $pos < $len; $pos++)
  {
    if ($fmt[$pos] == "%")
    {
      if ($argn < $argc)
        $sql .= stDBGetSQLParam($dbh, $fmt[++$pos], $argv[$argn++]);
      else
      {
        stLogError("Invalid SQL statement format string '".$fmt.
          "', not enough parameters specified (".$argn." of ".$argc.")");
        return FALSE;
      }
    }
    else
      $sql .= $fmt[$pos];
  }

  return $sql;
}


function stPrepareSQL()
{
  global $db;
  $argc = func_num_args();
  $argv = func_get_args();

  $fmt = $argv[0];
  $len = strlen($fmt);
  $sql = "";
  $argn = 1;
  for ($pos = 0; $pos < $len; $pos++)
  {
    if ($fmt[$pos] == "%")
    {
      if ($argn < $argc)
        $sql .= stDBGetSQLParam($db, $fmt[++$pos], $argv[$argn++]);
      else
      {
        stLogError("Invalid SQL statement format string '".$fmt.
          "', not enough parameters specified (".$argn." of ".$argc.")");
        return FALSE;
      }
    }
    else
      $sql .= $fmt[$pos];
  }

  return $sql;
}


function stDBExecSQLInsert($dbh, $sql)
{
  switch ($dbh->getAttribute(PDO::ATTR_DRIVER_NAME))
  {
    case "pgsql":
      if (($res = stDBFetchSQLColumn($dbh, $sql." RETURNING id")) !== false)
        return $res;
      else
        return FALSE;

    default:
      if (stDBExecSQL($dbh, $sql) !== false)
        return $dbh->lastInsertId();
      else
        return FALSE;
  }
}


function stDBExecSQL($dbh, $sql)
{
  if (($res = $dbh->query($sql)) !== FALSE)
    return $res;
  else
  {
    stLogSQLError($dbh, $sql);
    stError("Oh noes! SQL error #23!");
    return FALSE;
  }
}


function stDBFetchSQL($dbh, $sql)
{
  if (($res = $dbh->query($sql)) !== FALSE)
    return $res->fetch();
  else
  {
    stLogSQLError($dbh, $sql);
    stError("Oh noes! SQL error #31!");
    return FALSE;
  }
}


function stDBFetchSQLColumn($dbh, $sql, $column = 0)
{
  if (($res = $dbh->query($sql)) !== FALSE)
    return $res->fetchColumn($column);
  else
  {
    stLogSQLError($dbh, $sql);
    stError("Oh noes! SQL error #81!");
    return FALSE;
  }
}


function stPrepareSQLUpdate($table, $cond, $pairs)
{
  global $db;
  return stDBPrepareSQLUpdate($db, $table, $cond, $pairs);
}


function stExecSQLInsert($sql)
{
  global $db;
  return stDBExecSQLInsert($db, $sql);
}


function stExecSQL($sql)
{
  global $db;
  return stDBExecSQL($db, $sql);
}


function stFetchSQL($sql)
{
  global $db;
  return stDBFetchSQL($db, $sql);
}


function stFetchSQLColumn($sql, $column = 0)
{
  global $db;
  return stDBFetchSQLColumn($db, $sql, $column);
}


function stDBBeginTransaction($dbh = FALSE)
{
  global $db;
  return stDBExecSQL(($dbh !== FALSE) ? $dbh : $db, "BEGIN TRANSACTION");
}


function stDBCommitTransaction($dbh = FALSE)
{
  global $db;
  return stDBExecSQL(($dbh !== FALSE) ? $dbh : $db, "COMMIT");
}


function stDBGetTableSchema($dbh, $data)
{
  $res = array();
  $driver = $dbh->getAttribute(PDO::ATTR_DRIVER_NAME);

  foreach ($data as $col)
  {
    $tmp = array();

    switch ($driver)
    {
      case "pgsql":
        foreach ($col as $elem)
        {
          // For Postgres, use SERIAL for autoincrement
          if ($elem == "AUTOINCREMENT")
            $tmp[1] = "SERIAL";
          else
            $tmp[] = $elem;
        }
        break;

      case "mysql":
        foreach ($col as $elem)
        {
          if ($elem != "AUTOINCREMENT")
            $tmp[] = "AUTO_INCREMENT";
          else
            $tmp[] = $elem;
        }
        break;

      case "sqlite":
        $tmp = $col;
        break;
      
      default:
        die("Don't know how to handle PDO driver '".$driver."' yet.\n");
    }
    
    $res[] = implode(" ", $tmp);
  }

  return implode(", ", $res);
}


function stDBCreateOneTable($dbh, $name, $schema)
{
//  echo "CREATE TABLE ".$name ." (".$schema.")\n";
  return (stDBExecSQL($dbh, "CREATE TABLE ".$name." (".$schema.")") !== FALSE) ? TRUE : FALSE;
}


function stSubStrCmp($str, $cmp, $send = FALSE)
{
  if ($send)
    return substr($str, -strlen($cmp)) == $cmp;
  else
    return substr($str, 0, strlen($cmp)) == $cmp;
}


function stStrChop($str, $len)
{
  return (mb_strlen($str) > $len) ? mb_substr($str, 0, $len - 3)."..." : $str;
}


function stStrChopPad($str, $len)
{
  $tmp = stStrChop($str, $len);
  for ($i = mb_strlen($tmp); $i < $len; $i++)
    $tmp .= " ";
  return $tmp;
}


$stStrAtimeData =
[
  [ 30*24*60*60, "month"  , "months" ],
  [  7*24*60*60, "week"   , "weeks" ],
  [    24*60*60, "day"    , "days" ],
  [       60*60, "hour"   , "hours" ],
  [          60, "minute" , "minutes" ],
];


function stStrAtime($val)
{
  global $stStrAtimeData;

  $res = [];
  foreach ($stStrAtimeData as $data)
  if ($val >= $data[0])
  {
    $tmp = $val / $data[0];
    $val = $val % $data[0];
    $res[] = $tmp." ".($tmp > 1 ? $data[2] : $data[1]);
  }
  return implode(", ", $res);
}


function cmPrintCSSLine($filename, $media = FALSE)
{
  echo
    "  <link rel=\"stylesheet\" href=\"".$filename.
    "\" type=\"text/css\" ".($media !== FALSE ? "media=\"".$media."\"": "")." />\n";
}


function cmPrintPageHeader($pageTitle, $pageExtra = "", $useContents = TRUE)
{
  global $pageCSS, $pageCSSIndex, $pageCharset, $pageAuthor, $pageCSSData, $pageUrchin;

  if (!isset($pageCSS))
  {
    if (!isset($pageCSSData))
    {
      $pageCSSData = array(
        "cookie" => "docscss",
        "prefix" => "/css/docs",
      );
    }

    if (isset($_GET["css"]))
    {
      $pageCSSIndex = intval($_GET["css"]);
      setcookie($pageCSSData["cookie"], $pageCSSIndex, time() + 365*24*60*60, "/"); // expire in a year
    }
    else
    {
      $pageCSSIndex = isset($_COOKIE[$pageCSSData["cookie"]]) ? intval($_COOKIE[$pageCSSData["cookie"]]) : 1;
    }
    $pageCSS = $pageCSSData["prefix"].$pageCSSIndex.".css";
  }

  echo
  "<!DOCTYPE html>\n".
  "<html>\n".
  "<head>\n".
  "  <meta charset=\"".$pageCharset."\">\n".
  "  <meta http-equiv=\"Content-type\" content=\"text/html;charset=".$pageCharset."\">\n".
  "  <title>".strip_tags($pageTitle)."</title>\n".
  $pageExtra;

  if (is_array($pageCSS))
  {
    foreach ($pageCSS as $uri => $media)
      cmPrintCSSLine($uri, $media);
  }
  else
  {
    cmPrintCSSLine($pageCSS, FALSE);
  }

  echo
  "</head>\n".
  "<body>\n";

  if (isset($pageUrchin) && file_exists($pageUrchin))
    require_once $pageUrchin;
  else
  if (file_exists("urchin.inc.php"))
    require_once "urchin.inc.php";

  echo "<div id=\"messageBox\"></div>\n";

  if ($useContents)
    echo "<div id=\"contents\">\n";
}


function cmPrintPageFooter($useContents = TRUE)
{
  if ($useContents)
    echo "</div>\n";

  echo "</body>\n</html>\n";
}


function cmQM($msg)
{
  global $pageTranslations, $pageLang;

  if (isset($pageTranslations[$msg]) && isset($pageTranslations[$msg][$pageLang]))
    $str = $pageTranslations[$msg][$pageLang];
  else
    $str = $msg;
  
  foreach (func_get_args() as $argn => $argv)
    $str = preg_replace("/\%".$argn."/", $argv, $str);
  return $str;
}


function stCommonAJAX($backend, $failover)
{
?>
function jsSendPOSTRequest(params, success, failure)
{
<?php
  if (($csrfID = stGetSessionItem("csrfID", FALSE)) !== FALSE)
    echo "  params += \"&csrfID=".$csrfID."\";\n";
  else
    echo "// No CSRF?\n";
?>
  var req = jsCreateXMLRequest();
  req.open("POST", "<?php echo $backend ?>", true);
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  req.setRequestHeader("Content-length", params.length);
  req.setRequestHeader("Connection", "close");

  req.onreadystatechange = function()
  {
    if (req.readyState == 4)
    {
      switch (req.status)
      {
        case 404:
          window.location = "<?php echo $failover ?>";
          break;
        
        case 902:
          jsStatusMsg(req.statusText);
          jsMessageBox(req.responseText);
          break;

        case 903:
          {
            var nitem = document.getElementById("messageBox");
            if (nitem)
            {
              nitem.innerHTML = "<div class='messageBoxInner'>"+ req.responseText +
                "<div class='messageBoxControls'>"+
                "</div></div>";
              nitem.style.display = "block";
            }
          }
          break;
        
        case 200:
          if (success)
            success(req.responseText);
          jsStatusMsg(req.statusText);
          break;
        
        default:
          if (failure)
            failure(req.status, req.statusText, req.responseText);
          else
            jsStatusMsg("["+req.status+" - "+req.statusText+"] "+ req.responseText);
          break;
      }
    }
  }
  req.send(params);
}

<?php
}

//
// CLI related helper functions
//

// Check if we are running from commandline or not
function stCheckCLIExec($fail = TRUE)
{
  if (php_sapi_name() != "cli" || !empty($_SERVER["REMOTE_ADDR"]))
  {
    if ($fail)
    {
      header("Status: 404 Not Found");
      die();
    }
    else
      return TRUE;
  }
  else
    return FALSE;
}


function stCArg($index, $clip = FALSE)
{
  global $argc, $argv;
  if ($index < $argc)
  {
    $str = $argv[$index];
    return ($clip !== FALSE) ? substr($str, 0, $clip) : $str;
  }
  else
    return FALSE;
}


function stCArgLC($index, $clip = FALSE)
{
  global $argc, $argv;
  if ($index < $argc)
  {
    $str = strtolower($argv[$index]);
    return ($clip !== FALSE) ? substr($str, 0, $clip) : $str;
  }
  else
    return FALSE;
}


function stYesNoPrompt($msg, $default = FALSE)
{
  echo $msg." [".($default ? "Y/n" : "y/N")."]? ";
  $sprompt = strtolower(trim(fgets(STDIN)));

  if ($default)
    return ($sprompt == "n");
  else
    return ($sprompt == "y");
}


function stInputPrompt($msg, $default = FALSE, $validate = null)
{
  $valid = FALSE;
  while (!$valid)
  {
    echo $msg."\n".($default !== FALSE ? "[".$default."]" : "")."> ";
    $sprompt = trim(fgets(STDIN));

    if ($sprompt == "")
      $sprompt = ($default !== FALSE ? $default : "");

    $valid =  !is_callable($validate) || call_user_func($validate, $sprompt);
  }
  return $sprompt;
}


function stValidateNotEmpty($val)
{
  if ($val == "")
  {
    echo "The value can't be empty.\n";
    return FALSE;
  }
  else
    return TRUE;
}


function stGetDBMeta($dbh, $name)
{
  if (($item = stDBFetchSQL($dbh, "SELECT * FROM dbmeta WHERE key=".$dbh->quote($name))) === FALSE)
    return FALSE;
  
  return stGetSQLSettingData($item);
}


function stSetDBMeta($dbh, $name, $value)
{
  if (($item = stDBFetchSQL($dbh, "SELECT * FROM dbmeta WHERE key=".$dbh->quote($name))) === FALSE)
    return FALSE;

  $sql = "UPDATE dbmeta SET ".stGetSettingSQL($item, $value)." WHERE key=".$dbh->quote($name);
  return stDBExecSQL($dbh, $sql);
}


//
// Global locale initialization
//
if (!isset($localeInited) || !$localeInited)
{
  $localeInited = TRUE;
  $pageCharset = "UTF-8";

  mb_internal_encoding($pageCharset);

  $tmp = "en_US.".strtolower(str_replace("-", "", $pageCharset));
  setlocale(LC_ALL, $tmp);
}
?>