view msitegen.inc.php @ 1109:ac3bd4e94555

Merge.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 16 May 2019 21:59:44 +0300
parents c7093ad17858 acb65ff40ce1
children a5f52e54c9da
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 htmlspecialchars($str, ENT_COMPAT, "UTF-8");
}


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


function ihentities($str)
{
  return htmlspecialchars($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;
  }
  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, $values = NULL)
{
  $sql = [];
  foreach ($pairs as $name => $attr)
  {
    $sql[] = $name."=".stDBGetSQLParam($dbh,
      $attr, $values !== NULL ? $values[$name] : $name);
  }
  return
    "UPDATE ".$table." SET ".implode(",", $sql).
    ($cond != "" ? " ".$cond : "");
}


function stDBPrepareSQL_V($dbh, $fmt, $argv)
{
  $len = strlen($fmt);
  $sql = "";
  $argn = 0;
  $argc = count($argv);

  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 stDBPrepareSQL($dbh)
{
  $argv = func_get_args();
  return stDBPrepareSQL_V($dbh, $argv[1], array_splice($argv, 2));
}


function stPrepareSQL()
{
  global $db;
  $argv = func_get_args();
  return stDBPrepareSQL_V($db, $argv[0], array_splice($argv, 1));
}


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 (strlen($str) > $len) ? substr($str, 0, $len - 3)."..." : $str;
}


function stStrChopPad($str, $len)
{
  $tmp = stStrChop($str, $len);
  for ($i = 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".
  "  <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";

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