Files
selima-perl/lib/php/monica/checker.inc.php
2026-03-10 21:31:43 +08:00

3348 lines
115 KiB
PHP

<?php
// File name: checker.inc.php
// Description: PHP classes to check a form
// Date: 2004-11-01
// Author: imacat <imacat@pristine.com.tw>
// Copyright: Copyright (C) 2004-2013 Pristine Communications
// Set the include path
if (!defined("INCPATH_SET")) {
require_once dirname(__FILE__) . "/incpath.inc.php";
}
// Referenced subroutines
require_once "monica/actlog.inc.php";
require_once "monica/addget.inc.php";
require_once "monica/callform.inc.php";
require_once "monica/cgiemu.inc.php";
require_once "monica/chkfunc.inc.php";
require_once "monica/chkpriv.inc.php";
require_once "monica/chkwrite.inc.php";
require_once "monica/cracklib.inc.php";
require_once "monica/echoform.inc.php";
require_once "monica/email.inc.php";
require_once "monica/getlang.inc.php";
require_once "monica/gettext.inc.php";
require_once "monica/guest.inc.php";
require_once "monica/http.inc.php";
require_once "monica/lninfo.inc.php";
require_once "monica/login.inc.php";
require_once "monica/mimetype.inc.php";
require_once "monica/passwd.inc.php";
require_once "monica/pic.inc.php";
require_once "monica/request.inc.php";
require_once "monica/requri.inc.php";
require_once "monica/rfc2396.inc.php";
require_once "monica/sql.inc.php";
require_once "monica/trimtext.inc.php";
require_once "monica/upload.inc.php";
require_once "monica/userhome.inc.php";
require_once "monica/username.inc.php";
require_once "monica/usrconst.inc.php";
require_once "monica/xfileio.inc.php";
require_once "monica/zh2py.inc.php";
// BaseChecker: Base form checker class
class BaseChecker
{
protected $_form;
protected $_iscur = null;
protected $_isreq = null;
protected $_sn = null;
protected $_table;
public $maxlens;
public $minlens;
// __construct: Initialize the checker
function __construct(&$form, $table)
{
$this->_form =& $form;
$this->_table = $table;
if (!is_null($table)) {
$this->maxlens = sql_col_lens($table);
}
$this->minlens = array();
$this->minlens["id"] = 3;
$this->_iscur = array_key_exists("CURRENT", $GLOBALS);
if ($this->_iscur && array_key_exists("sn", $form)) {
$this->_sn = $form["sn"];
}
$this->_isreq = is_userreq();
}
// check: Run a list of checks
function check($cols)
{
// Check the list itself first
foreach ($cols as $col) {
if (!method_exists($this, "_check_$col")) {
trigger_error("Called an undefined check \"$col\"", E_USER_ERROR);
}
}
// Run each checker
foreach ($cols as $col) {
$error = call_user_func(array(&$this, "_check_$col"));
if (!is_null($error)) {
return $error;
}
}
return null;
}
// redir: Check and redirect to another form
function redir($cols)
{
// Check the list itself first
foreach ($cols as $col) {
if (!method_exists($this, "_redir_$col")) {
trigger_error("Called an undefined redirection \"$col\"", E_USER_ERROR);
}
}
// Check each redirection
foreach ($cols as $col) {
call_user_func(array(&$this, "_redir_$col"));
}
return;
}
// save_uploaded: Check and save the uploaded file
function save_uploaded($cols)
{
// Check the list itself first
foreach ($cols as $col) {
if (!method_exists($this, "_save_uploaded_$col")) {
trigger_error("Called an undefined uploaded file handler \"$col\"", E_USER_ERROR);
}
}
// Check each uploaded file
$errors = array();
foreach ($cols as $col) {
$error = call_user_func(array(&$this, "_save_uploaded_$col"));
if (!is_null($error)) {
// A list of errors
if (array_key_exists(0, $error)) {
$errors = array_merge($errors, $error);
} else {
$errors[] = $error;
}
}
}
switch (count($errors)) {
// OK
case 0:
return null;
case 1:
return $errors[0];
default:
return array("errors"=>$errors);
}
}
/////////////////////////
// Private column checkers. Do not call them directly.
// Add or override the column checkers when needed.
// Method names must be in the following format:
// function _check_{column}() { ... }
// Columns started with underlines are reserved for internal use, as usual.
/////////////////////////
// _check_usr: The default user checker
function _check_usr()
{
// Check if it exists
$error = $this->_missing("usr");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["usr"] = trim($this->_form["usr"]);
// Check if it is filled
if ($this->_form["usr"] == "") {
return array("msg"=>NC_("Please select a user."));
}
// Check if this user exists
if (!check_sn_in($this->_form["usr"], "users")) {
return array("msg"=>NC_("This user does not exist anymore. Please select another one."));
}
// OK
return null;
}
// _check_grp: The default group checker
function _check_grp()
{
// Check if it exists
$error = $this->_missing("grp");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["grp"] = trim($this->_form["grp"]);
// Check if it is filled
if ($this->_form["grp"] == "") {
return array("msg"=>NC_("Please select a group."));
}
// Check if the group exists
if (!check_sn_in($this->_form["grp"], "groups")) {
return array("msg"=>NC_("This group does not exist anymore. Please select another one."));
}
// OK
return null;
}
// _check_script: The default script checker
function _check_script()
{
// Check if it exists
$error = $this->_missing("script");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["script"] = trim($this->_form["script"]);
// Check if it is filled
if ($this->_form["script"] == "") {
return array("msg"=>NC_("Please fill in the script."));
}
// Check the length
if (sql_strlen($this->_form["script"]) > $this->maxlens["script"]) {
return array("msg"=>NC_("This script is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["script"]));
}
// Check if this script exists
if (!check_script($this->_form["script"])) {
return array("msg"=>NC_("This script is not a valid script. Please specify another one."));
}
// OK
return null;
}
// _check_date: The default date checker
function _check_date()
{
// Check if it exists
$error = $this->_missing("date");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["date"] = trim($this->_form["date"]);
// Check if it is filled
if ($this->_form["date"] == "") {
return array("msg"=>NC_("Please fill in the date."));
}
// Check the length
if (sql_strlen($this->_form["date"]) != $this->maxlens["date"]) {
return array("msg"=>NC_("Please fill in a valid date in YYYY-MM-DD format."));
}
// Check the date format
if (!preg_match("/^(\d{4})-(\d{2})-(\d{2})$/", $this->_form["date"], $m)) {
return array("msg"=>NC_("Please fill in a valid date in YYYY-MM-DD format."));
}
if (!checkdate($m[2], $m[3], $m[1])) {
return array("msg"=>NC_("Please fill in a valid date in YYYY-MM-DD format."));
}
// OK
return null;
}
// _check_id: The default ID. checker
function _check_id()
{
// Check if it exists
$error = $this->_missing("id");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["id"] = trim($this->_form["id"]);
// Check if it is filled
if ($this->_form["id"] == "") {
return array("msg"=>NC_("Please fill in the ID."));
}
// Check the length
if (sql_strlen($this->_form["id"]) > $this->maxlens["id"]) {
return array("msg"=>NC_("This ID. is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["id"]));
}
if (sql_strlen($this->_form["id"]) < $this->minlens["id"]) {
return array("msg"=>NC_("This ID. is too short. (Min. length %d)"),
"margs"=>array($this->minlens["id"]));
}
// Check if the characters used are valid
if (!preg_match("/^[a-z][a-z0-9_]*$/", $this->_form["id"])) {
return array("msg"=>NC_("Only lower-case English letters, numbers and underscores are allowed for the ID."));
}
// OK
return null;
}
// _check_ord: The default order checker
function _check_ord()
{
// Check if it exists
$error = $this->_missing("ord");
if (!is_null($error)) {
return $error;
}
$min = 0;
$max = pow(10, $this->maxlens["ord"]) - 1;
// Text string
if (is_string($this->_form["ord"])) {
// Regularize it
$this->_form["ord"] = trim($this->_form["ord"]);
// Check if it is filled
if ($this->_form["ord"] == "") {
return array("msg"=>NC_("Please fill in the order."));
}
// Check the length
if (sql_strlen($this->_form["ord"]) > $this->maxlens["ord"]) {
return array("msg"=>NC_("This order is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["ord"]));
}
// If there is any non-digit character
if (preg_match("/\D/", $this->_form["ord"])) {
return array("msg"=>NC_("Please fill in a positive integer order."));
}
// Check if it is in the valid range
if ($this->_form["ord"] < $min) {
return array("msg"=>NC_("The order is too small. Please fill in a larger order between %d and %d."),
"margs"=>array($min, $max));
}
// It is not possible to be too large now.
// Convert its type to integer
settype($this->_form["ord"], "integer");
// Integer
} elseif (is_int($this->_form["ord"])) {
// Check if it is in the valid range
if ($this->_form["ord"] < $min) {
return array("msg"=>NC_("The order is too small. Please fill in a larger order between %d and %d."),
"margs"=>array($min, $max));
}
if ($this->_form["ord"] > $max) {
return array("msg"=>NC_("The order is too large. Please fill in a smaller order between %d and %d."),
"margs"=>array($min, $max));
}
// Other types are non-sense
} else {
trigger_error("Unknown type for column \"ord\"", E_USER_ERROR);
}
// OK
return null;
}
// _check_path: The default page order checker
function _check_path()
{
// Get the available languages list
global $ALL_LINGUAS;
// Check if it exists
$error = $this->_missing("path");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["path"] = trim($this->_form["path"]);
// Remove the trailing excess "index.html"
$this->_form["path"] = preg_replace("/\/index\.html?$/i", "/", $this->_form["path"]);
// Check if it is filled
if ($this->_form["path"] == "") {
return array("msg"=>NC_("Please fill in the page path."));
}
// Check the length
if (sql_strlen($this->_form["path"]) > $this->maxlens["path"]) {
return array("msg"=>NC_("This page path is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["path"]));
}
// Check if this item is duplicated
$conds = array();
$conds[] = "path='" . sql_esctext($this->_form["path"]) . "'";
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This page already exists. You cannot create a duplicated one."));
}
// Check if the path is absolute
if (substr($this->_form["path"], 0, 1) != "/") {
return array("msg"=>NC_("Please fill in an absolute page path."));
}
// Check if the path is legal
if (!preg_match("/^\\/" . RFC2396_PATH_SEGMENTS . "$/", $this->_form["path"])) {
return array("msg"=>NC_("Please fill in a valid page path."));
}
// Check if it is the cover home page
if ($this->_form["path"] == "/") {
return array("msg"=>NC_("You cannot overwrite the cover home page."));
}
// Check if it is *.html
if (!preg_match("/(?:\/|\.html)$/", $this->_form["path"])) {
return array("msg"=>NC_("You can only fill in an HTML page path (*.html)."));
}
// Check if we are permitted to write files there
if (count($ALL_LINGUAS) > 1) {
$pathpat = DOC_ROOT . "/%s" . $this->_form["path"];
if (substr($pathpat, -1, 1) == "/") {
$pathpat .= "index.html";
}
for ($l = 0; $l < count($ALL_LINGUAS); $l++) {
$langfile = ln($ALL_LINGUAS[$l], LN_FILENAME);
$error = check_writable(sprintf($pathpat, $langfile));
if (!is_null($error)) {
return $error;
}
}
} else {
$path = DOC_ROOT . $this->_form["path"];
if (substr($path, -1, 1) == "/") {
$path .= "index.html";
}
$error = check_writable(DOC_ROOT . $path);
if (!is_null($error)) {
return $error;
}
}
// OK
return null;
}
// _check_attdsc: The default attachment description checker
function _check_attdsc()
{
// Skip if there is no file to check
$error = $this->_missing("att");
if (!is_null($error)) {
return null;
}
// Check if it exists
$error = $this->_missing("attdsc");
if (!is_null($error)) {
// No attdsc will be sent when uploading an attachment from nothing
return array("msg"=>NC_("Please fill in the attachment description."));
}
// Regularize it
$this->_form["attdsc"] = trim($this->_form["attdsc"]);
// Check if it is filled
if ($this->_form["attdsc"] == "") {
return array("msg"=>NC_("Please fill in the attachment description."));
}
// Check the length
if (sql_strlen($this->_form["attdsc"]) > $this->maxlens["attdsc"]) {
return array("msg"=>NC_("This attachment description is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["attdsc"]));
}
// OK
return null;
}
// _check_pdf: The default PDF. file checker
function _check_pdf()
{
// Skip if there is no file to check
$error = $this->_missing("pdf");
if (!is_null($error)) {
return null;
}
// Check if this file exists
if (!savefile_exists($this->_form["pdf"])) {
return array("msg"=>NC_("This PDF. file does not exist anymore. Please upload another one."));
}
// Obtain the file deposit
$FILES =& file_deposit();
$file =& $FILES[$this->_form["pdf"]];
// Check if this size is too large
if ($file["size"] > $this->maxlens["pdf"]) {
return array("msg"=>NC_("This PDF. file is too large. (Max. size %s)"),
"margs"=>array(report_size($this->maxlens["pdf"])));
}
// Check if the file type is valid
if ($file["type"] != "application/pdf") {
return array("msg"=>NC_("Please upload only PDF. file."));
}
// OK
return null;
}
// _check_title: The default title checker
function _check_title()
{
// Check if it exists
$error = $this->_missing("title");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["title"] = trim($this->_form["title"]);
// Check if it is filled
if ($this->_form["title"] == "") {
return array("msg"=>NC_("Please fill in the title."));
}
// Check the length
if (sql_strlen($this->_form["title"]) > $this->maxlens["title"]) {
return array("msg"=>NC_("This title is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["title"]));
}
// OK
return null;
}
// _check_subject: Check the subject
function _check_subject()
{
// Check if it exists
$error = $this->_missing("subject");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["subject"] = trim($this->_form["subject"]);
// Check if it is filled
if ($this->_form["subject"] == "") {
return array("msg"=>NC_("Please fill in the subject."));
}
// Check the length
if (sql_strlen($this->_form["subject"]) > $this->maxlens["subject"]) {
return array("msg"=>NC_("This subject is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["subject"]));
}
// OK
return null;
}
// _check_body: The default content body checker
function _check_body()
{
// Check if it exists
$error = $this->_missing("body");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["body"] = trimtext($this->_form["body"]);
// Check if it is filled
if ($this->_form["body"] == C_("Fill in the content here.")) {
$this->_form["body"] = "";
}
if ($this->_form["body"] == "") {
return array("msg"=>NC_("Please fill in the content."));
}
// Check the length
if (sql_strlen($this->_form["body"]) > $this->maxlens["body"]) {
return array("msg"=>NC_("This content is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["body"]));
}
// OK
return null;
}
// _check_kw: The default keyword list checker
function _check_kw()
{
// Check if it exists
$error = $this->_missing("kw");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["kw"] = trim($this->_form["kw"]);
// Check if it is filled
if ($this->_form["kw"] == "") {
return array("msg"=>NC_("Please fill in the keywords."));
}
// Check the length
if (sql_strlen($this->_form["kw"]) > $this->maxlens["kw"]) {
return array("msg"=>NC_("This keyword list is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["kw"]));
}
// OK
return null;
}
// _check_pinyin: The default pinyin checker
function _check_pinyin()
{
// Skip if there is no Chinese
if ($this->_missing("chinese")) {
return null;
}
// Check if it exists
$error = $this->_missing("pinyin");
if (!is_null($error)) {
return array("msg"=>NC_("Please select a proper pinyin."));
}
// Regularize it
$this->_form["pinyin"] = trim($this->_form["pinyin"]);
// Check the length
if (sql_strlen($this->_form["pinyin"]) > $this->maxlens["pinyin"]) {
return array("msg"=>NC_("This pinyin is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["pinyin"]));
}
// Check if the pinyin is in our safe list
if (!in_array($this->_form["pinyin"], zh2pys($this->_form["chinese"]))) {
return array("msg"=>NC_("This pinyin does not match the Chinese. Please select a proper pinyin from the list."));
}
// OK
return null;
}
// _check_pic: The default picture checker
function _check_pic()
{
// Check if it exists
$error = $this->_missing("pic");
if (!is_null($error)) {
// Check against the default language
// Only check if multilingual, not in the default language and column is multilingual
if ( ($this->_iscur || $this->_isreq)
&& count($GLOBALS["ALL_LINGUAS"]) > 1
&& getlang() != DEFAULT_LANG
&& in_array("pic", sql_cols_ml($this->_table))) {
$lndbdef = ln(DEFAULT_LANG, LN_DATABASE);
if ($this->_isreq) {
$defpic = $GLOBALS["REQUEST"]["args"]["pic_$lndbdef"];
} else {
$defpic = $GLOBALS["CURRENT"]["pic_$lndbdef"];
}
// Check if there is a matching column to the default language
if (!is_null($defpic)) {
return array("msg"=>N_("Please upload the picture."));
}
}
return null;
}
// Check if this picture exists
if (!pic_exists($this->_form["pic"])) {
return array("msg"=>NC_("This picture does not exist anymore. Please upload another one."));
}
// Obtain the picture deposit
$PICS =& pic_deposit();
// Check the length
if (strlen($PICS[$this->_form["pic"]]["content"]) > $this->maxlens["pic"]) {
return array("msg"=>NC_("This picture is too large. Please upload another one. (Max. size %d)"),
"margs"=>array($this->maxlens["pic"]));
}
// Check against the default language
// Only check if multilingual, not in the default language and column is multilingual
if ( ($this->_iscur || $this->_isreq)
&& count($GLOBALS["ALL_LINGUAS"]) > 1
&& getlang() != DEFAULT_LANG
&& in_array("pic", sql_cols_ml($this->_table))) {
$lndbdef = ln(DEFAULT_LANG, LN_DATABASE);
if ($this->_isreq) {
$defpic = $GLOBALS["REQUEST"]["args"]["pic_$lndbdef"];
} else {
$defpic = $GLOBALS["CURRENT"]["pic_$lndbdef"];
}
// Check if we start from the default language
if (!pic_exists($defpic)) {
return array("msg"=>NC_("Please upload a new picture from %s."),
"margs"=>array("_DEFAULT_LANG"));
}
}
// OK
return null;
}
// _check_piccap: The default picture caption checker
function _check_piccap()
{
// Skip if there is no picture now
if ($this->_missing("pic")) {
unset($this->_form["piccap"]);
return null;
}
// Check if it exists
$error = $this->_missing("piccap");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["piccap"] = trim($this->_form["piccap"]);
// Check if it is filled
if ($this->_form["piccap"] == "") {
return array("msg"=>NC_("Please fill in the picture caption."));
}
// Check the length
if (sql_strlen($this->_form["piccap"]) > $this->maxlens["piccap"]) {
return array("msg"=>NC_("This picture caption is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["piccap"]));
}
// OK
return null;
}
// _check_picpos: The default picture position checker
function _check_picpos()
{
// Skip if there is no picture now
if ($this->_missing("pic")) {
unset($this->_form["picpos"]);
return null;
}
// Check if it exists
$error = $this->_missing("picpos");
if (!is_null($error)) {
return array("msg"=>NC_("Please select the picture position."));
}
// Regularize it
$this->_form["picpos"] = trim($this->_form["picpos"]);
// Check if the picture position is legal
if (!in_array($this->_form["picpos"], $GLOBALS["PIC_VALID_POS"])) {
return array("msg"=>NC_("This picture position is invalid. Please choose a proper picture position."));
}
// OK
return null;
}
// _check_called_form: Check if this form is a called form
function _check_called_form()
{
// Check if it exists
$error = $this->_missing("caller", "cformid");
if (!is_null($error)) {
return $error;
}
// OK
return null;
}
// _check_cap: The default picture caption checker
function _check_cap()
{
// Skip if there is no picture now
if ($this->_missing("pic")) {
unset($this->_form["cap"]);
return null;
}
// Check if it exists
$error = $this->_missing("cap");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["cap"] = trim($this->_form["cap"]);
// Check if it is filled
if ($this->_form["cap"] == "") {
return array("msg"=>NC_("Please fill in the picture caption."));
}
// Check the length
if (sql_strlen($this->_form["cap"]) > $this->maxlens["cap"]) {
return array("msg"=>NC_("This picture caption is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["cap"]));
}
// OK
return null;
}
// _check_pos: The default picture position checker
function _check_pos()
{
// Skip if there is no picture now
if ($this->_missing("pic")) {
unset($this->_form["pos"]);
return null;
}
// Check if it exists
$error = $this->_missing("pos");
if (!is_null($error)) {
return array("msg"=>NC_("Please select the picture position."));
}
// Regularize it
$this->_form["pos"] = trim($this->_form["pos"]);
// Check if the picture position is legal
if (!in_array($this->_form["pos"], $GLOBALS["PIC_VALID_POS"])) {
return array("msg"=>NC_("This picture position is invalid. Please choose a proper picture position."));
}
// OK
return null;
}
// __check_upload: The default file checker
function __check_upload($col)
{
// Skip if multi-lingual and not in the default language
if ( ($this->_iscur || $this->_isreq)
&& count($GLOBALS["ALL_LINGUAS"]) > 1
&& getlang() != DEFAULT_LANG
&& in_array($col, sql_cols_ml($this->_table))) {
$defcol = $col . "_" . ln(DEFAULT_LANG, LN_DATABASE);
$deffile = $this->_isreq? $GLOBALS["REQUEST"]["args"][$defcol]:
$GLOBALS["CURRENT"][$defcol];
if (!savefile_exists($deffile)) {
return null;
}
}
// Check if it exists
$error = file_has("up$col");
if (!is_null($error)) {
return $error;
}
// Check the file upload status
switch ($_FILES["up$col"]["error"]) {
// Success
case UPLOAD_ERR_OK:
return null;
// Nothing uploaded
case UPLOAD_ERR_NO_FILE:
return null;
// Below are errors
case UPLOAD_ERR_INI_SIZE:
return array("msg"=>NC_("Your uploaded file is too large (Max %s)."),
"margs"=>array(get_cfg_var("upload_max_filesize")));
case UPLOAD_ERR_FORM_SIZE:
return array("msg"=>NC_("Your uploaded file is too large (Max %s)."),
"margs"=>array(UPLOAD_ERR_FORM_SIZE));
case UPLOAD_ERR_PARTIAL:
return array("msg"=>NC_("Upload not completed. Disk may be full or connection may be closed in the half. You may try to upload again, or contact the system administrator for this problem."));
default:
return array("msg"=>NC_("Upload failed with an unknown error (%d)."),
"margs"=>array($_FILES["up$col"]["error"]));
}
}
/////////////////////////
// Private form redirectors. Do not call them directly.
// Add redirector definitions here.
// Method names must be in the following format:
// function _redir_{column}() { ... }
// Columns started with underlines are reserved for internal use, as usual.
/////////////////////////
// _redir_del: Suspend and move to the deletion form
function _redir_del()
{
// Skip if not requested
if ($this->_missing("del")) {
return;
}
$args = array();
$args[] = "form=del";
if (!$this->_missing("sn")) {
$args[] = "sn=" . $this->_form["sn"];
} elseif (!$this->_missing("req")) {
$args[] = "req=" . $this->_form["req"];
}
call_form(FORM_THIS, $args, null);
}
// _redir_cancel: Cancel the form and return to the originator
function _redir_cancel()
{
// Skip if not requested
if ($this->_missing("cancel")) {
return;
}
// A calling form -- return to the caller
if (!$this->_missing("caller", "cformid")) {
$url = $this->_form["caller"];
if (!$this->_missing("hostport")) {
$url = $this->_form["hostport"] . $url;
}
$url = add_get_arg($url, "formid", $this->_form["cformid"]);
if ($_SERVER["REQUEST_METHOD"] == "POST") {
http_303($url);
} else {
http_307($url);
}
}
// Referer2 specified -- return to referer2
if (!$this->_missing("referer2")) {
$url = $this->_form["referer2"];
// Return to the hostport
} elseif (!$this->_missing("hostport")) {
$url = $this->_form["hostport"] . userhome();
} else {
$url = userhome();
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
http_303($url);
} else {
http_307($url);
}
}
// _redir_selgrp: Suspend and move to the group selection form
function _redir_selgrp()
{
// Skip if not requested
if ($this->_missing("selgrp")) {
return;
}
call_form(FORM_GROUPS, null, "import_selgrp");
}
// _redir_delgrp: Remove the group
function _redir_delgrp()
{
// Skip if not requested
if ($this->_missing("delgrp")) {
return;
}
// Remove the item
unset($this->_form["grp"]);
$status = null;
success_redirect($status);
}
// _redir_setpic: Suspend and move to the picture manager
function _redir_setpic()
{
// Skip if not requested
if ($this->_missing("setpic")) {
return;
}
// There is a current picture
if (!$this->_missing("pic")) {
$args = array();
$args[] = "form=cur";
$args[] = "sn=" . urlencode($this->_form["pic"]);
call_form(FORM_PIC, $args, "import_setpic");
// There is no current picture
} else {
$args = array();
$args[] = "form=new";
call_form(FORM_PIC, $args, "import_setpic");
}
}
// _redir_delpic: Remove the picture
function _redir_delpic()
{
// Skip if not requested
if ($this->_missing("delpic")) {
return;
}
// Remove the item
unset($this->_form["pic"]);
unset($this->_form["piccap"]);
unset($this->_form["picpos"]);
$status = null;
success_redirect($status);
}
// _redir_delfile: Remove the file
function _redir_delfile()
{
// Skip if not requested
if ($this->_missing("delfile")) {
return;
}
// Remove the file
unset($this->_form["file"]);
$status = null;
success_redirect($status);
}
// _redir_delatt: Remove the attachment file
function _redir_delatt()
{
// Skip if not requested
if ($this->_missing("delatt")) {
return;
}
// Remove the file
unset($this->_form["att"]);
$status = null;
success_redirect($status);
}
// _redir_delpdf: Remove the PDF. file
function _redir_delpdf()
{
// Skip if not requested
if ($this->_missing("delpdf")) {
return;
}
// Remove the file
unset($this->_form["pdf"]);
$status = null;
success_redirect($status);
}
// _redir_selpage: Suspend and move to the page selection form
function _redir_selpage()
{
// Skip if not requested
if ($this->_missing("selpage")) {
return;
}
call_form(FORM_PAGES, null, "import_selpage");
}
// _redir_selnews: Suspend and move to the news article selection form
function _redir_selnews()
{
// Skip if not requested
if ($this->_missing("selnews")) {
return;
}
call_form(FORM_NEWS, null, "import_selnews");
}
// _redir_delnews: Remove the news article
function _redir_delnews()
{
// Skip if not requested
if ($this->_missing("delnews")) {
return;
}
// Remove the item
unset($this->_form["news"]);
$status = null;
success_redirect($status);
}
// _redir_sellink: Suspend and move to the related link selection form
function _redir_sellink()
{
// Skip if not requested
if ($this->_missing("sellink")) {
return;
}
call_form(FORM_LINKS, null, "import_sellink");
}
// _redir_dellink: Remove the link
function _redir_dellink()
{
// Skip if not requested
if ($this->_missing("dellink")) {
return;
}
// Remove the item
unset($this->_form["link"]);
$status = null;
success_redirect($status);
}
// _redir_selparent: Suspend and move to the parent selection form
function _redir_selparent()
{
// Skip if not requested
if ($this->_missing("selparent")) {
return;
}
call_form(FORM_THIS, null, "import_selparent");
}
// _redir_delparent: Remove the parent
function _redir_delparent()
{
// Skip if not requested
if ($this->_missing("delparent")) {
return;
}
// Remove the item
unset($this->_form["parent"]);
$status = null;
success_redirect($status);
}
/////////////////////////
// Private uploaded file handlers. Do not call them directly.
// Add uploaded file handlers definitions here.
// Method names must be in the following format:
// function _save_uploaded_{column}() { ... }
// Columns started with underlines are reserved for internal use, as usual.
/////////////////////////
// _save_uploaded_pdf: Check and save the uploaded PDF. file
function _save_uploaded_pdf()
{
// Skip if multi-lingual and not in the default language
if ( ($this->_iscur || $this->_isreq)
&& count($GLOBALS["ALL_LINGUAS"]) > 1
&& getlang() != DEFAULT_LANG
&& in_array("pdf", sql_cols_ml($this->_table))) {
$defcol = "pdf_" . ln(DEFAULT_LANG, LN_DATABASE);
$deffile = $this->_isreq? $GLOBALS["REQUEST"]["args"][$defcol]:
$GLOBALS["CURRENT"][$defcol];
if (!savefile_exists($deffile)) {
return null;
}
}
// Check with the basic upload checker
$error = $this->__check_upload("pdf");
if (!is_null($error)) {
return $error;
}
// Skip if no new file was submitted
if ($_FILES["uppdf"]["error"] == UPLOAD_ERR_NO_FILE) {
return null;
}
$type = check_mime_type($_FILES["uppdf"]["tmp_name"],
$_FILES["uppdf"]["name"], $_FILES["uppdf"]["type"]);
// Save the file
$file = array();
$file["content"] = xfread($_FILES["uppdf"]["tmp_name"]);
$file["name"] = $_FILES["uppdf"]["name"];
$file["type"] = $type;
$file["size"] = strlen($file["content"]);
$fileid = suspend_file($file);
$this->_form["pdf"] = $fileid;
// Do not confirm now
if (!$this->_missing("confirm")) {
unset($this->_form["confirm"]);
}
// OK
return null;
}
// _save_uploaded_att: Check and save the uploaded attachment file
function _save_uploaded_att()
{
// Skip if multi-lingual and not in the default language
if ( ($this->_iscur || $this->_isreq)
&& count($GLOBALS["ALL_LINGUAS"]) > 1
&& getlang() != DEFAULT_LANG
&& in_array("att", sql_cols_ml($this->_table))) {
$defcol = "att_" . ln(DEFAULT_LANG, LN_DATABASE);
$deffile = $this->_isreq? $GLOBALS["REQUEST"]["args"][$defcol]:
$GLOBALS["CURRENT"][$defcol];
if (!savefile_exists($deffile)) {
return null;
}
}
// Check with the basic upload checker
$error = $this->__check_upload("att");
if (!is_null($error)) {
return $error;
}
// Skip if no new file was submitted
if ($_FILES["upatt"]["error"] == UPLOAD_ERR_NO_FILE) {
return null;
}
$type = check_mime_type($_FILES["upatt"]["tmp_name"],
$_FILES["upatt"]["name"], $_FILES["upatt"]["type"]);
// Save the file
$file = array();
$file["content"] = xfread($_FILES["upatt"]["tmp_name"]);
$file["name"] = $_FILES["upatt"]["name"];
$file["type"] = $type;
$file["size"] = strlen($file["content"]);
$fileid = suspend_file($file);
$this->_form["att"] = $fileid;
// Do not confirm now
if (!$this->_missing("confirm")) {
unset($this->_form["confirm"]);
}
// OK
return null;
}
// _save_uploaded_file: Check and save the uploaded file
function _save_uploaded_file()
{
// Skip if multi-lingual and not in the default language
if ( ($this->_iscur || $this->_isreq)
&& count($GLOBALS["ALL_LINGUAS"]) > 1
&& getlang() != DEFAULT_LANG
&& in_array("file", sql_cols_ml($this->_table))) {
$defcol = "file_" . ln(DEFAULT_LANG, LN_DATABASE);
$deffile = $this->_isreq? $GLOBALS["REQUEST"]["args"][$defcol]:
$GLOBALS["CURRENT"][$defcol];
if (!savefile_exists($deffile)) {
return null;
}
}
// Check with the basic upload checker
$error = $this->__check_upload("file");
if (!is_null($error)) {
return $error;
}
// Skip if no new file was submitted
if ($_FILES["upfile"]["error"] == UPLOAD_ERR_NO_FILE) {
return null;
}
$type = check_mime_type($_FILES["upfile"]["tmp_name"],
$_FILES["upfile"]["name"], $_FILES["upfile"]["type"]);
// Save the file
$file = array();
$file["content"] = xfread($_FILES["upfile"]["tmp_name"]);
$file["name"] = $_FILES["upfile"]["name"];
$file["type"] = $type;
$file["size"] = strlen($file["content"]);
$fileid = suspend_file($file);
$this->_form["file"] = $fileid;
// Do not confirm now
if (!$this->_missing("confirm")) {
unset($this->_form["confirm"]);
}
// OK
return null;
}
/////////////////////////
// Private utility methods. Do not override them.
/////////////////////////
// _missing: Check if a column is submitted
function _missing()
{
$cols = func_get_args();
foreach ($cols as $col) {
if (!array_key_exists($col, $this->_form)) {
return array("msg"=>NC_("The following field was not received: \"%s\"."),
"margs"=>array($col),
"isform"=>false);
}
}
// OK
return null;
}
}
/////////////////////////
// Account Checkers: Checkers for the account management system
/////////////////////////
// UserChecker: User form checker class
class UserChecker extends BaseChecker
{
protected $_is_guest = null;
// __construct: Initialize the checker
function __construct(&$form, $table = "users")
{
parent::__construct($form, $table);
$this->maxlens["passwd"] = 100;
$this->minlens["passwd"] = 6;
}
// check: Run a list of checks
function check($cols)
{
// Check the guest flag first
$this->_is_guest();
// Run the parent method
$error = parent::check($cols);
if (!is_null($error)) {
return $error;
}
return null;
}
// _is_guest: If the user being edited is a guest
function _is_guest()
{
// Checked before
if (!is_null($this->_is_guest)) {
return $this->_is_guest;
}
for ($i = 0; !$this->_missing("supgroup$i" . "sn"); $i++) {
// Skip unselected groups
if ($this->_missing("supgroup$i")) {
continue;
}
// Check if this is the guest group
if (groupid($this->_form["supgroup$i" . "sn"]) == GUEST_GROUP) {
$this->_is_guest = true;
return true;
}
}
// No guest group was found
$this->_is_guest = false;
return false;
}
// _check_id: Check the user ID.
function _check_id()
{
// Skip for a non-super-user editing a super-user
if ($this->_iscur && !is_su() && is_su($this->_sn)) {
return null;
}
// Check if it exists
$error = $this->_missing("id");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["id"] = trim($this->_form["id"]);
// Check if it is filled
if ($this->_form["id"] == "") {
return array("msg"=>NC_("Please fill in the user ID."));
}
// Check the length
if (sql_strlen($this->_form["id"]) > $this->maxlens["id"]) {
return array("msg"=>NC_("This user ID. is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["id"]));
}
if (sql_strlen($this->_form["id"]) < $this->minlens["id"]) {
return array("msg"=>NC_("This user ID. is too short. (Min. length %d)"),
"margs"=>array($this->minlens["id"]));
}
// Check if the characters used are valid
if (!preg_match("/^[a-z][a-z0-9@.\-_]*$/", $this->_form["id"])) {
return array("msg"=>NC_("Only lower-case English letters, numbers, at-signs, dots, dashes and underscores are allowed for the user ID."));
}
// Check if this item is duplicated
$conds = array();
$conds[] = "id='" . sql_esctext($this->_form["id"]) . "'";
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This user already has an account. You cannot create a duplicated one."));
}
// OK
return null;
}
// _check_passwd: Check the user password
function _check_passwd()
{
// Skip for a non-super-user editing a super-user
if ($this->_iscur && !is_su() && is_su($this->_sn)) {
return null;
}
// Set the passwords with the password registry
$dummy = str_repeat("*", 16);
sync_saved_passwd($this->_form, $dummy);
// Skip password checking for guests
if ($this->_is_guest()) {
return null;
}
// Check if it exists
$error = $this->_missing("passwd", "passwd2");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["passwd"] = trim($this->_form["passwd"]);
$this->_form["passwd2"] = trim($this->_form["passwd2"]);
// Check if it is filled
if (!$this->_iscur && $this->_form["passwd"] == "") {
return array("msg"=>NC_("Please fill in the password."));
}
if ($this->_form["passwd"] != "" && $this->_form["passwd2"] == "") {
return array("msg"=>NC_("Please confirm the password."));
}
// Check the length
if (sql_strlen($this->_form["passwd"]) > $this->maxlens["passwd"]) {
return array("msg"=>NC_("This password is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["passwd"]));
}
if ( $this->_form["passwd"] != ""
&& sql_strlen($this->_form["passwd"]) < $this->minlens["passwd"]) {
return array("msg"=>NC_("This password is too short. (Min. length %d)"),
"margs"=>array($this->minlens["passwd"]));
}
// Check if two passwords are consistent
if ($this->_form["passwd"] != $this->_form["passwd2"]) {
return array("msg"=>NC_("The 2 passwords are different. Please fill in the password again."));
}
if ($this->_form["passwd"] != "") {
// Check the password strength with cracklib
if (!crack_check($this->_form["passwd"])) {
// See the message from cracklib/fscist.c
switch (crack_getlastmessage()) {
// FascistGecos()
/* case "you are not registered in the password file":
return array("msg"=>NC_("You are not registered.")); */
case "it is based on your username":
return array("msg"=>NC_("This password is based on the user ID."));
/* case "it is based upon your password entry":
return array("msg"=>NC_("This password is based upon the personal information."));
case "it is derived from your password entry":
case "it's derived from your password entry":
return array("msg"=>NC_("This password is derived from the personal information."));
case "it is derivable from your password entry":
case "it's derivable from your password entry":
return array("msg"=>NC_("This password is derivable from the personal information.")); */
// FascistLook()
/* case "it's WAY too short":
case "it is too short":
return array("msg"=>NC_("This password is too short. (Min. length %d)"),
"margs"=>array($this->minlens["passwd"])); */
case "it does not contain enough DIFFERENT characters":
return array("msg"=>NC_("This password does not contain enough different characters."));
/* case "it is all whitespace":
return array("msg"=>NC_("This password is all whitespace.")); */
case "it is too simplistic/systematic":
return array("msg"=>NC_("This password is too simplistic/systematic."));
/* case "it looks like a National Insurance number":
return array("msg"=>NC_("This password looks like a National Insurance number.")); */
case "it is based on a dictionary word":
return array("msg"=>NC_("This password is based on a dictionary word."));
case "it is based on a (reversed) dictionary word":
return array("msg"=>NC_("This password is based on a (reversed) dictionary word."));
default:
return array("msg"=>NC_("This password is too simple."));
}
}
// Check if the password is based on the user ID.
if ( !$this->_missing("id")
&& strpos(strtolower($this->_form["passwd"]), strtolower($this->_form["id"])) !== false) {
return array("msg"=>NC_("You cannot use a password that is based on the user ID."));
}
}
// OK
return null;
}
// _check_name: Check the user name
function _check_name()
{
// Check if it exists
$error = $this->_missing("name");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["name"] = trim($this->_form["name"]);
// Check if it is filled
if ($this->_form["name"] == "") {
return array("msg"=>NC_("Please fill in the name."));
}
// Check the length
if (sql_strlen($this->_form["name"]) > $this->maxlens["name"]) {
return array("msg"=>NC_("This name is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["name"]));
}
// OK
return null;
}
// _check_email: Check the user e-mail
function _check_email($col = "email")
{
// Check if it exists
$error = $this->_missing($col);
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form[$col] = trim($this->_form[$col]);
// Check if it is filled
if ($this->_form[$col] == "") {
return array("msg"=>NC_("Please fill in the e-mail."));
}
// Check the length
if (sql_strlen($this->_form[$col]) > $this->maxlens[$col]) {
return array("msg"=>NC_("This e-mail is too long. (Max. length %d)"),
"margs"=>array($this->maxlens[$col]));
}
if (sql_strlen($this->_form[$col]) < $this->minlens[$col]) {
return array("msg"=>NC_("This e-mail is too short. (Min. length %d)"),
"margs"=>array($this->minlens[$col]));
}
// Check the e-mail validity
switch (is_email($this->_form[$col])) {
case ISEMAIL_OK:
break;
case ISEMAIL_MALFORMED:
default:
return array("msg"=>NC_("Please fill in a valid e-mail address."));
case ISEMAIL_DOMAIN_NOT_FOUND:
return array("msg"=>NC_("The domain of this e-mail does not exists. Check if there is any typo in it."));
}
// OK
return null;
}
// _check_supgroup: Check the belonging groups
function _check_supgroup()
{
// Skip for a non-super-user editing herself
if ($this->_iscur && !is_su() && $this->_sn == get_login_sn()) {
return null;
}
for ($i = 0, $items = array(); !$this->_missing("supgroup$i" . "sn"); $i++) {
// Skip unselected ones
if ($this->_missing("supgroup$i")) {
continue;
}
// Regularize it
$this->_form["supgroup$i" . "sn"] = trim($this->_form["supgroup$i" . "sn"]);
// Check if this selection is duplicated
if (in_array($this->_form["supgroup$i" . "sn"], $items)) {
return array("msg"=>NC_("This belonging group is duplicated. You cannot set duplicated ones."));
}
$items[] = $this->_form["supgroup$i" . "sn"];
// Check with the subform checker
$form = array();
$form["grp"] =& $this->_form["supgroup$i" . "sn"];
if ($this->_iscur) {
$form["member"] =& $this->_sn;
}
$checker = new UserMembershipChecker($form);
$error = $checker->check(array("grp"));
if (!is_null($error)) {
return $error;
}
// Check if a special group is submitted
switch (groupid($this->_form["supgroup$i" . "sn"])) {
case SU_GROUP:
return array("msg"=>NC_("You cannot submit the super-user group along with other groups."));
case ADMIN_GROUP:
return array("msg"=>NC_("You cannot set the administrators group."));
case ALLUSERS_GROUP:
return array("msg"=>NC_("You cannot set the all-users group."));
}
}
// OK
return null;
}
}
// GroupChecker: Group form checker class
class GroupChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "groups")
{
parent::__construct($form, $table);
}
// _check_id: Check the group ID.
function _check_id()
{
// Skip for a non-super-user editing a super-user group
if ($this->_iscur && !is_su() && $this->_sn == su_group_sn()) {
return null;
}
// Check if it exists
$error = $this->_missing("id");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["id"] = trim($this->_form["id"]);
// Check if it is filled
if ($this->_form["id"] == "") {
return array("msg"=>NC_("Please fill in the group ID."));
}
// Check the length
if (sql_strlen($this->_form["id"]) > $this->maxlens["id"]) {
return array("msg"=>NC_("This group ID. is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["id"]));
}
if (sql_strlen($this->_form["id"]) < $this->minlens["id"]) {
return array("msg"=>NC_("This group ID. is too short. (Min. length %d)"),
"margs"=>array($this->minlens["id"]));
}
// Check if the characters used are valid
if (!preg_match("/^[a-z][a-z0-9_]*$/", $this->_form["id"])) {
return array("msg"=>NC_("Only lower-case English letters, numbers and underscores are allowed for the group ID."));
}
// Check if this item is duplicated
$conds = array();
$conds[] = "id='" . sql_esctext($this->_form["id"]) . "'";
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This group already exists. You cannot create a duplicated one."));
}
// OK
return null;
}
// _check_dsc: Check the group description
function _check_dsc()
{
// Check if it exists
$error = $this->_missing("dsc");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["dsc"] = trim($this->_form["dsc"]);
// Check if it is filled
if ($this->_form["dsc"] == "") {
return array("msg"=>NC_("Please fill in the privilege description."));
}
// Check the length
if (sql_strlen($this->_form["dsc"]) > $this->maxlens["dsc"]) {
return array("msg"=>NC_("This privilege description is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["dsc"]));
}
// OK
return null;
}
// _check_subuser: Check the user members
function _check_subuser()
{
// Skip for a non-super-user editing a super-user group
if ($this->_iscur && !is_su() && $this->_sn == su_group_sn()) {
return null;
}
for ($i = 0, $items = array(); !$this->_missing("subuser$i" . "sn"); $i++) {
// Skip unselected ones
if ($this->_missing("subuser$i")) {
continue;
}
// Regularize it
$this->_form["subuser$i" . "sn"] = trim($this->_form["subuser$i" . "sn"]);
// Check if this selection is duplicated
if (in_array($this->_form["subuser$i" . "sn"], $items)) {
return array("msg"=>NC_("This user member is duplicated. You cannot set duplicated ones."));
}
$items[] = $this->_form["subuser$i" . "sn"];
// Check with the subform checker
$form = array();
$form["member"] =& $this->_form["subuser$i" . "sn"];
if ($this->_iscur) {
$form["grp"] =& $this->_sn;
}
$checker = new UserMembershipChecker($form);
$error = $checker->check(array("member"));
if (!is_null($error)) {
return $error;
}
}
// OK
return null;
}
// _check_subgroup: Check the group members
function _check_subgroup()
{
// Skip for a non-super-user editing a super-user group
if ($this->_iscur && !is_su() && $this->_sn == su_group_sn()) {
return null;
}
for ($i = 0, $items = array(); !$this->_missing("subgroup$i" . "sn"); $i++) {
// Skip unselected ones
if ($this->_missing("subgroup$i")) {
continue;
}
// Regularize it
$this->_form["subgroup$i" . "sn"] = trim($this->_form["subgroup$i" . "sn"]);
// Check if this selection is duplicated
if (in_array($this->_form["subgroup$i" . "sn"], $items)) {
return array("msg"=>NC_("This group member is duplicated. You cannot set duplicated ones."));
}
$items[] = $this->_form["subgroup$i" . "sn"];
// Check with the subform checker
$form = array();
$form["member"] =& $this->_form["subgroup$i" . "sn"];
if ($this->_iscur) {
$form["grp"] =& $this->_sn;
}
$checker = new GroupMembershipChecker($form);
$error = $checker->check(array("member"));
if (!is_null($error)) {
return $error;
}
}
// OK
return null;
}
// _check_supgroup: Check the belonging groups
function _check_supgroup()
{
// Skip for a non-super-user editing a super-user group
if ($this->_iscur && !is_su() && $this->_sn == su_group_sn()) {
return null;
}
for ($i = 0, $items = array(); !$this->_missing("supgroup$i" . "sn"); $i++) {
// Skip unselected ones
if ($this->_missing("supgroup$i")) {
continue;
}
// Regularize it
$this->_form["supgroup$i" . "sn"] = trim($this->_form["supgroup$i" . "sn"]);
// Check if this selection is duplicated
if (in_array($this->_form["supgroup$i" . "sn"], $items)) {
return array("msg"=>NC_("This belonging group is duplicated. You cannot set duplicated ones."));
}
$items[] = $this->_form["supgroup$i" . "sn"];
// Check with the subform checker
$form = array();
$form["grp"] =& $this->_form["supgroup$i" . "sn"];
if ($this->_iscur) {
$form["member"] =& $this->_sn;
}
$checker = new GroupMembershipChecker($form);
$error = $checker->check(array("grp"));
if (!is_null($error)) {
return $error;
}
}
// OK
return null;
}
// _redir_selsubuser: Suspend and move to the subordinate user selection form
function _redir_selsubuser()
{
// Skip if not requested
if ($this->_missing("selsubuser")) {
return;
}
call_form(FORM_USERS, null, "import_selsubuser");
}
// _redir_selsubgroup: Suspend and move to the subordinate group selection form
function _redir_selsubgroup()
{
// Skip if not requested
if ($this->_missing("selsubgroup")) {
return;
}
call_form(FORM_GROUPS, null, "import_selsubgroup");
}
// _redir_selsupgroup: Suspend and move to the superordinate group selection form
function _redir_selsupgroup()
{
// Skip if not requested
if ($this->_missing("selsupgroup")) {
return;
}
call_form(FORM_GROUPS, null, "import_selsupgroup");
}
}
// UserMembershipChecker: User membership form checker class
class UserMembershipChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "usermem")
{
parent::__construct($form, $table);
}
// check: Run a list of checks
function check($cols)
{
// Run the parent method
$error = parent::check($cols);
if (!is_null($error)) {
return $error;
}
// See if we need to check the duplicates. Check it in the end.
if (in_array("grp", $cols) && in_array("member", $cols)) {
$error = $this->__check_dup();
if (!is_null($error)) {
return $error;
}
}
return null;
}
// _check_grp: Check the group
// Use the default group checker
// _check_member: Check the member
function _check_member()
{
// Check if it exists
$error = $this->_missing("member");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["member"] = trim($this->_form["member"]);
// Check if it is filled
if ($this->_form["member"] == "") {
return array("msg"=>NC_("Please select a member."));
}
// Check if this member exists
if (!check_sn_in($this->_form["member"], "users AS usrmembers")) {
return array("msg"=>NC_("This member does not exist anymore. Please select another one."));
}
// OK
return null;
}
// __check_dup: Check if this item is duplicated
function __check_dup()
{
$conds = array();
$conds[] = "grp=" . $this->_form["grp"];
$conds[] = "member=" . $this->_form["member"];
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This membership record already exists. You cannot create a duplicated one."));
}
return null;
}
// _redir_selmember: Suspend and move to the member selection form
function _redir_selmember()
{
// Skip if not requested
if ($this->_missing("selmember")) {
return;
}
call_form(FORM_USERS, null, "import_selmember");
}
// _redir_delmember: Remove the member
function _redir_delmember()
{
// Skip if not requested
if ($this->_missing("delmember")) {
return;
}
// Remove the item
unset($this->_form["member"]);
$status = null;
success_redirect($status);
}
}
// GroupMembershipChecker: Group membership form checker class
class GroupMembershipChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "groupmem")
{
parent::__construct($form, $table);
}
// check: Run a list of checks
function check($cols)
{
// Run the parent method
$error = parent::check($cols);
if (!is_null($error)) {
return $error;
}
// See if we need to check the duplicates. Check it in the end.
if (in_array("grp", $cols) && in_array("member", $cols)) {
$error = $this->__check_dup();
if (!is_null($error)) {
return $error;
}
}
return null;
}
// _check_grp: Check the group
function _check_grp()
{
// Run the default group checker
$error = parent::_check_grp();
if (!is_null($error)) {
return $error;
}
// Check if the group and the member are different
if ( !$this->_missing("member")
&& $this->_form["grp"] == $this->_form["member"]) {
return array("msg"=>NC_("Please select a different belonging group."));
}
// OK
return null;
}
// _check_member: Check the member
function _check_member()
{
// Check if it exists
$error = $this->_missing("member");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["member"] = trim($this->_form["member"]);
// Check if it is filled
if ($this->_form["member"] == "") {
return array("msg"=>NC_("Please select a member."));
}
// Check if this member exists
if (!check_sn_in($this->_form["member"], "groups AS grpmembers")) {
return array("msg"=>NC_("This member does not exist anymore. Please select another one."));
}
// Check if the group and the member are different
if ( !$this->_missing("grp")
&& $this->_form["grp"] == $this->_form["member"]) {
return array("msg"=>NC_("Please select a different group member."));
}
// OK
return null;
}
// __check_dup: Check if this item is duplicated
function __check_dup()
{
$conds = array();
$conds[] = "grp=" . $this->_form["grp"];
$conds[] = "member=" . $this->_form["member"];
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This membership record already exists. You cannot create a duplicated one."));
}
return null;
}
// _redir_selmember: Suspend and move to the member selection form
function _redir_selmember()
{
// Skip if not requested
if ($this->_missing("selmember")) {
return;
}
call_form(FORM_GROUPS, null, "import_selmember");
}
// _redir_delmember: Remove the member
function _redir_delmember()
{
// Skip if not requested
if ($this->_missing("delmember")) {
return;
}
// Remove the item
unset($this->_form["member"]);
$status = null;
success_redirect($status);
}
}
// ScriptPrivilegeChecker: Script privilege form checker class
class ScriptPrivilegeChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "scptpriv")
{
parent::__construct($form, $table);
}
// check: Run a list of checks
function check($cols)
{
// Run the parent method
$error = parent::check($cols);
if (!is_null($error)) {
return $error;
}
// See if we need to check the duplicates. Check it in the end.
if (in_array("script", $cols) && in_array("grp", $cols)) {
$error = $this->__check_dup();
if (!is_null($error)) {
return $error;
}
}
return null;
}
// _check_script: Check the script
// Use the default script checker
// _check_grp: Check the group
// Use the default group checker
// __check_dup: Check if this item is duplicated
function __check_dup()
{
$conds = array();
$conds[] = "script='" . sql_esctext($this->_form["script"]) . "'";
$conds[] = "grp=" . $this->_form["grp"];
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This script privilege already exists. You cannot create a duplicated one."));
}
return null;
}
}
// UserPreferenceChecker: User preference form checker class
class UserPreferenceChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "userpref")
{
parent::__construct($form, $table);
}
// check: Run a list of checks
function check($cols)
{
// Run the parent method
$error = parent::check($cols);
if (!is_null($error)) {
return $error;
}
// See if we need to check the duplicates. Check it in the end.
if (in_array("usr", $cols) && in_array("domain", $cols) && in_array("name", $cols)) {
$error = $this->__check_dup();
if (!is_null($error)) {
return $error;
}
}
return null;
}
// _check_usr: Check the user
function _check_usr()
{
// "everyone not set" has a different form context
if ($this->_missing("everyone")) {
return array("msg"=>NC_("Please select the user."));
}
// Regularize it
$this->_form["everyone"] = trim($this->_form["everyone"]);
// Check the option value
if (!in_array($this->_form["everyone"], array("true", "false"))) {
return array("msg"=>NC_("This option is invalid. Please select a proper user."));
}
// Run the default user checker if not everyone
if ($this->_form["everyone"] == "false") {
$error = parent::_check_usr();
if (!is_null($error)) {
return $error;
}
}
// OK
return null;
}
// _check_domain: Check the preference domain
function _check_domain()
{
// "everywhere not set" has a different form context
if ($this->_missing("everywhere")) {
return array("msg"=>NC_("Please set the preference domain."));
}
// Regularize it
$this->_form["everywhere"] = trim($this->_form["everywhere"]);
// Check the option value
if (!in_array($this->_form["everywhere"], array("true", "false"))) {
return array("msg"=>NC_("This option is invalid. Please set a proper preference domain."));
}
// Check the domain if not everywhere
if ($this->_form["everywhere"] == "false") {
// Check if it exists
$error = $this->_missing("domain");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["domain"] = trim($this->_form["domain"]);
// Check if it is filled
if ($this->_form["domain"] == "") {
return array("msg"=>NC_("Please fill in the preference domain."));
}
// Check the length
if (sql_strlen($this->_form["domain"]) > $this->maxlens["domain"]) {
return array("msg"=>NC_("This preference domain is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["domain"]));
}
}
// OK
return null;
}
// _check_name: Check the preference name
function _check_name()
{
// Check if it exists
$error = $this->_missing("name");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["name"] = trim($this->_form["name"]);
// Check if it is filled
if ($this->_form["name"] == "") {
return array("msg"=>NC_("Please fill in the preference name."));
}
// Check the length
if (sql_strlen($this->_form["name"]) > $this->maxlens["name"]) {
return array("msg"=>NC_("This preference name is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["name"]));
}
// OK
return null;
}
// _check_value: Check the preference value
function _check_value()
{
// Check if it exists
$error = $this->_missing("value");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["value"] = trim($this->_form["value"]);
// Check if it is filled
if ($this->_form["value"] == "") {
return array("msg"=>NC_("Please fill in the preference value."));
}
// Check the length
if (sql_strlen($this->_form["value"]) > $this->maxlens["value"]) {
return array("msg"=>NC_("This preference value is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["value"]));
}
// OK
return null;
}
// __check_dup: Check if this item is duplicated
function __check_dup()
{
$conds = array();
if ($this->_form["everyone"] == "true") {
$conds[] = "usr IS NULL";
} else {
$conds[] = "usr=" . $this->_form["usr"];
}
if ($this->_form["everywhere"] == "true") {
$conds[] = "domain IS NULL";
} else {
$conds[] = "domain='" . sql_esctext($this->_form["domain"]) . "'";
}
$conds[] = "name='" . sql_esctext($this->_form["name"]) . "'";
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This user preference already exists. You cannot create a duplicated one."));
}
return null;
}
// _redir_selusr: Suspend and move to the user selection form
function _redir_selusr()
{
// Skip if not requested
if ($this->_missing("selusr")) {
return;
}
call_form(FORM_USERS, null, "import_selusr");
}
// _redir_delusr: Remove the user
function _redir_delusr()
{
// Skip if not requested
if ($this->_missing("delusr")) {
return;
}
// Remove the item
unset($this->_form["usr"]);
$status = null;
success_redirect($status);
}
}
// UserRequestChecker: user requests form checker class
class UserRequestChecker extends UserChecker
{
protected $_types = array();
// __construct: Initialize the checker
function __construct(&$form, $table = "userreq")
{
parent::__construct($form, $table);
$this->minlens["email"] = 5;
$this->_types = array("join", "chgeml", "rstpwd");
}
// _check_type: Check the request type
function _check_type()
{
// "type not set" has a different form context
$error = $this->_missing("type");
if (!is_null($error)) {
return array("msg"=>NC_("Please select the request type."));
}
// Regularize it
$this->_form["type"] = trim($this->_form["type"]);
// Check the option value
if (!in_array($this->_form["type"], $this->_types)) {
return array("msg"=>NC_("This option is invalid. Please select a proper request type."));
}
// OK
return null;
}
// _check_usr: Check the user
function _check_usr()
{
// "anonymous not set" has a different form context
if ($this->_missing("anonymous")) {
return array("msg"=>NC_("Please select the user."));
}
// Regularize it
$this->_form["anonymous"] = trim($this->_form["anonymous"]);
// Check the option value
if (!in_array($this->_form["anonymous"], array("true", "false"))) {
return array("msg"=>NC_("This option is invalid. Please select a proper user."));
}
// Anonymous option depends on the request type
if ($this->_form["type"] == "join" && $this->_form["anonymous"] == "false") {
return array("msg"=>NC_("You must choose anonymous for join requests."));
}
if ($this->_form["type"] != "join" && $this->_form["anonymous"] == "true") {
return array("msg"=>NC_("You cannot choose anonymous for non-join requests."));
}
// Run the default user checker if not anonymous
if ($this->_form["anonymous"] == "false") {
$error = parent::_check_usr();
if (!is_null($error)) {
return $error;
}
}
// OK
return null;
}
// _check_args: Check the arguments
function _check_args()
{
// Check if it exists
$error = $this->_missing("args");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["args"] = trimtext($this->_form["args"]);
// Skip if it is not filled
if ($this->_form["args"] == C_("Please fill in the request arguments list here.")) {
$this->_form["args"] = "";
}
if ($this->_form["args"] == "") {
return null;
}
// Check the length
if (sql_strlen($this->_form["args"]) > $this->maxlens["args"]) {
return array("msg"=>NC_("This request arguments list is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["args"]));
}
// OK
return null;
}
// _redir_selusr: Suspend and move to the user selection form
function _redir_selusr()
{
// Skip if not requested
if ($this->_missing("selusr")) {
return;
}
call_form(FORM_USERS, null, "import_selusr");
}
// _redir_delusr: Remove the user
function _redir_delusr()
{
// Skip if not requested
if ($this->_missing("delusr")) {
return;
}
// Remove the item
unset($this->_form["usr"]);
$status = null;
success_redirect($status);
}
}
// ListPreferenceChecker: List preference form checker class
class ListPreferenceChecker extends BaseChecker
{
// Maximum list size is 1000, to prevent processing timeout.
const MAX_LISTSIZE = 1000;
// __construct: Initialize the checker
function __construct(&$form, $table = "userpref")
{
if (func_num_args() < 2) {
if (!is_guest()) {
$table = "userpref";
} else {
$table = null;
}
}
parent::__construct($form, $table);
if (is_null($table)) {
$this->maxlens = array();
$this->maxlens["domain"] = 64;
$this->maxlens["name"] = 16;
$this->maxlens["value"] = 65536;
}
$this->maxlens["listsize"] = 4;
}
// _check_domain: Check the preference domain
function _check_domain()
{
// Check if it exists
$error = $this->_missing("domain");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["domain"] = trim($this->_form["domain"]);
// Check if it is filled
if ($this->_form["domain"] == "") {
return array("msg"=>NC_("Please fill in the preference domain."));
}
// Check the length
if (sql_strlen($this->_form["domain"]) > $this->maxlens["domain"]) {
return array("msg"=>NC_("This preference domain is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["domain"]));
}
// OK
return null;
}
// _check_listcols: Check the list columns
function _check_listcols()
{
// No need to check the validility. Invalids are simply ignored.
$cols = array();
foreach (array_keys($this->_form) as $key) {
if (preg_match("/^listcols_(.+)$/", $key, $m)) {
$cols[] = $m[1];
}
}
// Obtain the preference value
$listcols = implode(" ", $cols);
// Check the length
if (sql_strlen("listcols") > $this->maxlens["name"]) {
$errmsg = sprintf("Maximum preference name length too short (%d for \"%s\" %d)",
$this->maxlens["name"], "listcols", sql_strlen("listcols"));
trigger_error($errmsg, E_USER_ERROR);
}
if (sql_strlen($listcols) > $this->maxlens["value"]) {
$errmsg = sprintf("Maximum preference value length too short (%d for \"%s\" %d)",
$this->maxlens["value"], $listcols, sql_strlen($listcols));
trigger_error($errmsg, E_USER_ERROR);
}
// OK
return null;
}
// _check_listsize: Check the list size
function _check_listsize()
{
// Check if it exists
$error = $this->_missing("listsize");
if (!is_null($error)) {
return $error;
}
$min = 0;
//$max = pow(10, $this->maxlens["listsize"]) - 1;
// Text string
if (is_string($this->_form["listsize"])) {
// Regularize it
$this->_form["listsize"] = trim($this->_form["listsize"]);
// Check if it is filled
if ($this->_form["listsize"] == "") {
return array("msg"=>NC_("Please fill in the number of rows per page."));
}
// Check the length
if (sql_strlen($this->_form["listsize"]) > $this->maxlens["listsize"]) {
return array("msg"=>NC_("This number of rows per page is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["listsize"]));
}
// If there is any non-digit character
if (preg_match("/\D/", $this->_form["listsize"])) {
return array("msg"=>NC_("Please fill in a positive integer number of rows per page."));
}
// Check if it is in the valid range
if ($this->_form["listsize"] < $min) {
return array("msg"=>NC_("The number of rows per page is too small. Please fill in a larger number of rows per page between %d and %d."),
"margs"=>array($min, self::MAX_LISTSIZE));
}
if ($this->_form["listsize"] > self::MAX_LISTSIZE) {
return array("msg"=>NC_("The number of rows per page is too large. Please fill in a smaller number of rows per page between %d and %d."),
"margs"=>array($min, self::MAX_LISTSIZE));
}
// Convert its type to integer
settype($this->_form["listsize"], "integer");
// Integer
} elseif (is_int($this->_form["listsize"])) {
// Check if it is in the valid range
if ($this->_form["listsize"] < $min) {
return array("msg"=>NC_("The number of rows per page is too small. Please fill in a larger number of rows per page between %d and %d."),
"margs"=>array($min, self::MAX_LISTSIZE));
}
if ($this->_form["listsize"] > self::MAX_LISTSIZE) {
return array("msg"=>NC_("The number of rows per page is too large. Please fill in a smaller number of rows per page between %d and %d."),
"margs"=>array($min, self::MAX_LISTSIZE));
}
// Other types are non-sense
} else {
trigger_error("Unknown type for column \"listsize\"", E_USER_ERROR);
}
// Check the length
if (sql_strlen("listsize") > $this->maxlens["name"]) {
$errmsg = sprintf("Maximum preference name length too short (%d for \"%s\" %d)",
$this->maxlens["name"], "listsize", sql_strlen("listsize"));
trigger_error($errmsg, E_USER_ERROR);
}
if (sql_strlen($this->_form["listsize"]) > $this->maxlens["value"]) {
$errmsg = sprintf("Maximum preference value length too short (%d for \"%s\" %d)",
$this->maxlens["value"], $this->_form["listsize"], sql_strlen($this->_form["listsize"]));
trigger_error($errmsg, E_USER_ERROR);
}
// OK
return null;
}
}
// LogInChecker: Log in form checker class
class LogInChecker extends UserChecker
{
public $row = null;
protected $_allcols;
protected $_login = null;
// __construct: Initialize the checker
function __construct(&$form, $table = "users")
{
parent::__construct($form, $table);
$this->row = null;
$this->_allcols = sql_cols($table);
// Always confirmed
$this->_form["confirm"] = true;
}
// check: Run a list of checks
function check($cols)
{
// See if a log in is attemped.
if (is_null($this->_login)) {
$this->_login = (in_array("id", $cols) && in_array("passwd", $cols));
}
// Run the parent method
$error = parent::check($cols);
if (!is_null($error)) {
return $error;
}
return null;
}
// _check_id: Check the user ID.
function _check_id()
{
// Check if it exists
$error = $this->_missing("id");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["id"] = trim($this->_form["id"]);
// Check if it is filled
if ($this->_form["id"] == "") {
return array("msg"=>NC_("Please fill in your user ID."));
}
// Check the length
if (sql_strlen($this->_form["id"]) > $this->maxlens["id"]) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because user ID is too long.");
}
return array("msg"=>NC_("Log in failed. Either your user ID or your password is incorrect."));
}
if (sql_strlen($this->_form["id"]) < $this->minlens["id"]) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because user ID is too short.");
}
return array("msg"=>NC_("Log in failed. Either your user ID or your password is incorrect."));
}
// Check if this user exists
$conds = array();
$conds[] = "id='" . sql_esctext($this->_form["id"]) . "'";
if (in_array("deleted", $this->_allcols)) {
$conds[] = sql_is_false("deleted");
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 1) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because user ID does not exist.");
}
return array("msg"=>NC_("Log in failed. Either your user ID or your password is incorrect."));
}
// Save it for further reference
$this->row = sql_fetch_assoc($result);
$this->_sn = $this->row["sn"];
// Check if log-in is closed
if (defined("NOLOGIN") && NOLOGIN && !is_su($this->_sn)) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " website is temporarily closed.");
}
// This message is duplicated
return array();
}
// Check if this user is disabled
if ($this->row["disabled"]) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because account is disabled.");
}
return array("msg"=>NC_("Your account is disabled. Contact our system administrator for assistence."));
}
// Check if we have exceed the maximum number of fail logins
// Skip super users - super users are invincible
if ( defined("MAX_FAIL_LOGINS")
&& MAX_FAIL_LOGINS !== false
&& !is_su($this->_sn)
&& $this->row["fails"] >= MAX_FAIL_LOGINS) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because too many bad logins (" . $this->row["fails"] . ").");
}
$this->_update_fails();
return array("msg"=>NC_("Log in failed. Either your user ID or your password is incorrect."));
}
// OK
return null;
}
// _check_passwd: Check the user password
function _check_passwd()
{
// Skip password checks for guests
if ( !is_null($this->_sn)
&& is_guest($this->_sn)) {
return null;
}
// Check if it exists
$error = $this->_missing("passwd");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["passwd"] = trim($this->_form["passwd"]);
// Check if it is filled
if ($this->_form["passwd"] == "") {
return array("msg"=>NC_("Please fill in your password."));
}
// Check the length
if (sql_strlen($this->_form["passwd"]) > $this->maxlens["passwd"]) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because password is too long.");
}
$this->_update_fails();
return array("msg"=>NC_("Log in failed. Either your user ID or your password is incorrect."));
}
if (sql_strlen($this->_form["passwd"]) < $this->minlens["passwd"]) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because password is too short.");
}
$this->_update_fails();
return array("msg"=>NC_("Log in failed. Either your user ID or your password is incorrect."));
}
// Check if the password is correct
if ( !is_null($this->row)
&& md5($this->_form["passwd"]) != $this->row["passwd"]) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because password is incorrect.");
}
$this->_update_fails();
return array("msg"=>NC_("Log in failed. Either your user ID or your password is incorrect."));
}
// OK
return null;
}
// _check_admin: Check if the user is an administrator
function _check_admin()
{
// Skip checking for guests
if (is_guest($this->_sn)) {
return null;
}
// Skip checking for super users
if (is_su($this->_sn)) {
return null;
}
// Check if this user is an administrator
if (!is_admin($this->_sn)) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because user is not an administrator.");
}
return array("msg"=>NC_("You are not an administrator so may not log in here."));
}
// OK
return null;
}
// _check_nonadmin: Check if the user is not an administrator
function _check_nonadmin()
{
// Skip checking for guests
if (is_guest($this->_sn)) {
return null;
}
// Check if this user is an administrator
if (is_admin($this->_sn)) {
if ($this->_login) {
actlog("Log in failed for user " . $this->_form["id"]
. " because user is an administrator.");
}
return array("msg"=>NC_("You are an administrator so may not log in here."));
}
// OK
return null;
}
// _update_fails: Add one to the number of failed logins
function _update_fails()
{
// We need the user information
if (is_null($this->_sn)) {
return;
}
sql_begin();
$update = "UPDATE users SET fails=fails+1,"
. " updated=now()"
. " WHERE sn=" . $this->_sn . ";\n";
sql_query($update);
sql_commit();
$this->row["fails"]++;
return;
}
}
/////////////////////////
// Content Checkers: Checkers for the content management system
/////////////////////////
// PageChecker: Page form checker class
class PageChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "pages")
{
parent::__construct($form, $table);
}
// _check_path: Check the page path
// Use the default page path checker
// _check_ord: Check the order
// Use the default order checker
// _check_title: Check the title
// Use the default title checker
// _check_body: Check the content body
// Use the default content body checker
// _check_kw: Check the keyword list
// Use the default keyword list checker
// _check_pic: Check the picture
// Use the default picture checker
// _check_piccap: Check the picture caption
// Use the default picture captio checker
// _check_picpos: Check the picture position
// Use the default picture position checker
}
// NewsChecker: News form checker class
class NewsChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "news")
{
parent::__construct($form, $table);
}
// _check_date: Check the date
// Use the default date checker
// _check_ord: Check the order
// Actually this is to set the order, but not to check the order
function _check_ord()
{
// Current form
if ($this->_iscur) {
global $CURRENT;
// Same day -- inherit the same order
if ($this->_form["date"] == $CURRENT["date"]) {
$this->_form["ord"] = $CURRENT["ord"];
return;
}
}
// Create a new order for this new day
$this->_form["ord"] = $this->_new_ord();
return;
}
// _check_title: Check the title
// Use the default title checker
// _check_body: Check the content body
// Use the default content body checker
// _check_kw: Check the keyword list
// Use the default keyword list checker
// _check_pic: Check the picture
// Use the default picture checker
// _new_ord: Create a new news order
function _new_ord()
{
// Cache the result
static $cache;
// Return the cache
if (isset($cache)) {
return $cache;
}
// Get the largest or der
$select = "SELECT ord FROM " . $this->_table
. " WHERE date='" . $this->_form["date"] . "'"
. " ORDER BY ord DESC LIMIT 1;\n";
$result = sql_query($select);
$count = sql_num_rows($result);
// No record yet
if ($count == 0) {
$cache = 1;
// Largest plus 1
} else {
$row = sql_fetch_assoc($result);
$cache = $row["ord"] + 1;
}
return $cache;
}
}
// CountryChecker: Country form checker class
class CountryChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "country")
{
parent::__construct($form, $table);
$this->minlens["id"] = 2;
}
// _check_id: Check the country code
function _check_id()
{
// Check if it exists
$error = $this->_missing("id");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["id"] = trim($this->_form["id"]);
// Check if it is filled
if ($this->_form["id"] == "") {
return array("msg"=>NC_("Please fill in the code."));
}
// Check the length
if (sql_strlen($this->_form["id"]) != $this->maxlens["id"]) {
return array("msg"=>NC_("You must fill in a %d-letters code."),
"margs"=>array($this->maxlens["id"]));
}
// Check if the characters used are valid
if (!preg_match("/^(?:[A-Z][A-Z0-9]|==)$/", $this->_form["id"])) {
return array("msg"=>NC_("You can only use upper letters and for the code."));
}
// Check if this item is duplicated
$conds = array();
$conds[] = "id='" . sql_esctext($this->_form["id"]) . "'";
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This code is duplicated. You cannot create a duplicated one."));
}
// OK
return null;
}
// _check_name: Check the country name
function _check_name()
{
// Check if it exists
$error = $this->_missing("name");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["name"] = trim($this->_form["name"]);
// Check if it is filled
if ($this->_form["name"] == "") {
return array("msg"=>NC_("Please fill in the country name."));
}
// Check the length
if (sql_strlen($this->_form["name"]) > $this->maxlens["name"]) {
return array("msg"=>NC_("This country name is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["name"]));
}
// OK
return null;
}
}
/////////////////////////
// Link Checkers: Checkers for the related links
/////////////////////////
// LinkCategoryChecker: Link category form checker class
class LinkCategoryChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "linkcat")
{
parent::__construct($form, $table);
$this->maxlens["ord"] = 2;
$this->minlens["id"] = 2;
}
// _check_parent: Check the parent category
function _check_parent()
{
// "topmost not set" has a different form context
$error = $this->_missing("topmost");
if (!is_null($error)) {
return array("msg"=>NC_("Please select a parent category."));
}
// Regularize it
$this->_form["topmost"] = trim($this->_form["topmost"]);
// Check the option value
if (!in_array($this->_form["topmost"], array("true", "false"))) {
return array("msg"=>NC_("This option is invalid. Please select a proper parent category."));
}
// Check the parent category if not a topmost category
if ($this->_form["topmost"] == "false") {
// Check if it exists
$error = $this->_missing("parent");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["parent"] = trim($this->_form["parent"]);
// Check if it is filled
if ($this->_form["parent"] == "") {
return array("msg"=>NC_("Please select a parent category."));
}
// Check if this category exists
if (!check_sn_in($this->_form["parent"], "linkcat")) {
return array("msg"=>NC_("This parent category does not exist anymore. Please select another one."));
}
if ($this->_iscur) {
// Check if the parent category is itself
if ($this->_form["parent"] == $this->_sn) {
return array("msg"=>NC_("A category cannot belong to itself. Please select another one."));
}
// Check if the parent directory is its descendant
$select = "SELECT linkcat_ischild(" . $this->_sn . ", "
. $this->_form["parent"] . ") AS is_child;\n";
$result = sql_query($select);
$row = sql_fetch_assoc($result);
if ($row["is_child"]) {
return array("msg"=>NC_("A category cannot belong to its descendant. Please select another one."));
}
}
}
// OK
return null;
}
// _check_id: Check the ID.
function _check_id()
{
// Run the default ID. checker
$error = parent::_check_id();
if (!is_null($error)) {
return $error;
}
// ID. cannot be "index" to avoid overriding index.html
if ($this->_form["id"] == "index") {
return array("msg"=>NC_("\"index\" is dedicated to the index file index.html. You cannot set the ID. as \"index\"."));
}
// Check if this item is duplicated
if (!$this->_missing("topmost", "parent")) {
$conds = array();
$conds[] = "id='" . sql_esctext($this->_form["id"]) . "'";
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
if ($this->_form["topmost"] == "true") {
$conds[] = "parent IS NULL";
} else {
$conds[] = "parent=" . $this->_form["parent"];
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This category already exists. You cannot create a duplicated one."));
}
}
// OK
return null;
}
// _check_ord: Check the order
// Use the default order checker
// _check_title: Check the title
// Use the default title checker
// _check_kw: Check the keyword list
// Use the default keyword list checker
// _redir_selparent: Suspend and move to the parent selection form
// Use the default parent redirector
// _redir_delparent: Remove the parent
// Use the default parent remover
}
// LinkChecker: Link form checker class
class LinkChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "links")
{
parent::__construct($form, $table);
}
// _check_title: Check the title
// Use the default title checker
// _check_url: Check the URL.
function _check_url()
{
// Check if it exists
$error = $this->_missing("url");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["url"] = trim($this->_form["url"]);
// Check if it is filled
if ($this->_form["url"] == "" || $this->_form["url"] == "http://") {
return array("msg"=>NC_("Please fill in the URL.."));
}
// Check the length
if (sql_strlen($this->_form["url"]) > $this->maxlens["url"]) {
return array("msg"=>NC_("This URL. is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["url"]));
}
// Check its format
if (!is_url_wellformed($this->_form["url"])) {
return array("msg"=>NC_("Please fill in a valid URL.."));
}
// Check if this item is duplicated
$conds = array();
$conds[] = "url='" . sql_esctext($this->_form["url"]) . "'";
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This related link already exists. You cannot create a duplicated one."));
}
// Check if it is available
if ( $this->_missing("hid")
&& !is_url_reachable($this->_form["url"])) {
return array("msg"=>NC_("This URL. is not reachable. Check if there is any typo in it."));
}
// OK
return null;
}
// _check_dsc: Check the description
function _check_dsc()
{
// Check if it exists
$error = $this->_missing("dsc");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["dsc"] = trimtext($this->_form["dsc"]);
// Check if it is filled
if ($this->_form["dsc"] == C_("Fill in the description here.")) {
$this->_form["dsc"] = "";
}
if ($this->_form["dsc"] == "") {
return array("msg"=>NC_("Please fill in the description."));
}
// Check the length
if (sql_strlen($this->_form["dsc"]) > $this->maxlens["dsc"]) {
return array("msg"=>NC_("This description is too long. (Max. length %d)"),
"margs"=>array($this->maxlens["dsc"]));
}
// OK
return null;
}
// _check_cats: Check the categories list
function _check_cats()
{
// Loop each category
for ($i = 0, $items = array(); !$this->_missing("cat$i"); $i++) {
// Regularize it
$this->_form["cat$i"] = trim($this->_form["cat$i"]);
// Skip if it is not filled
if ($this->_form["cat$i"] == "") {
continue;
}
// Check if this selection is duplicated
if (in_array($this->_form["cat$i"], $items)) {
return array("msg"=>NC_("This category is duplicated. You cannot set duplicated ones."));
}
// Check if the category exists
if (!check_sn_in($this->_form["cat$i"], "linkcat")) {
return array("msg"=>NC_("This category does not exist anymore. Please select another one."));
}
$items[] = $this->_form["cat$i"];
}
// Check if there is any category selected
if (count($items) == 0) {
return array("msg"=>NC_("Please select a category."));
}
// OK
return null;
}
}
// LinkCategorizationChecker: Link categorization form checker class
class LinkCategorizationChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = "linkcatz")
{
parent::__construct($form, $table);
}
// check: Run a list of checks
function check($cols)
{
// Run the parent method
$error = parent::check($cols);
if (!is_null($error)) {
return $error;
}
// See if we need to check the duplicates. Check it in the end.
if (in_array("cat", $cols) && in_array("link", $cols)) {
$error = $this->__check_dup();
if (!is_null($error)) {
return $error;
}
}
return null;
}
// _check_cat: Check the category
function _check_cat()
{
// Check if it exists
$error = $this->_missing("cat");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["cat"] = trim($this->_form["cat"]);
// Check if it is filled
if ($this->_form["cat"] == "") {
return array("msg"=>NC_("Please select a category."));
}
// Check if this category exists
if (!check_sn_in($this->_form["cat"], "linkcat")) {
return array("msg"=>NC_("This category does not exist anymore. Please select another one."));
}
// OK
return null;
}
// _check_link: Check the link
function _check_link()
{
// Check if it exists
$error = $this->_missing("link");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["link"] = trim($this->_form["link"]);
// Check if it is filled
if ($this->_form["link"] == "") {
return array("msg"=>NC_("Please select a related link."));
}
// Check if this link exists
if (!check_sn_in($this->_form["link"], "links")) {
return array("msg"=>NC_("This link does not exist anymore. Please select another one."));
}
// OK
return null;
}
// __check_dup: Check if this item is duplicated
function __check_dup()
{
$conds = array();
$conds[] = "cat=" . $this->_form["cat"];
$conds[] = "link=" . $this->_form["link"];
if ($this->_iscur) {
$conds[] = "sn!=" . $this->_sn;
}
$select = "SELECT * FROM " . $this->_table
. " WHERE " . implode(" AND ", $conds) . ";\n";
$result = sql_query($select);
if (sql_num_rows($result) != 0) {
return array("msg"=>NC_("This link categorization already exists. You cannot create a duplicated one."));
}
return null;
}
// _redir_sellink: Suspend and move to the link selection form
function _redir_sellink()
{
// Skip if not requested
if ($this->_missing("sellink")) {
return;
}
call_form(FORM_LINKS, null, "import_sellink");
}
}
/////////////////////////
// Miscellaneous Checkers: Checkers for various data
/////////////////////////
// RebuildChecker: Rebuild form checker class
class RebuildChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = null)
{
parent::__construct($form, $table);
}
// _check_type: Check the page type
function _check_type()
{
// Check if it exists
$error = $this->_missing("type");
if (!is_null($error)) {
return $error;
}
// Regularize it
$this->_form["type"] = trim($this->_form["type"]);
// Check if it is filled
if ($this->_form["type"] == "") {
return array("msg"=>NC_("Please select the type."));
}
// Check if this link exists
if (!function_exists("rebuild_" . $this->_form["type"])) {
return array("msg"=>NC_("This type does not exist anymore. Please select another one."));
}
// OK
return null;
}
}
// QueryChecker: Query form checker class
class QueryChecker extends BaseChecker
{
// __construct: Initialize the checker
function __construct(&$form, $table = null)
{
parent::__construct($form, $table);
}
// _check_query: Check the query phrase
function _check_query()
{
// Skip if there is no query phrase
if ($this->_missing("query")) {
return null;
}
// Regularize it
$this->_form["query"] = trim($this->_form["query"]);
// Check if it is filled
if ($this->_form["query"] == "") {
return array("msg"=>NC_("Please fill in your query."));
}
// OK
return null;
}
}
// PictureChecker: Picture form checker class
// This is specially for the pic.php picture handler
class PictureChecker extends BaseChecker
{
protected $_newpic = null;
// __construct: Initialize the checker
function __construct(&$form, $table = null)
{
parent::__construct($form, $table);
}
// _check_pic: Check the picture
function _check_pic()
{
// Check if it exists
$error = $this->_missing("pic");
if (!is_null($error)) {
return array("msg"=>NC_("Please submit the picture."));
}
// Check if this picture exists
if (!pic_exists($this->_form["pic"])) {
return array("msg"=>NC_("This picture does not exist anymore. Please upload another one."));
}
// Obtain the picture
$PICS =& pic_deposit();
$this->_newpic =& $PICS[$this->_form["pic"]];
// OK
return null;
}
// _check_ratio: Check the picture ratio
function _check_ratio()
{
// Check if it exists
$error = $this->_missing("ratio");
if (!is_null($error)) {
return $error;
}
// Regularize it
if (is_string($this->_form["ratio"])) {
$this->_form["ratio"] = trim($this->_form["ratio"]);
}
// Check if it is filled
if ($this->_form["ratio"] == "") {
return array("msg"=>NC_("Please fill in the resize ratio."));
}
// Check if the resize ratio is valid
if (!is_null($this->_newpic)) {
$error = check_pic_ratio($this->_newpic, $this->_form["ratio"]);
if (!is_null($error)) {
return $error;
}
}
}
// _save_uploaded_pic: Check and save the uploaded picture
function _save_uploaded_pic()
{
// Check if it exists
$error = file_has("uppic");
if (!is_null($error)) {
return $error;
}
// Skip if no new file was submitted
if ($_FILES["uppic"]["error"] == UPLOAD_ERR_NO_FILE) {
return null;
}
// Check the upload error
$error = check_picfile("uppic");
if (!is_null($error)) {
return $error;
}
// Save the picture
$pic = array();
$pic["content"] = xfread($_FILES["uppic"]["tmp_name"]);
$pic["type"] = $_FILES["uppic"]["type"];
$img = imagecreatefromstring($pic["content"]);
$pic["width"] = imagesx($img);
$pic["height"] = imagesy($img);
$picid = suspend_pic($pic);
$this->_form["pic"] = $picid;
$this->_form["ratio"] = best_pic_ratio($pic);
// Do not confirm now
if (!$this->_missing("confirm")) {
unset($this->_form["confirm"]);
}
// OK
return null;
}
}
// ShowPictureChecker: Show picture form checker class
class ShowPictureChecker extends BaseChecker
{
protected $_pic = null;
// __construct: Initialize the checker
function __construct(&$form, $table = null)
{
parent::__construct($form, $table);
}
// _check_sn: Check the picture S/N
function _check_sn()
{
// Check if it exists
$error = $this->_missing("sn");
if (!is_null($error)) {
return $error;
}
// Check if the picture is valid
if (!pic_exists($this->_form["sn"])) {
return array("msg"=>NC_("Please specify a valid picture."));
}
// Obtain the picture
$PICS =& pic_deposit();
$this->_pic =& $PICS[$this->_form["sn"]];
// OK
return null;
}
// _check_ratio: Check the picture ratio
function _check_ratio()
{
// Check if it exists
$error = $this->_missing("ratio");
if (!is_null($error)) {
return $error;
}
// Regularize it
if (is_string($this->_form["ratio"])) {
$this->_form["ratio"] = trim($this->_form["ratio"]);
}
// Check if it is filled
if ($this->_form["ratio"] == "") {
return array("msg"=>NC_("Please fill in the resize ratio."));
}
// Check if the resize ratio is valid
if (!is_null($this->_pic)) {
$error = check_pic_ratio($this->_pic, $this->_form["ratio"]);
if (!is_null($error)) {
return $error;
}
}
}
}
?>