<?php
/**
*******************************************************************************
FiForms -- A collection of PHP classes designed
to facilitate rapid development of web-database software
Copyright (C) 2003-2008 Daniel McFeeters
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
The original author of this library can be contacted at the following
address:
Daniel McFeeters
182 Baker Rd.
Faubush, KY 42544-6526
email:databases [at] fiforms [dot] org
http://www.fiforms.org/
Project Started May 4, 2003
*******************************************************************************
FiForms_FiForm.inc.php
Main FiForms include file
This file contains the definition for the main iForm class
This single file should be included in any script that uses
the functionality of the FiForms library
*******************************************************************************
**/
/* ?><code><?php */
/******************************************************************************
INCLUDES
******************************************************************************/
/**
* This does some automatic checking to attempt to load the local config file
* and templates.
*/
/*
if(!isset($FIFORMS_CONFIG))
{
if(!@include('localconfig.php'))
{
// can't include config from php path, so we'll try to get the config
// from the same directory as the calling php (which is always
// the first file in get_included_files()
$includes = get_included_files();
if(!@include(dirname($includes[0])."/localconfig.php"))
{
die('No Configuration found. Did you perhaps call an include file' .
' directly instead of calling it as part of the FiForms' .
' application?');
}
} // end if can't include config
} // end if no config
*/
/* ?><ignore><?php */
require_once("FiForms_iContainer.inc.php");
require_once("FiForms_iFormControl.inc.php");
require_once("FiForms_imports.inc.php");
require_once("FiForms_QueryParser.inc.php");
require_once("htmltemplate.php");
/* ?></ignore><?php */
/******************************************************************************
FIFORM CLASS DEFINITION
******************************************************************************/
class FiForm extends iContainer
{
/******************************************************************************
PROPERTIES
******************************************************************************/
public $dataServer; // the name or IP address of MySQL Server
public $dataDB; // the name of the database to connect to
public $dataTable; // name of table where data comes from, and also the
// table to update. If $dataQuery not given, used to
// construct $dataQuery
public $dataQuery; // Query used to retreive data from MySQL table. If
// not given, set to "SELECT * FROM $dataTable;"
// NOTE: never include a WHERE, GROUP BY, or HAVING
// clause in dataQuery. Use the where property
// to set the WHERE clause
public $formAction; // the page to load. If not given, use PHP_SELF
public $currentRec; // Index of current record in MySQL dataset
public $maxRec; // Index of the last record in MySQL dataset
private $keyArray; // String of html containing primary keys in hidden
// inputs. Used to identify the record when updated.
public $readOnly; // global readOnly; if TRUE, sets all
// $this->inputs[]->readOnly=TRUE
private $isProcessed;// tests whether the processData function has been
// called in this instance
private $formatStrSV;// format string when form in in sheetView mode
public $sheetView; // true if form is in sheetView mode
public $recordLimit;
// Maximum number of records returned by dataQuery
public $controlsOnTop;
// show the form control links on top and on bottom
public $noNavigation;
// disables the navigation links on the form control
public $showDelete; // show the delete function, even if navigation
// is disabled
public $having; // HAVING clause (without the keyword)
public $groupBy; // GROUP BY clause (without the keyword)
public $orderBy; // field to order the query by
private $orderDesc; // if TRUE, sort in descending order by field orderBy
public $wrapper; // contains HTML code to "wrap" the form into a
// complete HTML page
public $noMoveOnInsert; // if true, return to inserted record after
// insert, rather than moving to a new record.
private $auth; // authentication Module
public $where; // WHERE clause of query (without WHERE keyword)
public $allowSheetView; // set to TRUE if sheet view is allowed at all
public $allowFormView; // set to TRUE if form (normal) view is allowed
public $allowNewView; // set to TRUE if form (normal) view is allowed
// in insert mode
public $debugMode; // set to TRUE to show all debug info in HTML
private $merge_query; // saved data query
private $connectID; // MySQL connection ID
public $excludeLinkTerms;
// Parameters to preserve in links passed in the URL
// source
public $allowedParameters;
// Parameters allowed to be passed to the form
// query WHERE clause directly through the URL.
private $controlHeader;
private $controlHeaderSpacer;
private $controlFooter;
public $timing; // array of timing information for performance tuning
public $preQueries; // array of queries to execute before the main query
/******************************************************************************
CONSTRUCTOR
******************************************************************************/
public function FiForm()
// class constructor. Used to initialize variables
{
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['CONSTRUCTOR'] = microtime(true);
}
$this->auth = new FiFormsAuth();
$this->dataServer = $GLOBALS['FIFORMS_CONFIG']['DEFAULT_SERVER'];
$this->dataDB = $GLOBALS['FIFORMS_CONFIG']['DEFAULT_DATABASE'];
$this->name = "FiFormData";
if(func_num_args() >= 3)
{
$formArgs = func_get_args();
if($formArgs[0] != "")
{
$this->name = $formArgs[0];
}
$this->dataDB = $formArgs[1];
$this->dataTable = $formArgs[2];
if($GLOBALS['FIFORMS_CONFIG']['CONNECT_EARLY'])
{
$this->makeConnection();
}
}
// Initialize $formatStr
$this->formatStrSV->rowStartEven = "<tr class=\"even\">";
$this->formatStrSV->headStart = "<thead><tr class=\"odd\">";
$this->formatStrSV->headStop = "</tr></thead><tbody>";
$this->formatStrSV->rowStartOdd = "<tr class=\"odd\">";
$this->formatStrSV->rowStop = "</tr>";
if(array_key_exists("deleteRec",$_GET) && $_GET["deleteRec"] == "confirm")
{
$this->readOnly = TRUE;
}
if(array_key_exists("readonly",$_GET) && $_GET["readonly"] == "TRUE")
{
$this->readOnly = TRUE;
}
$this->formAction = htmlentities(stripslashes(
$GLOBALS['FIFORMS_CONFIG']['SERVER_ADDRESS'].
$_SERVER["REQUEST_URI"]));
$this->currentRec = array_key_exists("currentRec",$_GET) ?
$_GET["currentRec"] : "";
if(array_key_exists("sheetView",$_GET) && $_GET["sheetView"] == "YES")
{
$this->sheetView = TRUE;
}
$this->wrapper = new htmlTemplate();
$this->wrapper->errorMsg = "";
$this->errorMsg = &$this->wrapper->errorMsg;
$this->wrapper->pageHeader = "<div class=\"FiFormPage\">";
$this->allowSheetView = TRUE;
$this->allowFormView = TRUE;
$this->allowNewView = TRUE;
$this->excludeLinkTerms = array("deleteRec","currentRec",
"PRIMARYKEYS","PRIMARYKEY_");
$this->moveOnInsert = TRUE;
$this->allowUserSort = TRUE;
$this->recNum = $this->currentRec;
$this->inputs = array();
$this->inputs["_CONTROLS"] = new iFormControl($this);
$this->inputs["_CONTROLS"]->visible = FALSE;
$this->allowedParameters = array();
$this->isProcessed = FALSE;
$this->controlHeader = "";
$this->controlFooter = "";
$this->having = "";
$this->groupBy = "";
$this->preQueries = array();
$this->boundForm = &$this;
} //function FiForm
function getXMLContent($query,$fiform,$doc)
{
$content = "";
$rslt = $fiform->query($query)->item(0);
if(is_object($rslt) && property_exists($rslt,'firstChild'))
{
$element = $rslt->firstChild;
}
else
{
return false;
}
while($element)
{
$content .= $doc->saveXML($element);
$element = $element->nextSibling;
}
return str_replace(array("<html:","</html:","<default:","</default:"),
array("<", "</", "<", "</", ),$content);
}
function loadXMLDef($doc)
{
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['LOADXML_START'] = microtime(true);
}
// Initialize Variables
$doc->preserveWhiteSpace = false;
// Create a DOMXPath object $fiform so we can access data in $doc
$fiform = new DOMXPath($doc);
foreach($GLOBALS['FIFORM_XML_INPUT_NAMESPACES'] as $prefix => $uri)
{
$fiform->registerNamespace($prefix,$uri);
}
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['LOADXML_GOTDOC'] = microtime(true);
}
// Process Conditional Statements (<if> tags)
$ifNode = $doc->getElementsByTagName('if')->item(0);
while($ifNode)
{
$subElement = $ifNode->firstChild;
while($subElement)
{
$nextElement = $subElement->nextSibling;
$paramName = $ifNode->getAttribute('param');
$paramTest = $ifNode->getAttribute('test');
$paramCompare = $ifNode->getAttribute('value');
$paramValue = array_key_exists($paramName,$_GET) ?
$_GET[$paramName] : "";
if(get_magic_quotes_gpc())
{
$paramValue = stripslashes($paramValue);
}
switch($paramTest)
{
case 'equals':
$switch = ($paramValue == $paramCompare);
break;
case 'does not equal':
$switch = ($paramValue != $paramCompare);
break;
case 'is greater than':
$switch = ($paramValue > $paramCompare);
break;
case 'is less than':
$switch = ($paramValue < $paramCompare);
break;
case 'is greater than or equal to':
$switch = ($paramValue >= $paramCompare);
break;
case 'is less than or equal to':
$switch = ($paramValue <= $paramCompare);
break;
case 'does not exist':
$switch = !array_key_exists($paramName,$_GET) ||
$paramValue === '';
break;
case 'exists':
default:
$switch = array_key_exists($paramName,$_GET) &&
$paramValue !== '';
} // switch
if($switch)
{
$ifNode->parentNode->insertBefore($subElement,$ifNode);
}
$subElement = $nextElement;
} // while subElement
$ifNode->parentNode->removeChild($ifNode);
$ifNode = $doc->getElementsByTagName('if')->item(0);
} // while ifNode
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['LOADXML_STRIPPEDIFS'] = microtime(true);
}
$fiformatt = $fiform->query("/f:fiform")->item(0)->attributes;
$noMoveOnInsert = FALSE;
if($fiformatt->getNamedItem('insert'))
{
if($fiformatt->getNamedItem('insert')->nodeValue == 'none' && $_GET['currentRec'] == 'new')
{
$this->allowNewView = FALSE;
$_GET['currentRec'] = '';
$_POST = array();
}
if($fiformatt->getNamedItem('insert')->nodeValue == 'sheet' && $_POST)
{
$_GET['sheetView'] = 'YES';
}
if($fiformatt->getNamedItem('insert')->nodeValue == 'current')
{
$noMoveOnInsert = TRUE;
}
}
if($fiformatt->getNamedItem('allowInsert') and $fiformatt->getNamedItem('allowInsert')->nodeValue == 'no')
{
$this->allowNewView = FALSE;
$_GET['currentRec'] = '';
$_POST = array();
}
if($fiformatt->getNamedItem('allowView') and $fiformatt->getNamedItem('allowView')->nodeValue == 'no' && $_GET['currentRec'] != 'new')
{
$_GET['currentRec'] = 'new';
}
$viewsAllowed = $fiformatt->getNamedItem('viewsAllowed')->nodeValue;
switch($viewsAllowed)
{
case "none":
$this->allowSheetView = FALSE;
$this->allowFormView = FALSE;
break;
case "sheet":
$this->allowFormView = FALSE;
$this->allowSheetView = TRUE;
$_GET['sheetView'] = 'YES';
break;
case "form":
$this->allowSheetView = FALSE;
$this->allowFormView = TRUE;
unset($_GET['sheetView']);
break;
default:
$this->allowSheetView = TRUE;
$this->allowFormView = TRUE;
}
// Extract form definition from XML and build the fiform
// Create new FiForm object
$this->noMoveOnInsert = $noMoveOnInsert;
// Start processing the definition, generating FiForm objects and
// copying properties
$db =
trim($fiform->query("/f:fiform/f:connect/@db")->item(0)->nodeValue);
if($db)
{
$this->dataDB = $db;
}
$this->dataTable =
trim($fiform->query("/f:fiform/f:connect/@update")->item(0)->nodeValue);
$connectID = $fiform->query("/f:fiform/f:connect/@id")->item(0)->nodeValue;
foreach($fiform->query('/f:fiform/f:param') as $param)
{
$name = trim($param->attributes->getNamedItem('name')->nodeValue);
$this->allowedParameters[] = $name;
}
// Load any "pre" queries
$i = 1;
$sqlNode = $fiform->query("/f:fiform/f:query[@mode='pre'][$i]/f:sql/text()");
while(is_object($sqlNode->item(0)))
{
$j = 0;
$sql = "";
while($sqlNode->item($j))
{
$sql .= $sqlNode->item($j)->nodeValue." ";
$j++;
}
$this->preQueries[] = $sql;
$i++;
$sqlNode = $fiform->query("/f:fiform/f:query[@mode='pre'][$i]/f:sql/text()");
} // end while
$sqlNode = $fiform->query("/f:fiform/f:query[not(@mode)]/f:sql/text()");
if(is_object($sqlNode))
{
$i = 0;
$sql = "";
while($sqlNode->item($i))
{
$sql .= $sqlNode->item($i)->nodeValue." ";
$i++;
}
$this->setQuery($sql);
} // if is_object
if($fiformatt->getNamedItem('allowUpdate') &&
$fiformatt->getNamedItem('allowUpdate')->nodeValue == 'no' &&
$_GET['currentRec'] != 'new')
{
$this->readOnly = TRUE;
$_POST = array();
}
$this->caption = $fiform->query("/f:fiform/f:title")->item(0)->nodeValue;
$ctrlPosition = $fiformatt->getNamedItem('ctlPosition')->nodeValue;
if(($ctrlPosition == 'top' || $ctrlPosition == 'both') &&
$_GET['sheetView'] != 'YES')
{
$this->controlsOnTop = TRUE;
}
$whichString = $fiformatt->getNamedItem('whichControls')->nodeValue;
$which = explode(",",$whichString);
if($ctrlPosition == 'none' || (!is_null($whichString) &&
!in_array('all',$which) && !in_array('nav',$which)))
{
$this->noNavigation = TRUE;
}
// FIXME: showDelete should be false if not "all" or "delete" or nothing
if(in_array('delete',$which))
{
$this->showDelete = TRUE;
}
$this->clearPrimaryKeys();
foreach($fiform->query('/f:fiform/f:connect/f:primaryKey') as $pkey)
{
$this->setPrimaryKey(trim($pkey->attributes->getNamedItem('field')->nodeValue));
}
$svPosition = $fiformatt->getNamedItem('svctlPosition')->nodeValue;
if($svPosition == 'left' || $svPosition == 'both')
{
$this->inputs[] = new iLinkBack();
}
$rLimitNode = $fiformatt->getNamedItem('recordLimit');
if(is_object($rLimitNode))
{
$rLimit = $rLimitNode->nodeValue;
if($rLimit > 1)
{
$this->recordLimit = $rLimit;
}
} // if is_object
// Record timing mark before starting loop
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['LOADXML_SETPROP'] = microtime(true);
}
// Loop over each element in the body of the form
$startPath = '/f:fiform/';
foreach($fiform->query(
$startPath.
implode(' | '.$startPath,
$GLOBALS['FIFORM_XML_INPUTS'])) as $input)
{
$this->loadInputFromXML($input);
}
if($svPosition == "right" || $svPosition == "both" || !$svPosition)
{
$this->inputs[] = new iLinkBack();
}
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['LOADXML_BUILTINPUTS'] = microtime(true);
}
$this->wrapper->pageHeader .=
$this->getXMLContent("/f:fiform/f:wrapper/f:pageHeader",$fiform,$doc);
$this->wrapper->pageFooter .=
$this->getXMLContent("/f:fiform/f:wrapper/f:pageFooter",$fiform,$doc);
$this->wrapper->headerTags .=
$this->getXMLContent("/f:fiform/f:wrapper/f:headerTags",$fiform,$doc);
$this->wrapper->bodyProperties .=
$this->getXMLContent("/f:fiform/f:wrapper/f:bodyProperties",
$fiform,$doc);
$element = $fiform->query("/f:fiform/f:wrapper/f:bodyProperties")->item(0);
if($element)
{
foreach($element->attributes as $attr)
{
$this->wrapper->bodyProperties .=
$attr->nodeName."=\"".$attr->nodeValue."\" ";
}
}
unset($doc);
// Record Timing Point
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['LOADXML_END'] = microtime(true);
}
} // function loadXMLDef
/******************************************************************************
MAKE CONNECTION
******************************************************************************/
public function makeConnection()
{
// Connect to the MySQL database and select the database
if(!$this->dataDB)
{
return(false);
}
if($this->connectID)
{
return($this->connectID);
}
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['DBCONNECT_START'] = microtime(true);
}
$this->wrapper->debugQueries .= "Making Connection<br/><br />";
$this->connectID = @mysql_connect($this->dataServer,
$this->auth->username,
$this->auth->passwd);
if(!$this->connectID)
{
$this->auth->connectFailure();
$this->throwError("Unable to connect to server ".$this->dataServer);
return(false);
}
elseif(!mysql_select_db($this->dataDB))
{
$suggestion = "";
if($GLOBALS['FIFORMS_CONFIG']['ALLOW_DD_OPERATIONS'])
{
$uri = $GLOBALS['FIFORMS_CONFIG']['URI']."createSchema.php";
$app = htmlentities($_GET['app']);
$formname = htmlentities($_GET['formname']);
$suggestion = <<<EOD
<br /><p>
If you want, and if your account has enough permissions,
FiForms can correct this problem for you by creating the
database and the table that you need to use this form.
</p>
<p>
<a href="$uri?createDB=YES&app=$app&formname=$formname">Click here
to attempt to create the necessary items.</a>
</p>
EOD;
}
$this->throwError("Unable to select database ".$this->dataDB.$suggestion);
return(false);
}
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['DBCONNECT_END'] = microtime(true);
}
return($this->connectID);
} //makeConnection
/******************************************************************************
CLOSE CONNECTION
******************************************************************************/
private function closeConnection ()
{
if($this->connectID)
{
$this->wrapper->debugQueries .= "Closing Connection<br/><br />";
mysql_close($this->connectID);
$this->connectID = 0;
}
else
{
return 0;
}
}
/******************************************************************************
BUILD TABLE DESCRIPTION
******************************************************************************/
private function runQuery($sql)
{
if(trim($sql) == '')
{
return false;
}
$lastTime = microtime(true);
$this->wrapper->debugQueries .=
"<p>".nl2br(htmlentities($sql)).";</p>";
$rslt = @mysql_query($sql);
$err = mysql_error();
if($err)
{
$this->throwError(
"MySQL returned an error while running a query: ".
$err);
$this->wrapper->debugQueries .= "<p>ERROR: $err</p>";
}
// Record timing in debugQueries output
$thisTime = microtime(true);
$this->wrapper->debugQueries .=
"<p># Running Time:".($thisTime - $lastTime)."</p>";
return $rslt;
}
private function buildTableDescription()
{
// Get a description of dataTable so we know how to build
// an update / insert statement
$describeQuery = "DESCRIBE ".$this->dataTable;
$describeRslt = $this->runQuery($describeQuery);
if(!$describeRslt)
{
$this->throwError(
"<b>Error getting field information from table.
Unable to save data.</b><br />");
return(FALSE);
}
$buildKeys = (count($this->keyArray) == 0);
while($describerow=mysql_fetch_array($describeRslt))
{
$describeArray[] = $describerow["Field"];
if($describerow["Key"] == "PRI" && $buildKeys)
{
$this->keyArray[] = $describerow["Field"];
}
}
return($describeArray);
} // function buildTableDescription
/******************************************************************************
SAVE POST DATA
******************************************************************************/
private function savePostData()
// Save the data submitted via _POST to MySQL dataTable
{
if($this->dataTable=="")
{
if(count($_POST) == 0)
{
return(TRUE);
}
else
{
$this->throwError(
"<b>No data table specified.
Unable to save data.</b><br />");
return(FALSE);
} // if POST
} // if dataTable
if(count($_POST) > 0 || count($this->keyArray) == 0)
$describeArray = $this->buildTableDescription();
if(!$describeArray && count($_POST) > 0)
return(FALSE);
if(count($_POST) == 0)
{
return(TRUE);
}
if($this->error)
{
return(FALSE);
}
if(($GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY']) &&
isset($_POST['_CHECK_DATA'])
&& strlen($_POST['_CHECK_DATA']) > 50
&& function_exists('mcrypt_module_open'))
{
$hash = substr($_POST['_CHECK_DATA'],0,40);
$data = substr($_POST['_CHECK_DATA'],40);
if(sha1($data.$GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY']) != $hash)
{
$this->throwError("Check data appears to be invalid. Unable to save data.");
return FALSE;
}
$check_data = unserialize($this->decompress($this->crypt(pack("H*",$data),true)));
//print_r($check_data);
if(is_array($check_data['preQueries']))
{
foreach($check_data['preQueries'] as $preQuery)
{
$this->runQuery($preQuery);
}
}
$result = $this->runQuery($check_data['dataQuery']);
if(!$result)
{
$this->throwError("Error executing check data query. Unable to save data.");
}
$rslt_array = @mysql_fetch_array($result,MYSQL_ASSOC);
if($rslt_array != $check_data['resultArray'])
{
$this->throwError(
"<b>This record has been modified in the database while you were editing it.
Following is a proposed merge of the changes. Please verify that the changes
are correct and click \"Update Record\" again to save your changes.</b><br />");
$this->merge_record = $rslt_array;
$this->merge_query = $check_data['dataQuery'];
$this->original_record = $check_data['resultArray'];
}
if($this->error)
{
$this->closeConnection();
$this->makeConnection();
return false;
}
}
else if(($GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY']) && $this->currentRec != "new" && function_exists('mcrypt_module_open'))
{
$this->throwError("No check data available. Unable to save data.");
return false;
}
if($this->currentRec === "new")
{
$tmp = "";
$this->buildInsertQuery($describeArray,$updateQuery,$tmp);
} // if currentRec = new
elseif($_GET["deleteRec"] == "")
{
$this->buildUpdateQuery($describeArray,$updateQuery);
} // else if deleteRec
elseif($_GET["deleteRec"] == "confirm" &&
$_POST["_DELETECONFIRM"]=="yes")
{
$updateQuery = $this->buildDeleteQuery($describeArray);
$this->readOnly = FALSE;
}// else if deleteRec
else
{
$updateQuery = TRUE;
} // else (nothing)
if(!$updateQuery)
{
// exit on error
$this->throwError("<b>Error building the query statement.</b><br />");
return(FALSE);
}
if($this->currentRec !== "new")
{
$criteria = $this->buildQueryCriteria();
if(!$criteria)
{
$this->throwError(
"<b>Unable to determine criteria for updating record. Update aborted.</b><br />");
return(FALSE);
}
$updateQuery .= $criteria;
} // if currentRec=
if($this->error)
{
return false;
}
$success = $this->runQuery($updateQuery);
$this->insertID = selectValue('SELECT @last_fiforms_UUID');
if(!$this->insertID)
{
$this->insertID = mysql_insert_id();
}
$this->closeConnection();
$this->makeConnection();
if($success)
{
return(TRUE);
}
else
{
return(FALSE);
}
} // function savePostData
/******************************************************************************
BUILD INSERT QUERY
******************************************************************************/
function buildInsertQuery($describeArray,&$updateQuery,&$valuestring)
// build an INSERT query to insert posted data into the database
{
$updateQuery = "INSERT INTO ".$this->dataTable." (";
$valuestring = "";
parent::buildInsertQuery($describeArray,$updateQuery,$valuestring);
$updateQuery = substr($updateQuery,0,strlen($updateQuery)-2);
$updateQuery .= ") VALUES (".$valuestring;
$updateQuery = substr($updateQuery,0,strlen($updateQuery)-2);
$updateQuery .= ")";
return($updateQuery);
} // function buildInsertQuery
/******************************************************************************
BUILD UPDATE QUERY
******************************************************************************/
function buildUpdateQuery($describeArray,&$updateQuery)
{
$updateQuery = "UPDATE ".$this->dataTable." SET ";
parent::buildUpdateQuery($describeArray,$updateQuery);
$updateQuery = substr($updateQuery,0,strlen($updateQuery)-2);
}
/******************************************************************************
BUILD DELETE QUERY
******************************************************************************/
private function buildDeleteQuery($describeArray)
{
$updateQuery = "DELETE FROM ".$this->dataTable;
return($updateQuery);
}
/******************************************************************************
BUILD QUERY CRITERIA
******************************************************************************/
private function buildQueryCriteria()
// build the WHERE clause for the select statement used in
// savePostData
{
$updateQuery = " WHERE ";
foreach($this->keyArray as $thisKey)
{
if(!array_key_exists("PRIMARYKEY_".$thisKey,$_POST))
// if value doesn't exist
{
return(FALSE);
} // if
$updateQuery .= "`".$thisKey."` = \"".
$_POST["PRIMARYKEY_".$thisKey]."\" AND ";
} // foreach in keyArray
$updateQuery = substr($updateQuery,0,strlen($updateQuery)-4);
$updateQuery .= "LIMIT 1";
return($updateQuery);
}
/******************************************************************************
GET NEXT RECORD
******************************************************************************/
public function crypt($input,$decrypt = false)
{
$key = $GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY'];
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
if($decrypt)
$encrypted_data = mdecrypt_generic($td, $input);
else
$encrypted_data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $encrypted_data;
}
private function getNextRecord()
{
$this->resultArray =
@mysql_fetch_array($this->resultSet,MYSQL_ASSOC);
// get the next row from the resultSet. If there is no row, and
// hence mysql_fetch_array returns false, then getNextRecord also
// returns false without futher processing.
if($this->resultArray == FALSE)
{
return(FALSE);
}
$this->buildKeyTags();
// Check the verification data to see if this record has been modified.
if(($GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY']) &&
isset($this->inputs['_CHECK_DATA']) &&
function_exists('mcrypt_module_open'))
{
$check_data = array();
$check_data['resultArray'] = $this->resultArray;
$check_data['dataQuery'] = $this->dataQuery;
$check_data['preQueries'] = $this->preQueries;
$data_string = bin2hex($this->crypt($this->compress(serialize($check_data))));
$this->inputs['_CHECK_DATA']->setValue(
sha1($data_string.
$GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY'])
.$data_string);
}
$this->fillInputs();
return(TRUE);
} // function getNextRecord
/******************************************************************************
RESTORE RECORD
******************************************************************************/
private function restoreRecord()
// reinstate values submitted via _POST back into the form
// (called when an error occurs in saving the data)
{
$merge_mode = ($GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY']) &&
is_array($this->original_record) &&
is_array($this->merge_record);
$this->restoreMerge($merge_mode);
if($merge_mode)
{
$this->inputs['_CHECK_DATA'] = new iHidden('_CHECK_DATA');
$check_data = array();
$check_data['resultArray'] = $this->merge_record;
$check_data['dataQuery'] = $this->merge_query;
$preQueries = $this->preQueries;
$params = $_GET;
if(!get_magic_quotes_gpc())
{
foreach($params as $key => $value)
{
$params[$key] = addslashes($value);
}
} // if not magic quotes
foreach($preQueries as $k => $q)
{
$preQueries[$k] = fillVars($_GET,$q);
}
$check_data['preQueries'] = $preQueries;
$data_string = bin2hex($this->crypt($this->compress(serialize($check_data))));
$this->inputs['_CHECK_DATA']->setValue(
sha1($data_string.$GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY']).
$data_string);
} // if
// output PRIMARYKEY inputs
foreach($_POST as $fieldName => $fieldValue)
{
if(strpos($fieldName,"PRIMARYKEY") !== FALSE)
{
$this->inputs[$fieldName] = new iHidden($fieldName);
$this->inputs[$fieldName]->setValue($fieldValue);
} // if
} // foreach
} // function restoreRecord
/******************************************************************************
BUILD SELECT QUERY
******************************************************************************/
private function buildSelectQuery()
{
$dataQuery = &$this->dataQuery;
// Build a complete SELECT query
if($dataQuery == "" && $this->dataTable != "")
{
// generate a "generic" query if none exists.
if($GLOBALS['FIFORMS_CONFIG']['MYSQL_VERSION'] < 4.0)
{
$dataQuery = "SELECT * FROM `".$this->dataTable."`";
}
else
{
$dataQuery = "SELECT SQL_CALC_FOUND_ROWS * FROM `".
$this->dataTable."`";
}
} // if no dataQuery
if($dataQuery == "")
{
return;
}
// make sure the query isn't already terminate by a semicolon
if(substr($dataQuery,strlen($dataQuery)-1) == ";")
{
$dataQuery = substr($dataQuery,0,-1);
}
if($_GET["PRIMARYKEYS"] == "" || $_POST["_DELETECONFIRM"] == "yes")
{
if(is_array($this->allowedParameters))
{
if($this->where != "")
{
$this->where .= " AND ";
}
foreach($this->allowedParameters as $param)
{
if(isset($_GET[$param]))
{
$this->where .= "$param = \"".$_GET[$param]."\" AND ";
}
}
$this->where .= "1";
}
if($this->where == "")
{
$this->where = "1";
}
$dataQuery .= " WHERE ".$this->where;
} // if no PRIMARYKEYS
// Generate an ORDER BY clause to be added to the query
// This fixes the bug that required an ORDER BY clause
// to be declared on every form
if($this->allowUserSort && $_GET['sort'])
{
$sort = $_GET['sort'];
if(array_key_exists($sort,$this->inputs))
{
if($this->inputs[$sort]->allowUserSort)
{
$this->orderBy = " ORDER BY ".$this->inputs[$sort]->dbField." ";
if($_GET['st'] == 'DESC')
$this->orderDesc = TRUE;
}
}
}
if(trim($this->orderBy) == "" && $this->keyArray[0])
{
$this->orderBy = " ORDER BY 1 ";
foreach($this->keyArray as $key)
{
$this->orderBy .= ", $key ";
}
}
else if(trim($this->orderBy) == "")
{
$this->orderBy = " ORDER BY 1 ";
}
// add a LIMIT to the query. (Note that this will generate an
// error if the query already has a LIMIT)
//$this->buildTableDescription();
if($_GET["PRIMARYKEYS"] != "" &&
$_POST["_DELETECONFIRM"] != "yes" && $this->keyArray)
{
$dataQuery .= " WHERE 1 ";
foreach($this->keyArray as $key)
{
$dataQuery .= " AND $key = \"".$_GET["PRIMARYKEY_$key"]."\"";
}
} // if single record query
if($this->groupBy != "")
{
$dataQuery .= " GROUP BY ".$this->having;
}
if($this->having != "")
{
$dataQuery .= " HAVING ".$this->having;
}
if($_GET["PRIMARYKEYS"] != "" &&
$_POST["_DELETECONFIRM"] != "yes" && $this->keyArray)
{
$dataQuery .= " LIMIT 0,1";
}
else
{
$dataQuery .= $this->orderBy.($this->orderDesc ? " DESC " : "").
" LIMIT 0".
$this->currentRec.
",0".
$this->recordLimit;
} // if
} // function buildSelectQuery
/******************************************************************************
BUILD KEY TAGS
******************************************************************************/
private function buildKeyTags()
// Generates PRIMARYKEY_ iHidden inputs to identify the record for
// updating and $this->primaryKeyFilter to identify the record in
// the delete link
{
if($this->keyArray != "")
{
$this->primaryKeyFilter = "YES&";
foreach($this->keyArray as $thisKeyField)
{
if(!$this->sheetView)
{
$this->inputs["PRIMARYKEY_".$thisKeyField] =
new iHidden("PRIMARYKEY_".$thisKeyField);
$this->inputs["PRIMARYKEY_".$thisKeyField]->setValue(
$this->resultArray[$thisKeyField]);
$this->inputs["PRIMARYKEY_".$thisKeyField]->dbField =
"PRIMARYKEY_".$thisKeyField;
}
$this->primaryKeyFilter .= htmlentities("PRIMARYKEY_".urlencode($thisKeyField)."=".urlencode($this->resultArray[$thisKeyField])."&");
} // foreach keyArray
} // if keyArray
else
{
$this->primaryKeyFilter = "NO&";
}
} // function buildKeyTags
/******************************************************************************
FIX CURRENT RECORD
******************************************************************************/
private function fixCurrentRec()
{
// This function is called to force the currentRec
// position counter to stay within bounds (not negative
// and not greater than maxRec)
if($this->maxRec > 1 && $this->currentRec >= $this->maxRec)
{
$this->currentRec = "new";
}
if($this->currentRec < 0)
{
$this->currentRec = 0;
}
} // fixCurrentRec
/******************************************************************************
PROCESS DATA
******************************************************************************/
public function processData()
// Connect to and query database, and perform any operations directed
// in POST variables. This method should be called after the class has
// been constructed and variables set, but before output has been sent
// to client.
{
if($this->isProcessed)
{
return(0);
}
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['PROCESSD_START'] = microtime(true);
}
if($this->makeConnection() === false) // connect to MySQL
{
return(false);
}
$this->isProcessed = TRUE; // set flag to prevent processing twice.
if(($GLOBALS['FIFORMS_CONFIG']['ENCRYPT_KEY']) && !$this->sheetView)
{
$this->inputs["_CHECK_DATA"] = new iHidden('_CHECK_DATA');
}
if(is_array($this->allowedParameters) && !$this->sheetView)
{
foreach($this->allowedParameters as $param)
{
if(!array_key_exists($param,$this->inputs))
{
$this->addIn('iHidden',$param);
}
if(isset($_GET[$param]))
{
$this->inputs[$param]->setValue($_GET[$param]);
}
}
}
// Insert or update any record in POST variables
$saveSuccess = $this->savePostData();
// set the maximum number of records to retreive
if($this->sheetView && $this->recordLimit == "")
{
$this->recordLimit = $GLOBALS['FIFORMS_CONFIG']['DEFAULT_LIMIT'];
}
elseif($this->recordLimit == "" || !$this->sheetView)
{
$this->recordLimit = 1;
}
if($saveSuccess && $this->currentRec != "new")
{
// The save was successful, and this isn't a new record, so
// we need to query the database and display something
if($this->sheetView && $this->currentRec >= 1)
{
$this->currentRec -= $this->currentRec % $this->recordLimit;
}
// build query
$this->buildSelectQuery();
// record timing point
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['QUERYSTART'] = microtime(true);
}
// Execute any pre-queries
foreach($this->preQueries as $pqKey => $preQuery)
{
// fill %% variables in $preQuery
$sql = fillVars($_GET,$preQuery);
$this->preQueries[$pqKey] = $sql;
// execute the query
$this->runQuery($sql);
}
$this->resultSet = $this->runQuery($this->dataQuery);
// record timing point
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['QUERYEND'] = microtime(true);
}
if($this->resultSet == FALSE)
{
$err = mysql_error();
if($GLOBALS['FIFORMS_CONFIG']['ALLOW_DD_OPERATIONS'] &&
strpos($err,'doesn\'t exist'))
{
$uri = $GLOBALS['FIFORMS_CONFIG']['URI']."createSchema.php";
$suggestion = <<<EOD
<br /><p>
If you want, and if your account has enough permissions,
FiForms can correct this problem for you by creating the
table that you need to use this form.
</p>
<p>
<a href="$uri?createDB=NO&app=$_GET[app]&formname=$_GET[formname]">Click here
to attempt to create the necessary table.</a>
</p>
EOD;
$this->throwError($suggestion);
} // if doesn't exist error
} // if no result set
elseif(mysql_num_rows($this->resultSet) < 1)
{
if($this->allowNewView &&
(!$this->sheetView || $this->allowFormView))
{
// This is record edit mode, and there are no records,
// so we need to go to a new record
$this->excludeLinkTerms[] = 'sheetView';
$newURL = html_entity_decode(iFormControl::buildMyURL(
$this->excludeLinkTerms));
if($GLOBALS['FIFORMS_CONFIG']['QUERY_DEBUGGING'])
{
echo($this->wrapper->debugQueries);
echo('<a href="'.htmlentities($newURL).'&currentRec=new">Click to Continue</a>');
die();
}
else
{
header("Location: $newURL"."¤tRec=new");
die("Redirecting to $newURL"."¤tRec=new");
}
}
$err = mysql_error();
if($err)
{
$this->throwError("No rows returned from query:<br />".$err);
}
}
$this->getNextRecord();
if(strpos($this->dataQuery,"SQL_CALC_FOUND_ROWS"))
{
$explainQuery = ( "SELECT FOUND_ROWS() as rows;");
$explainRslt = $this->runQuery($explainQuery);
$explainArray = @mysql_fetch_array($explainRslt);
$this->maxRec = $explainArray["rows"];
}
else if($this->where)
{
// get the count of rows by running count(*)
// NOTE: this is could be a source of performance issues
// and it is not always totally accurate. The preferred method is
// to always include SQL_CALC_FOUND_ROWS in the data query
$explainQuery = (
"SELECT count( * ) as rows FROM ".
$this->dataTable.
" WHERE ".
$this->where
);
// run the query
$explainRslt = $this->runQuery($explainQuery);
$explainArray = @mysql_fetch_array($explainRslt);
$this->maxRec = $explainArray["rows"];
}
$this->fixCurrentRec();
$this->buildKeyTags();
} // if not currentRec=new
elseif($saveSuccess)
// current record is new
{
if(count($_POST) > 0 && $this->noMoveOnInsert)
{
// Find the primary keys of the inserted record
// and move back to that record, if noMoveOnInsert
// is TRUE.
foreach($this->keyArray as $keyName)
{
$keyValue = $_POST[$keyName];
if($keyValue == '')
{
$keyValue = $this->insertID;
}
$newKeyFilter .= "PRIMARYKEY_$keyName=$keyValue&";
}
$newKeyFilter .= "TRUE";
$newURL = html_entity_decode(iFormControl::buildMyURL($this->excludeLinkTerms));
if($GLOBALS['FIFORMS_CONFIG']['QUERY_DEBUGGING'])
{
echo($this->wrapper->debugQueries);
echo('<a href="'.htmlentities($newURL)."PRIMARYKEYS=YES&".htmlentities($newKeyFilter).'">Click to Continue</a>');
die();
}
else
{
header("Location: ".$newURL."PRIMARYKEYS=YES&$newKeyFilter");
die("Redirecting to ".$newURL."PRIMARYKEYS=YES&$newKeyFilter");
}
}
} // if new and save successful
else
// save unsuccessful, restore data
{
$this->restoreRecord();
}
// Set up _CONTROLS page contorls
if(isset($this->inputs["_CONTROLS"]))
{
$this->inputs["_CONTROLS"]->processControls();
if($this->controlsOnTop)
{
$this->inputs['_CONTROLS']->htmlClass = "FiForm_Control_Top";
$this->controlHeader = $this->inputs["_CONTROLS"]->drawInput();
$this->controlHeaderSpacer = "<div class=\"FiFormControlSpacer\"> </div>";
}
$this->inputs['_CONTROLS']->htmlClass = "FiForm_Control";
$this->controlFooter = $this->inputs["_CONTROLS"]->drawInput();
}
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['PROCESSD_END'] = microtime(true);
}
} // function processData
/******************************************************************************
ERASE INPUT
******************************************************************************/
public function eraseIn($inputName)
{
unset($this->inputs[$inputName]);
}
/******************************************************************************
RENAME INPUT
******************************************************************************/
public function renameIn($inputName,$newName)
// doesn't really rename, just puts a different caption
{
$this->inputs[$inputName]->caption = $newName;
}
/******************************************************************************
HIDE INPUT
******************************************************************************/
public function hideIn($inputName)
{
$this->inputs[$inputName]->otherTags .= " hidden=\"hidden\" ";
}
/******************************************************************************
DISABLE INPUT
******************************************************************************/
public function disableIn($inputName = "_this")
{
$this->inputs[$inputName]->disableIn();
}
/******************************************************************************
DRAW INPUT
******************************************************************************/
public function drawBody($type)
{
switch($type)
{
case 'fieldNames':
return("<th class=\"FiFormSV\">$this->drawCaption</th>\n");
case 'sv':
return("<td class=\"FiFormSV\">$this->drawInput</td>\n");
case 'body':
return("\n<tr>\n<th class=\"FiForm\">$this->drawCaption</th>\n".
"<td class=\"FiForm\">$this->drawInput</td>\n</tr>\n");
}
} // function drawBody
function drawHead()
{
if($this->sheetView)
{
return($this->controlHeader.
$this->controlHeaderSpacer.
$this->wrapper->pageHeader.
"<div id=\"calendardiv\"
style=\"position:absolute;visibility:hidden;\"></div><h1>".
$this->wrapper->pageTitle.
"</h1>".
"<div class=\"ruler\"></div>".
"<p class=\"error\">".
$this->wrapper->errorMsg.
"</p>"
."<table class=\"FiFormSV\">".$this->wrapper->formHeader);
}
else
{
return("<form ".($GLOBALS['FIFORMS_CONFIG']['USE_XHTML'] ?
"id" : "name").
"=\"$this->name\" ".
"action=\"$this->formAction\" ".
"method=\"post\" enctype=\"multipart/form-data\"
onchange=\"markDirty();\"
onsubmit=\"validateSubmit();\">".
$this->controlHeaderSpacer.
$this->wrapper->pageHeader.
"<div id=\"calendardiv\"
style=\"position:absolute;visibility:hidden;\"></div><h1>".
$this->wrapper->pageTitle.
"</h1>".
"<div class=\"ruler\"></div>".
"<p class=\"error\">".
$this->wrapper->errorMsg.
"</p>".
$this->wrapper->formHeader.
$this->controlHeader
."<table class=\"FiForm\">");
} // if-else
} // function drawHead
function drawFoot()
{
if($this->sheetView)
{
return('</tbody></table>'.
$this->wrapper->formFooter.$this->wrapper->pageFooter.
'</div>'.$this->controlFooter);
}
else
{
return('</table>'.$this->wrapper->formFooter.
$this->wrapper->pageFooter.'</div>'.
$this->controlFooter.'</form>');
}
} // function drawFoot
public function drawInput($withFooter = TRUE)
// return the output to draw the form (without the wrapper)
// processData() should be called before this function is called.
// Note that the actual process of calling the drawInput
// of each child iInput is done in outputRow() function, not here.
{
if(!$this->recordLimit)
{
$this->recordLimit = 1;
}
$this->recNum = $this->currentRec - ($this->currentRec % $this->recordLimit);
if(!$this->allowSheetView && !$this->allowFormView)
{
return("This form has been disabled. No views are allowed.");
}
if(!$this->allowSheetView)
{
$this->sheetView = FALSE;
}
if(!$this->allowFormView)
{
$this->sheetView = TRUE;
}
if(count($this->keyArray) == 0)
{
$this->readOnly = TRUE;
}
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['DRAWINGSTART'] = microtime(true);
}
$output = $this->drawHead();
if($this->sheetView)
{
// Output a single header followed by multiple rows (records)
// For now, sheet view is always read-only
$this->readOnly = TRUE;
$this->wrapper->headerTags .= <<<EOD
<script type="text/javascript">
sheetView = true;
</script>
EOD;
$output .= $this->formatStrSV->headStart;
$output .= $this->outputRow($this,true,'fieldNames');
$output .= $this->formatStrSV->headStop;
$recordsRemain = true;
$even = TRUE;
// loop over each record
while($this->isProcessed && $recordsRemain == true)
{
if($even)
{
$output .= $this->formatStrSV->rowStartEven;
}
else
{
$output .= $this->formatStrSV->rowStartOdd;
}
$even = !$even; // alternate even and odd rows, for coloring
$output .= $this->outputRow($this,false,'sv');
$output .= $this->formatStrSV->rowStop;
$recordsRemain = $this->getNextRecord();
$this->recNum++;
} // while loop over all records
} // if sheetView
else
{
$this->wrapper->headerTags .= <<<EOD
<script type="text/javascript">
warnOnUnload = true;
</script>
EOD;
// output the normal FiForm view.
$output .= $this->outputRow($this,true,'body');
}
// output the footer
$output .= $this->drawFoot();
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['DRAWINGDONE'] = microtime(true);
}
//$this->closeConnection();
return($output);
} // function drawInput
/******************************************************************************
DRAW FORM
******************************************************************************/
public function drawForm()
// Calls processData() to run all necessary queries of the database
// server, then draws the form with all controls and returns
// the result as a string, which can be placed in the body
// of an HTML document.
{
$this->processData();
return($this->drawInput());
} //function drawForm
/******************************************************************************
DRAW FORM PAGE
******************************************************************************/
public function drawFormPage()
// Same as drawForm(), but wrapped in HTML to make a complete page
{
reset($this->inputs);
list($ctrlName) = each($this->inputs);
if($this->caption == "")
{
$this->wrapper->pageTitle = "Data Form: ".$this->name;
}
else
{
$this->wrapper->pageTitle = $this->caption;
}
if(!$this->readOnly && !$this->wrapper->bodyProperties && !$this->sheetView)
{
$this->wrapper->bodyProperties =
" onload=\"FiForm_onLoad();\" ";
}
$form = $this->drawForm();
$output = $this->wrapper->returnHeader();
$output .= $form;
$output .= $this->wrapper->returnFooter();
return($output);
}
/******************************************************************************
AUTO INPUTS
******************************************************************************/
public function autoInputs()
{
$this->makeConnection();
// get a description of the table
$describeQuery = "DESCRIBE ".$this->dataTable;
$describeRslt = $this->runQuery($describeQuery);
// loop through each field in the description
while($describerow = mysql_fetch_array($describeRslt))
{
$type = $describerow["Type"];
// determine the input type based on the field type
if(strpos($type,'date') !== FALSE)
{
$this->inputs[$describerow["Field"]] =
new iDateText($describerow["Field"],$describerow["Field"]);
}
elseif(strpos($type,'enum') !== FALSE)
{
// convert the enum declaration into an array declaration
// and evalutate it.
$valueArray = array();
eval("\$valueArray = array".substr($type,4).";");
$this->inputs[$describerow["Field"]] =
new iDBSelect($describerow["Field"],
$describerow["Field"],
$valueArray);
}
elseif(strpos($type,'text') !== FALSE)
{
$this->inputs[$describerow["Field"]] =
new iTextArea($describerow["Field"],$describerow["Field"],30,5);
}
else // default
{
$this->inputs[$describerow["Field"]] =
new iText($describerow["Field"],$describerow["Field"]);
} // if
} // while
} // function autoInputs
function throwError($errorMessage)
{
$this->wrapper->errorMsg .= $errorMessage;
$this->error = true;
}
public function setQuery($sql)
{
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['LOADXML_STARTSETQUERY'] = microtime(true);
}
$qparser = new QueryParser($sql);
$query = trim(fillVars($_GET,$qparser->getClause('SELECT')." ".$qparser->getClause('FROM')));
if($query)
{
$this->dataQuery = $query;
}
else
{
$this->dataQuery = ""; //"SELECT * FROM ".$this->dataTable;
}
$this->where = substr(trim(fillVars($_GET,$qparser->getClause('WHERE'))),5);
$this->groupBy = substr(trim(fillVars($_GET,$qparser->getClause('GROUP BY'))),8);
$this->having = substr(trim(fillVars($_GET,$qparser->getClause('HAVING'))),6);
$this->orderBy = " ".trim($qparser->getClause('ORDER BY'));
if($GLOBALS['FIFORMS_CONFIG']['PERF_STAT'])
{
$this->timing['LOADXML_ENDSETQUERY'] = microtime(true);
}
}
public function clearPrimaryKeys()
{
$this->keyArray = array();
}
public function setPrimaryKey($keyName)
{
$this->keyArray = array_merge($this->keyArray,array($keyName));
}
public function compress($data)
{
if(function_exists('gzcompress'))
{
return gzcompress($data,9);
}
return $data;
}
public function decompress($data)
{
if(function_exists('gzuncompress'))
{
return gzuncompress($data);
}
return $data;
}
} //class FiForm
/* ?></code><?php */
?>