Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 28 additions & 42 deletions modules/formulize/include/extract.php
Original file line number Diff line number Diff line change
Expand Up @@ -519,25 +519,7 @@ function dataExtraction($frame, $form, $filter, $andor, $scope, $limitStart, $li
}

// FIGURE OUT THE SCOPE (WHICH ENTRIES ARE INCLUDED BASED ON GROUPS ETC)
$scopeFilter = "";
if (is_array($scope)) { // assume any arrays are groupid arrays, and so make a valid scope string based on this. Use the new entry owner table.
if (count((array) $scope) > 0) {
$start = true;
foreach ($scope as $groupid) { // need to loop through the array, and not use implode, so we can sanitize the values
if (!$start) {
$scopeFilter .= " OR scope.groupid=" . intval($groupid);
} else {
$start = false;
$scopeFilter = " AND EXISTS(SELECT 1 FROM " . DBPRE . "formulize_entry_owner_groups AS scope WHERE (scope.entry_id=main.entry_id AND scope.fid=" . intval($fid) . ") AND (scope.groupid=" . intval($groupid);
}
}
$scopeFilter .= ")) "; // need two closing brackets for the exists statement and its where clause
} else { // no valid entries found, so show no entries
$scopeFilter = " AND main.entry_id<0 ";
}
} elseif ($scope) { // need to handle old "uid = X OR..." syntax
$scopeFilter = " AND (" . str_replace("uid", "main.creation_uid", $scope) . ") ";
}
$scopeFilter = makeScopeSQL($fid, $scope);

// PARSE THE FILTER THAT HAS BEEN PASSED IN, INTO WHERE CLAUSE AND OTHER RELATED CLAUSES WE WILL NEED
formulize_getElementMetaData("", false, $fid); // initialize the element metadata for this form...serious performance gain from this
Expand Down Expand Up @@ -1419,12 +1401,13 @@ function formulize_getFormIdFromName($nameHandle)

// THIS FUNCTION BREAKS DOWN THE FILTER STRING INTO ITS COMPONENTS. TAKES EVERYTHING UP TO THE TOP LEVEL ARRAY SYNTAX.
// $linkfids is the linked fids in order that they appear in the SQL query
function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid, $tableAlias = "main")
{
global $xoopsDB;
if ($filtertemp == "") {
return array(0 => array(), "", "");
}
$tableAlias = $tableAlias ? $tableAlias . "." : "";

$formFieldFilterMap = array();
$whereClause = "";
Expand Down Expand Up @@ -1513,7 +1496,7 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
if ($ifParts[0] == "creation_datetime" or $ifParts[0] == "mod_datetime") {
$queryElement = $ifParts[0];
} else {
list($ifParts[0], $formFieldFilterMap, $mappedForm, $element_id, $elementPrefix, $queryElement) = prepareElementMetaData($frid, $fid, $linkfids, $ifParts[0], $formFieldFilterMap);
list($ifParts[0], $formFieldFilterMap, $mappedForm, $element_id, $elementPrefix, $queryElement) = prepareElementMetaData($frid, $fid, $linkfids, $ifParts[0], $formFieldFilterMap, trim($tableAlias, "."));
}
$orderByClause = " ORDER BY $queryElement DESC LIMIT 0," . substr($ifParts[2], 6);
continue;
Expand All @@ -1539,7 +1522,7 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
// FIRST: NUMERIC FILTERS ARE INTERPRETTED AS ENTRY IDS IN THE MAIN FORM
if (is_numeric($ifParts[0]) and $ifParts[0] == $indivFilter) {
// if this is a numeric value, then we must treat it specially
$newWhereClause = "main.entry_id=" . $ifParts[0];
$newWhereClause = $tableAlias."entry_id=" . $ifParts[0];
$mappedForm = $fid;

// SECOND: HANDLE ANY METADATA FILTER TERMS
Expand All @@ -1559,7 +1542,7 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
} else { // need to put mysql_real_escape_string around $ifParts[1] only when it's a date field, since that escaping requirement has been handled already in the subquery for uid filters
$ifParts[1] = formulize_db_escape($ifParts[1]);
}
$newWhereClause = "main." . $ifParts[0] . $operator . $quotes . $likebits . $ifParts[1] . $likebits . $quotes;
$newWhereClause = $tableAlias . $ifParts[0] . $operator . $quotes . $likebits . $ifParts[1] . $likebits . $quotes;
$mappedForm = $fid;
} elseif ($ifParts[0] == "creator_email") {
$formFieldFilterMap['creator_email'] = true;
Expand All @@ -1577,24 +1560,24 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
INNER JOIN " . $xoopsDB->prefix('group_permission') . " AS p
ON eog.groupid = p.gperm_groupid AND eog.fid = p.gperm_itemid
WHERE eog.fid=$fid
AND eog.entry_id = main.entry_id
AND eog.entry_id = ".$tableAlias."entry_id
AND p.gperm_modid = " . getFormulizeModId() . "
AND p.gperm_name = 'view_form'
$ownerGroupSearchClause)";
$mappedForm = $fid;
} elseif ($ifParts[0] == "entry_id") {
$formFieldFilterMap['entry_id'] = true;
$newWhereClause = "main.entry_id" . $operator . $quotes . $likebits . formulize_db_escape($ifParts[1]) . $likebits . $quotes;
$newWhereClause = $tableAlias."entry_id" . $operator . $quotes . $likebits . formulize_db_escape($ifParts[1]) . $likebits . $quotes;
$mappedForm = $fid;
} elseif ($ifParts[0] == "revision_id" and is_numeric($ifParts[1])) {
$formFieldFilterMap['revision_id'] = true;
$newWhereClause = "main.revision_id" . $operator . $quotes . $likebits . formulize_db_escape($ifParts[1]) . $likebits . $quotes;
$newWhereClause = $tableAlias."revision_id" . $operator . $quotes . $likebits . formulize_db_escape($ifParts[1]) . $likebits . $quotes;
$mappedForm = $fid;

//THIRD: NON-METADATA QUERIES
} else {

list($ifParts[0], $formFieldFilterMap, $mappedForm, $element_id, $elementPrefix, $queryElement) = prepareElementMetaData($frid, $fid, $linkfids, $ifParts[0], $formFieldFilterMap);
list($ifParts[0], $formFieldFilterMap, $mappedForm, $element_id, $elementPrefix, $queryElement) = prepareElementMetaData($frid, $fid, $linkfids, $ifParts[0], $formFieldFilterMap, trim($tableAlias, "."));

// set query term for yes/no questions
if ($formFieldFilterMap[$mappedForm][$element_id]['isyn'] and $ifParts[1] !== "") {
Expand All @@ -1613,7 +1596,7 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
// instead of doing a subquery, this could probably be redone similarly to creator_email and then we would have the "other" value in the raw query result, and then the process in prepValues would not need to requery the other table
if ($formFieldFilterMap[$mappedForm][$element_id]['hasother']) {
$subquery = "(SELECT id_req FROM " . DBPRE . "formulize_other WHERE ele_id=" . intval($element_id) . " AND other_text " . $operator . $quotes . $likebits . formulize_db_escape($ifParts[1]) . $likebits . $quotes . ")";
$newWhereClause = "(($elementPrefix.entry_id = ANY $subquery)OR($queryElement " . $operator . $quotes . $likebits . formulize_db_escape($ifParts[1]) . $likebits . $quotes . "))"; // need to look in the other box and the main field, and return values that match in either case
$newWhereClause = "((".$elementPrefix."entry_id = ANY $subquery)OR($queryElement " . $operator . $quotes . $likebits . formulize_db_escape($ifParts[1]) . $likebits . $quotes . "))"; // need to look in the other box and the main field, and return values that match in either case

// HANDLE LINKED ELEMENTS
} elseif ($sourceMeta = $formFieldFilterMap[$mappedForm][$element_id]['islinked']) {
Expand Down Expand Up @@ -1733,7 +1716,7 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
$newWhereClause .= ") ";
}
} else {
$newWhereClause = "main.entry_id<0"; // no matches, so result set should be empty, so set a where clause that will return zero results
$newWhereClause = $tableAlias."entry_id<0"; // no matches, so result set should be empty, so set a where clause that will return zero results
}

// HANDLE ALL OTHER ELEMENT TYPES (not other box, not linked, not username/fullname list)
Expand Down Expand Up @@ -1807,6 +1790,7 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
if ($searchTermToUse) { // set as an override value in certain cases above
$newWhereClause = $searchTermToUse;
} else {
$searchTerm = formulize_db_escape($searchTerm);
// for checkboxes when equals operator, look for matches within the prefix strings or with a prefix and then end of string
// could extend to other multi value elements, but they might potentially have different formats
// which is why the class should be extended to figure out this lookup... could be an evolution of the prepareLiteralTextForDB ??
Expand Down Expand Up @@ -1848,12 +1832,12 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)
$numIndivFilters++;
}

if ($whereClause == "(") { // if no contents for the whereclause where generated...make a fake contents (should only happen if the only filter term passed in is a newest operator)
$whereClause .= "main.entry_id>0";
}
$whereClause .= ")";
$numSeachExps++;
}
if($whereClause == "(") { // if no contents for the whereclause where generated...make a fake contents (should only happen if the only filter term passed in is a newest operator)
$whereClause .= $tableAlias."entry_id>0";
}
$whereClause .= ")";
$numSeachExps++;
}

// sort out the one side filters that have been generated and cached per form, put the global and/or between the expressions produced by the distinct filter sets that were passed in
// this allows two different filter sets that have local "or" booleans, to get concatenated correctly. OR filters in a single set: red or blue or apples or oranges. OR filters in two sets: (red or blue) AND (apples or oranges)
Expand Down Expand Up @@ -1907,8 +1891,9 @@ function formulize_parseFilter($filtertemp, $andor, $linkfids, $fid, $frid)


// THIS FUNCTION TAKES INPUTS ABOUT AND ELEMENT, AND RETURNS A SET OF INFORMATION THAT IS NECESSARY WHEN BUILDING VARIOUS PARTS OF THE WHERE CLAUSE
function prepareElementMetaData($frid, $fid, $linkfids, $ifPartsZero, $formFieldFilterMap)
function prepareElementMetaData($frid, $fid, $linkfids, $ifPartsZero, $formFieldFilterMap, $tableAlias = "")
{

// first convert any handles to element Handles, and/or get the element id if necessary...element id is necessary for creating the formfieldfiltermap, since that function was written the first time we tried to do this, when there were no element handles in the mix
if ($frid and !is_numeric($ifPartsZero)) {
$element_id = formulize_getIdFromElementHandle($ifPartsZero);
Expand All @@ -1925,19 +1910,20 @@ function prepareElementMetaData($frid, $fid, $linkfids, $ifPartsZero, $formField
print_r($formFieldFilterMap);
print "<br>Mappedform: $mappedForm<br>";
print "<br>fid: $fid";*/
$elementPrefix = $mappedForm == $fid ? "main" : "f" . array_search($mappedForm, $linkfids);
$elementPrefix = $tableAlias != "main" ? $tableAlias : ($mappedForm == $fid ? "main" : "f" . array_search($mappedForm, $linkfids));
$elementPrefix = $elementPrefix ? $elementPrefix."." : "";

// check if its encrypted or not, and setup the proper field reference
$queryElementMetaData = formulize_getElementMetaData($ifPartsZero, true);

// add ` ` around ifParts[0]...
$ifPartsZero = "`" . $ifPartsZero . "`";

if ($queryElementMetaData['ele_encrypt']) {
$queryElement = "AES_DECRYPT($elementPrefix." . $ifPartsZero . ", '" . getAESPassword() . "')";
} else {
$queryElement = "$elementPrefix." . $ifPartsZero;
}
if($queryElementMetaData['ele_encrypt']) {
$queryElement = "AES_DECRYPT($elementPrefix".$ifPartsZero.", '".getAESPassword()."')";
} else {
$queryElement = "$elementPrefix" . $ifPartsZero;
}

// return in this order: $ifParts[0], $formFieldFilterMap, $mappedForm, $element_id, $elementPrefix, $queryElement
$to_return = array();
Expand Down
77 changes: 65 additions & 12 deletions modules/formulize/include/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ function getEntryOwner($entry, $fid) {
function makeUidFilter($users) {
if (is_array($users)) {
if (count((array) $users) > 1) {
return "uid=" . implode(" OR uid=", $users);
return "uid=" . implode(" OR uid=", array_map('intval', array_filter($users, 'is_numeric')));
} else {
return "uid=" . intval($users[0]);
}
Expand All @@ -921,7 +921,6 @@ function makeUidFilter($users) {
}
}


// FUNCTION HANDLES CHECKING FOR ALL LINKING RELATIONSHIPS FOR THE FORM
// returns the fids and entries passed to it, plus any others in a framework relationship
// $entries is optional, and if left out this will only return the linked forms
Expand Down Expand Up @@ -1677,6 +1676,63 @@ function getCalcHandleText($handle, $forceColhead=true) {
}
}

/**
* Create a SQL string suitable for putting into a query being performed on a Formulize form data table, that will restrict the records returned to the ones the user has permission to see.
* @param int fid - The form id of the form the scope is being generated for.
* @param string|array scopeData - Optional - If present, can be an array of group ids, or an arbitrary string that will be put inside "AND ( )". In the string, 'uid' will be replaced with $tableAlias.creation_uid. Typically the string would be in "uid=X OR uid=Y" format (as produced by the buildScope function).
* @param object|int - userObjectOrUserId - Optional - If no scopeData is passed in, this specifies the user for whom the scope should be determined. If not specified, then the active user is used
* @param string - tableAlias - Optional - The table alias being used to refer to the Formulize form data table in the SQL query where this SQL will be used. Defaults to 'main'.
* @return string - Returns the SQL, if any, that is required to limit a query on the Formulize form data table
*/
function makeScopeSQL($fid, $scopeData=null, $userObjectOrUserId = null, $tableAlias="main") {

$tableAlias = $tableAlias ? $tableAlias."." : "";

// determine the user's scope on the declared form, if no scope data was provided
// start with 'all' and buildScope will ratchet down to the most appropriate scope based on user's permissions
if(!is_array($scopeData) AND !$scopeData AND intval($fid)) {
// the user is the passed in user, or the active user if none passed in
if(is_object($userObjectOrUserId)) {
if(!$uid = $userObjectOrUserId->getVar('uid')) {
error_log("Fatal Formulize Error: invalid user object passed in to makeScopeSQL().");
exit();
}
} elseif($userObjectOrUserId) {
$uid = intval($userObjectOrUserId);
} else {
global $xoopsUser;
$uid = $xoopsUser ? $xoopsUser->getVar('uid') : 0;
}
list($scopeData, $scopeType) = buildScope('all', $uid, intval($fid));
}

$scopeFilter = ""; // default to no scope (see all entries). Passed in scope, or a scope determined for the user on the fid, if any, will be either an array or a string of uids

// if scope info is an array of group ids...
if(is_array($scopeData)) {
if (count($scopeData) > 0 ) {
global $xoopsDB;
$start = true;
foreach($scopeData as $groupId) { // need to loop through the array, and not use implode, so we can sanitize the values
if(!$start) {
$scopeFilter .= " OR scope.groupid=".intval($groupId);
} else {
$start = false;
$scopeFilter = " AND EXISTS(SELECT 1 FROM ".$xoopsDB->prefix("formulize_entry_owner_groups")." AS scope WHERE (scope.entry_id=".$tableAlias."entry_id AND scope.fid=".intval($fid).") AND (scope.groupid=".intval($groupId);
}
}
$scopeFilter .= ")) "; // need two closing brackets for the exists statement and its where clause
} else { // no valid entries found, so show no entries
$scopeFilter = " AND ".$tableAlias."entry_id<0 ";
}

// if scope is a string...
} elseif($scopeData) { // need to handle old "uid = X OR..." syntax
$scopeFilter = " AND (".str_replace("uid", $tableAlias."creation_uid", formulize_db_escape($scopeData)).") ";
}

return $scopeFilter;
}

// this function builds the scope used for passing to the getData function
// based on values of either mine, group, all, or a groupid string formatted with start, end and inbetween commas: ,1,3,
Expand All @@ -1694,7 +1750,7 @@ function buildScope($currentView, $uid, $fid, $currentViewCanExpand = false) {

$scope = "";
if ($currentView == "blank") { // send an invalid scope
$scope = "uid=\"blankscope\"";
$scope = 'uid="blankscope"';
} elseif (strstr($currentView, ",")) { // advanced scope, or oldscope
$grouplist = explode("," , trim($currentView, ","));
if ($grouplist[0] == "onlymembergroups") { // first key may be a special flag to cause the scope to be handled differently
Expand All @@ -1705,10 +1761,9 @@ function buildScope($currentView, $uid, $fid, $currentViewCanExpand = false) {
}
// safeguard against empty or invalid grouplists
if (count((array) $grouplist)==0) {
$all_users[] = "";
$scope = makeUidFilter($all_users);
$scope = 'uid="blankscope"'; // show nothing because there are no defined groups
} else {
$scope = $grouplist;
$scope = $grouplist;
}
} elseif ($currentView == "all") {
if ($hasGlobalScope = $gperm_handler->checkRight("view_globalscope", $fid, $groups, $mid) OR $currentViewCanExpand) {
Expand All @@ -1723,7 +1778,7 @@ function buildScope($currentView, $uid, $fid, $currentViewCanExpand = false) {
// do this second last, just in case currentview =all was passed in but not valid and defaulted back to group
if ($currentView == "group") {

if (!$hasGroupScope = $gperm_handler->checkRight("view_groupscope", $fid, $groups, $mid) AND !$currentViewCanExpand) {
if (!$hasGroupScope = $gperm_handler->checkRight("view_groupscope", $fid, $groups, $mid) AND !$currentViewCanExpand AND !$hasGlobalScope = $gperm_handler->checkRight("view_globalscope", $fid, $groups, $mid)) { // odd checking of global here, but 'group' could have been specifically requested even though user only has global. So in that case, checking for groupscope would fail, but user still has rights to the entries due to global scope, so don't default to 'mine' in this case
$currentView = "mine";
} else {
$formulize_permHandler = new formulizePermHandler($fid);
Expand All @@ -1734,18 +1789,16 @@ function buildScope($currentView, $uid, $fid, $currentViewCanExpand = false) {
}
// safeguard against empty or invalid grouplists
if (count((array) $scopeGroups)==0) {
$all_users[] = $uid;
$scope = makeUidFilter($all_users);
$scope = makeUidFilter(array($uid)); // limit user to themselves since no their groupscope is empty
} else {
$scope = $scopeGroups;
$scope = $scopeGroups;
}
}
}

// catch all. if it's "mine" or an old view, or there's no scope yet defined, then treat it as just the user's own entries
if ($currentView == "mine" OR substr($currentView, 0, 4) == "old_" OR ($scope == "" AND $currentView != "all")) {
$all_users[] = $uid;
$scope = makeUidFilter($all_users);
$scope = makeUidFilter(array($uid));
}
return array($scope, $currentView);
}
Expand Down
Loading