$time) AND
(DateStarts IS NULL OR UNIX_TIMESTAMP(DateStarts) <= $time)";
$resProfileMemLevels = db_res($query);
$membershipProfiles = mysql_fetch_row($resProfileMemLevels);
$membershipProfiles = (int)$membershipProfiles[0];
if($membershipID == MEMBERSHIP_ID_STANDARD) $membershipProfiles = $totalProfiles - $membershipProfiles;
if($except) $membershipProfiles = $totalProfiles - $membershipProfiles;
return $membershipProfiles;
}*/
/**
* This is an internal function - do NOT use it outside of membership_levels.inc.php!
*/
function getMemberMembershipInfo_current($memberID, $time = '')
{
$sCacheName = 'arrMemLevel'.$memberID.$time;
$memberID = (int)$memberID;
$time = ($time == '') ? time() : (int)$time;
//fetch the last purchased/assigned membership
//that is still active for the given member
$arrMemLevel =& $GLOBALS['MySQL']->fromMemory($sCacheName, 'getRow', "
SELECT `sys_acl_levels_members`.IDLevel as ID,
`sys_acl_levels`.Name as Name,
UNIX_TIMESTAMP(`sys_acl_levels_members`.DateStarts) as DateStarts,
UNIX_TIMESTAMP(`sys_acl_levels_members`.DateExpires) as DateExpires,
`sys_acl_levels_members`.`TransactionID` AS `TransactionID`
FROM `sys_acl_levels_members`
RIGHT JOIN Profiles
ON `sys_acl_levels_members`.IDMember = Profiles.ID
AND (`sys_acl_levels_members`.DateStarts IS NULL
OR `sys_acl_levels_members`.DateStarts <= FROM_UNIXTIME($time))
AND (`sys_acl_levels_members`.DateExpires IS NULL
OR `sys_acl_levels_members`.DateExpires > FROM_UNIXTIME($time))
LEFT JOIN `sys_acl_levels`
ON `sys_acl_levels_members`.IDLevel = `sys_acl_levels`.ID
WHERE Profiles.ID = $memberID
ORDER BY `sys_acl_levels_members`.DateStarts DESC
LIMIT 0, 1");
//no such member found
if (!$arrMemLevel || !count($arrMemLevel))
{
//fetch info about Non-member membership
$arrMemLevel =& $GLOBALS['MySQL']->fromCache('sys_acl_levels'.MEMBERSHIP_ID_NON_MEMBER, 'getRow', "SELECT ID, Name FROM `sys_acl_levels` WHERE ID = ".MEMBERSHIP_ID_NON_MEMBER);
if (!$arrMemLevel || !count($arrMemLevel))
{
//this should never happen, but just in case
echo "
getMemberMembershipInfo() fatal error: Non-Member membership not found.";
exit();
}
return $arrMemLevel;
}
//no purchased/assigned memberships for the member or all of them
//have expired -- the member is assumed to have Standard membership
if(is_null($arrMemLevel['ID']))
{
$arrMemLevel =& $GLOBALS['MySQL']->fromCache('sys_acl_levels'.MEMBERSHIP_ID_STANDARD, 'getRow', "SELECT ID, Name FROM `sys_acl_levels` WHERE ID = ".MEMBERSHIP_ID_STANDARD);
if (!$arrMemLevel || !count($arrMemLevel))
{
//again, this should never happen, but just in case
echo "
getMemberMembershipInfo() fatal error: Standard membership not found.";
exit();
}
}
return $arrMemLevel;
}
/**
* Retrieves information about membership for a given member at a given moment.
*
* If there are no memberships purchased/assigned to the
* given member or all of them have expired at the given point,
* the member is assumed to be a standard member, and the function
* returns information about the Standard membership. This will
* also happen if a member wasnt actually registered in the database
* at that point - the function will still return info about Standard
* membership, not the Non-member one.
*
* If there is no profile with the given $memberID,
* the function returns information about the Non-member
* predefined membership.
*
* The Standard and Non-member memberships have their
* DateStarts and DateExpires attributes set to NULL.
*
* @param int $memberID - ID of a member to get info about
* @param int $time - specifies the time to use when determining membership;
* if not specified, the function takes the current time
*
* @return array( 'ID' => membership id,
* 'Name' => membership name,
* 'DateStarts' => (UNIX timestamp) date/time purchased,
* 'DateExpires' => (UNIX timestamp) date/time expires )
*
*/
function getMemberMembershipInfo($memberID, $time = '')
{
$time = ($time == '') ? time() : (int)$time;
$originalMembership = getMemberMembershipInfo_current($memberID, $time);
if( $originalMembership['ID'] == MEMBERSHIP_ID_STANDARD ||
$originalMembership['ID'] == MEMBERSHIP_ID_NON_MEMBER )
{
return $originalMembership;
}
$arrMembership = $originalMembership;
do
{
$dateStarts = $arrMembership['DateStarts'];
$arrMembership = getMemberMembershipInfo_current($memberID, $dateStarts - 1);
}
while($arrMembership['ID'] == $originalMembership['ID'] && (int)$arrMembership['DateStarts']);
$arrMembership = $originalMembership;
do
{
$dateExpires = $arrMembership['DateExpires'];
$arrMembership = getMemberMembershipInfo_current($memberID, $dateExpires);
}
while($arrMembership['ID'] == $originalMembership['ID'] && (int)$arrMembership['DateExpires']);
$originalMembership['DateStarts'] = $dateStarts;
$originalMembership['DateExpires'] = $dateExpires;
return $originalMembership;
}
/**
* This is an internal function - do NOT use it outside of membership_levels.inc.php!
*/
function getMemberMembershipInfo_latest($memberID, $time = '')
{
$time = ($time == '') ? time() : (int)$time;
$originalMembership = getMemberMembershipInfo_current($memberID, $time);
if( $originalMembership['ID'] == MEMBERSHIP_ID_STANDARD ||
$originalMembership['ID'] == MEMBERSHIP_ID_NON_MEMBER )
{
return $originalMembership;
}
$arrMembership = $originalMembership;
$lastMembership = $originalMembership;
do
{
$dateExpires = $arrMembership['DateExpires'];
$arrMembership = getMemberMembershipInfo_current($memberID, $dateExpires);
if(!is_null($dateExpires))
$lastMembership = $arrMembership;
}
while($arrMembership['ID'] != MEMBERSHIP_ID_STANDARD && (int)$arrMembership['DateExpires']);
$arrMembership = $lastMembership;
do
{
$dateStarts = $arrMembership['DateStarts'];
$arrMembership = getMemberMembershipInfo_current($memberID, $dateStarts - 1);
}
while($arrMembership['ID'] == $lastMembership['ID'] && (int)$arrMembership['DateStarts']);
$originalMembership['DateStarts'] = $dateStarts;
$originalMembership['DateExpires'] = $dateExpires;
return $originalMembership;
}
/**
* Checks if a given action is allowed for a given member and updates action information if the
* action is performed.
*
* @param int $memberID - ID of a member that is going to perform an action
* @param int $actionID - ID of the action itself
* @param boolean $performAction - if true, then action information is updated, i.e. action
* is 'performed'
*
* @return array( CHECK_ACTION_RESULT => CHECK_ACTION_RESULT_ constant,
* CHECK_ACTION_MESSAGE => CHECK_ACTION_MESSAGE_ constant,
* CHECK_ACTION_PARAMETER => additional action parameter (string) )
*
*
* NOTES:
*
* $result[CHECK_ACTION_MESSAGE] contains a message with detailed information about the result,
* already processed by the language file
*
* if $result[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED then this node contains
* an empty string
*
* The error messages themselves are stored in the language file. Additional variables are
* passed to the languages.inc.php function _t_ext() as an array and can be used there in the form of
* {0}, {1}, {2} ...
*
* Additional variables passed to the lang. file on errors (can be used in error messages):
*
* For all errors:
*
* $arg0[CHECK_ACTION_LANG_FILE_ACTION] = name of the action
* $arg0[CHECK_ACTION_LANG_FILE_MEMBERSHIP]= name of the current membership
*
* CHECK_ACTION_RESULT_LIMIT_REACHED:
*
* $arg0[CHECK_ACTION_LANG_FILE_LIMIT] = limit on number of actions allowed for the member
* $arg0[CHECK_ACTION_LANG_FILE_PERIOD] = period that the limit is set for (in hours, 0 if unlimited)
*
* CHECK_ACTION_RESULT_NOT_ALLOWED_BEFORE:
*
* $arg0[CHECK_ACTION_LANG_FILE_BEFORE] = date/time since when the action is allowed
*
* CHECK_ACTION_RESULT_NOT_ALLOWED_AFTER:
*
* $arg0[CHECK_ACTION_LANG_FILE_AFTER] = date/time since when the action is not allowed
*
* $result[CHECK_ACTION_PARAMETER] contains an additional parameter that can be considered
* when performing the action (like the number of profiles to show in search result)
*/
function checkAction($memberID, $actionID, $performAction = false, $iForcedProfID = 0)
{
global $logged;
global $site;
//output array initialization
$result = array();
$arrLangFileParams = array();
$dateFormat = "F j, Y, g:i a"; //used when displaying error messages
//input validation
$memberID = (int)$memberID;
$actionID = (int)$actionID;
$performAction = $performAction ? true : false;
//get current member's membership information
$arrMembership = getMemberMembershipInfo($memberID);
$arrLangFileParams[CHECK_ACTION_LANG_FILE_MEMBERSHIP] = $arrMembership['Name'];
$arrLangFileParams[CHECK_ACTION_LANG_FILE_SITE_EMAIL] = $site['email'];
//profile active check
if($arrMembership['ID'] != MEMBERSHIP_ID_NON_MEMBER || $logged['admin'] || $logged['moderator'])
{
$iDestID = $memberID;
if (($logged['admin'] || $logged['moderator']) && $iForcedProfID>0) {
$iDestID = $iForcedProfID;
$performAction = false;
}
$active = getProfileInfo( $iDestID );
$active = ($active['Status'] == 'Active');
if(!$active)
{
$result[CHECK_ACTION_RESULT] = CHECK_ACTION_RESULT_NOT_ACTIVE;
$result[CHECK_ACTION_MESSAGE] = _t_ext(CHECK_ACTION_MESSAGE_NOT_ACTIVE, $arrLangFileParams);
return $result;
}
}
//get permissions for the current action
$resMembershipAction = db_res("
SELECT Name,
IDAction,
AllowedCount,
AllowedPeriodLen,
UNIX_TIMESTAMP(AllowedPeriodStart) as AllowedPeriodStart,
UNIX_TIMESTAMP(AllowedPeriodEnd) as AllowedPeriodEnd,
AdditionalParamValue
FROM `sys_acl_actions`
LEFT JOIN `sys_acl_matrix`
ON `sys_acl_matrix`.IDAction = `sys_acl_actions`.ID
AND `sys_acl_matrix`.IDLevel = {$arrMembership['ID']}
WHERE `sys_acl_actions`.ID = $actionID");
//no such action
if(mysql_num_rows($resMembershipAction) < 1)
{
echo "
checkAction() fatal error. Unknown action ID: $actionID
";
exit();
}
$arrAction = mysql_fetch_assoc($resMembershipAction);
$result[CHECK_ACTION_PARAMETER] = $arrAction['AdditionalParamValue'];
$arrLangFileParams[CHECK_ACTION_LANG_FILE_ACTION] = _t('_'.$arrAction['Name']);
//action is not allowed for the current membership
if(is_null($arrAction['IDAction']))
{
$result[CHECK_ACTION_RESULT] = CHECK_ACTION_RESULT_NOT_ALLOWED;
$result[CHECK_ACTION_MESSAGE] = _t_ext(CHECK_ACTION_MESSAGE_NOT_ALLOWED, $arrLangFileParams);
return $result;
}
//Check fixed period limitations if present (also for non-members)
if($arrAction['AllowedPeriodStart'] && time() < $arrAction['AllowedPeriodStart'])
{
$arrLangFileParams[CHECK_ACTION_LANG_FILE_BEFORE] = date($dateFormat, $arrAction['AllowedPeriodStart']);
$result[CHECK_ACTION_RESULT] = CHECK_ACTION_RESULT_NOT_ALLOWED_BEFORE;
$result[CHECK_ACTION_MESSAGE] = _t_ext(CHECK_ACTION_MESSAGE_NOT_ALLOWED_BEFORE, $arrLangFileParams);
return $result;
}
if($arrAction['AllowedPeriodEnd'] && time() > $arrAction['AllowedPeriodEnd'])
{
$arrLangFileParams[CHECK_ACTION_LANG_FILE_AFTER] = date($dateFormat, $arrAction['AllowedPeriodEnd']);
$result[CHECK_ACTION_RESULT] = CHECK_ACTION_RESULT_NOT_ALLOWED_AFTER;
$result[CHECK_ACTION_MESSAGE] = _t_ext(CHECK_ACTION_MESSAGE_NOT_ALLOWED_AFTER, $arrLangFileParams);
return $result;
}
//if non-member, allow action without performing further checks
if ($arrMembership['ID'] == MEMBERSHIP_ID_NON_MEMBER)
{
$result[CHECK_ACTION_RESULT] = CHECK_ACTION_RESULT_ALLOWED;
return $result;
}
//check other limitations (for members only)
$allowedCnt = (int)$arrAction['AllowedCount']; //number of allowed actions
//if not specified or 0, number of
//actions is unlimited
$periodLen = (int)$arrAction['AllowedPeriodLen']; //period for AllowedCount in hours
//if not specified, AllowedCount is
//treated as total number of actions
//permitted
//number of actions is limited
if($allowedCnt > 0)
{
//get current action info for the member
$actionTrack = db_res("SELECT ActionsLeft,
UNIX_TIMESTAMP(ValidSince) as ValidSince
FROM `sys_acl_actions_track`
WHERE IDAction = $actionID AND IDMember = $memberID");
$actionsLeft = $performAction ? $allowedCnt - 1 : $allowedCnt;
$validSince = time();
//member is requesting/performing this action for the first time,
//and there is no corresponding record in sys_acl_actions_track table
if(mysql_num_rows($actionTrack) <= 0)
{
//add action to sys_acl_actions_track table
db_res("
INSERT INTO `sys_acl_actions_track` (IDAction, IDMember, ActionsLeft, ValidSince)
VALUES ($actionID, $memberID, $actionsLeft, FROM_UNIXTIME($validSince))");
$result[CHECK_ACTION_RESULT] = CHECK_ACTION_RESULT_ALLOWED;
return $result;
}
//action has been requested/performed at least once at this point
//and there is a corresponding record in sys_acl_actions_track table
$actionTrack = mysql_fetch_assoc($actionTrack);
//action record in sys_acl_actions_track table is out of date
$periodEnd = (int)$actionTrack['ValidSince'] + $periodLen * 3600; //ValidSince is in seconds, PeriodLen is in hours
if($periodLen > 0 && $periodEnd < time())
{
db_res("
UPDATE `sys_acl_actions_track`
SET ActionsLeft = $actionsLeft, ValidSince = FROM_UNIXTIME($validSince)
WHERE IDAction = $actionID AND IDMember = $memberID");
$result[CHECK_ACTION_RESULT] = CHECK_ACTION_RESULT_ALLOWED;
return $result;
}
//action record is up to date
$actionsLeft = (int)$actionTrack['ActionsLeft'];
//action limit reached for now
if($actionsLeft <= 0 )
{
$arrLangFileParams[CHECK_ACTION_LANG_FILE_LIMIT] = $allowedCnt;
$arrLangFileParams[CHECK_ACTION_LANG_FILE_PERIOD] = $periodLen;
$result[CHECK_ACTION_RESULT] = CHECK_ACTION_RESULT_LIMIT_REACHED;
$result[CHECK_ACTION_MESSAGE] = '